Sorting words (not lines) in VIM
In pure vim, you could do this:
call setline('.', join(sort(split(getline('.'), ' ')), " "))
Edit
To do this so that it works over a range that is less than one line is a little more complicated (this allows either sorting multiple lines individually or sorting part of one line, depending on the visual selection):
command! -nargs=0 -range SortWords call SortWords()" Add a mapping, go to your string, then press vi",s" vi" selects everything inside the quotation" ,s calls the sorting algorithmvmap ,s :SortWords<CR>" Normal mode one: ,s to select the string and sort itnmap ,s vi",sfunction! SortWords() " Get the visual mark points let StartPosition = getpos("'<") let EndPosition = getpos("'>") if StartPosition[0] != EndPosition[0] echoerr "Range spans multiple buffers" elseif StartPosition[1] != EndPosition[1] " This is a multiple line range, probably easiest to work line wise " This could be made a lot more complicated and sort the whole " lot, but that would require thoughts on how many " words/characters on each line, so that can be an exercise for " the reader! for LineNum in range(StartPosition[1], EndPosition[1]) call setline(LineNum, join(sort(split(getline('.'), ' ')), " ")) endfor else " Single line range, sort words let CurrentLine = getline(StartPosition[1]) " Split the line into the prefix, the selected bit and the suffix " The start bit if StartPosition[2] > 1 let StartOfLine = CurrentLine[:StartPosition[2]-2] else let StartOfLine = "" endif " The end bit if EndPosition[2] < len(CurrentLine) let EndOfLine = CurrentLine[EndPosition[2]:] else let EndOfLine = "" endif " The middle bit let BitToSort = CurrentLine[StartPosition[2]-1:EndPosition[2]-1] " Move spaces at the start of the section to variable StartOfLine while BitToSort[0] == ' ' let BitToSort = BitToSort[1:] let StartOfLine .= ' ' endwhile " Move spaces at the end of the section to variable EndOfLine while BitToSort[len(BitToSort)-1] == ' ' let BitToSort = BitToSort[:len(BitToSort)-2] let EndOfLine = ' ' . EndOfLine endwhile " Sort the middle bit let Sorted = join(sort(split(BitToSort, ' ')), ' ') " Reform the line let NewLine = StartOfLine . Sorted . EndOfLine " Write it out call setline(StartPosition[1], NewLine) endifendfunction
Using great ideas from your answers, especially Al's answer, I eventually came up with the following:
:vnoremap <F2> d:execute 'normal i' . join(sort(split(getreg('"'))), ' ')<CR>
This maps the F2 button in visual
mode to delete the selected text, split, sort and join it and then re-insert it. When the selection spans multiple lines this will sort the words in all of them and output one sorted line, which I can quickly fix using gqq
.
I'll be glad to hear suggestions on how this can be further improved.
Many thanks, I've learned a lot :)
EDIT: Changed '<C-R>"'
to getreg('"')
to handle text with the char '
in it.
Here's the equivalent in pure vimscript:
:call setline('.',join(sort(split(getline('.'),' ')),' '))
It's no shorter or simpler, but if this is something you do often, you can run it across a range of lines:
:%call setline('.',join(sort(split(getline('.'),' ')),' '))
Or make a command
:command -nargs=0 -range SortLine <line1>,<line2>call setline('.',join(sort(split(getline('.'),' ')),' '))
Which you can use with
:SortLine:'<,'>SortLine:%SortLine
etc etc