Ashwin Nanjappa
Ashwin Nanjappa

Reputation: 78528

How to sort comma separated words in Vim

In Python code, I frequently run into import statements like this:

from foo import ppp, zzz, abc

Is there any Vim trick, like :sort for lines, to sort to this:

from foo import abc, ppp, zzz

Upvotes: 12

Views: 3571

Answers (5)

Geremia
Geremia

Reputation: 5636

Select the comma-separated text in visual mode, :, and run this command:

'<,'>!tr ',' '\n' | sort -f | paste -sd ','

🎩-tip this comment

Upvotes: 1

Jeremiah Boyle
Jeremiah Boyle

Reputation: 61

I came here looking for a fast way to sort comma separated lists, in general, e.g.

    relationships = {
        'project', 'freelancer', 'task', 'managers', 'team'
    }

My habit was to search/replace spaces with newlines and invoke shell sort but that's such a pain.

I ended up finding Chris Toomey's sort-motion plugin, which is just the ticket: https://github.com/christoomey/vim-sort-motion. Highly recommended.

Upvotes: 3

Angel Vel&#225;squez
Angel Vel&#225;squez

Reputation: 778

Why not try vim-isort ? https://github.com/fisadev/vim-isort

I use that and vim-yapf-format for beautify the code :) https://github.com/pignacio/vim-yapf-format

Upvotes: 1

Mateusz Piotrowski
Mateusz Piotrowski

Reputation: 9137

Alternatively, you can do the following steps:

  1. Move the words you want to sort to the next line:

    from foo import 
    ppp, zzz, abc
    
  2. Add a comma at the end of the words list:

    from foo import 
    ppp, zzz, abc,
    
  3. Select the word list for example with Shift-v. Now hit : and then enter !xargs -n1 | sort | xargs. It should look like this:

    :'<,'>!xargs -n1 | sort | xargs
    

    Hit Enter.

    from foo import 
    abc, ppp, zzz,
    
  4. Now remove the trailing comma and merge the word list back to the original line (for example with Shift-j).

    from foo import abc, ppp, zzz
    

There are Vim plugins, which might be useful to you:

Upvotes: 4

Luc Hermitte
Luc Hermitte

Reputation: 32966

Yep, there is:

%s/import\s*\zs.*/\=join(sort(split(submatch(0), '\s*,\s*')),', ')

The key elements are:

To answer the comment, if you want to apply the substitution on a visual selection, it becomes:

'<,'>s/\%V.*\%V\@!/\=join(sort(split(submatch(0), '\s*,\s*')), ', ')

The new key elements are this time:

  • :h /\%V that says the next character matched shall belong to the visual selection
  • :h /\@! that I use, in order to express (combined with \%V), that the next character shall not belong to the visual selection. That next character isn't kept in the matched expression.

BTW, we can also use s and i_CTRL-R_= interactively, or put it in a mapping (here triggered on µ):

:xnoremap µ s<c-r>=join(sort(split(@", '\s*,\s*')), ', ')<cr><esc>

Upvotes: 15

Related Questions