Reputation: 55720
Often I just want to sort all my #include
's at the top of my source and header files by their length.
vim
allows me to sort alphanumerically in a similar manner with :{range} sort u
.
In vim
, how do you sort a range of lines by the length of the line? Such that shorter lines are followed by longer lines.
Searching the internet, I found this:
:% s/.*/\=printf("%03d", len(submatch(0)))."|".submatch(0)/ | sor n | %s/..../
But that only works to sort the entire file, and is black magic to me anyway. I'm trying to figure out how to do that same sort with a range such as from line 4 to 18, as in :4,18 s/...
Do you have any ideas?
Upvotes: 43
Views: 11186
Reputation: 172648
I've written the AdvancedSorters plugin to deal with these complex sorting requirements.
Like in @Birei's answer, this plugin offers extension commands that evaluate an expression per line, put that number in front of the line, do a numerical sort, and then remove the temporary number again. Specializations handle the common sort by number of characters and by the line's display width, so you could just use:
:SortByWidth
Upvotes: 8
Reputation: 36272
One way, neither elegant nor efficient, but it works:
Add following function to your vimrc
file. It inserts at the beginning of each line its number of characters, sort them numerically and deletes the numbers.
function! SortLines() range
execute a:firstline . "," . a:lastline . 's/^\(.*\)$/\=strdisplaywidth( submatch(0) ) . " " . submatch(0)/'
execute a:firstline . "," . a:lastline . 'sort n'
execute a:firstline . "," . a:lastline . 's/^\d\+\s//'
endfunction
Call it with a range of numbers, like
:4,18call SortLines()
or in Visual mode using V
, like:
:'<,'>call SortLines()
EDIT: Ops, now I realised that this solution is very similar to yours. It was fine, only that %
means the complete buffer instead :4,18
or :'<,:'>
that selects specific lines.
Upvotes: 8
Reputation: 84393
One way to do this in vim is by filtering the visual selection with awk's length() function before sorting. For example:
:'<,'> ! awk '{ print length(), $0 | "sort -n | cut -d\\ -f2-" }'
Upvotes: 44