Yesterday I had to refactor a very large ruby class. It had a lot of methods and, to make it cleaner, I decided to sort methods alphabetically.
Is there a way to do this in vim? Of course there is, and it’s quite tricky - so let’s see how we can do it.
The basic idea is taken from this post on wincent.com, I just adapted it for ruby. All credits to this guy for his work :)
We’ll use the same approach of the original post: first we’ll collapse each ruby method on a single line, using a defined pattern to replace line terminators. We’ll proceed sorting the one-lined methods, and finally we’ll expand them back to multi-line.
These are the three commands, we’ll explain them in detail later:
:'<,'>g/\vdef\ /,/\v^\s*end$/ s/$\n/@@@
:'<,'>sort
:'<,'>s/@@@/\r/g
Let’s do it step by step.
1. Collapsing on a single line Link to heading
First, we visually select the methods we want to sort, and issue this command:
:'<,'>g/\vdef\ /,/\v^\s*end$/ s/$\n/@@@
This will apply a global command on every instance of a defined pattern inside our visual selection. Look at the documentation inside vim for global commands (:help :g
):
*:g* *:global* *E147* *E148*
:[range]g[lobal]/{pattern}/[cmd]
Execute the Ex command [cmd] (default ":p") on the
lines within [range] where {pattern} matches.
So, our range is '<,'>
(this means from <
mark to >
mark, in other words from the beginning of the visual selection to its end); our pattern is \vdef\ /,/\v^\s*end$/
. This means everything from def\
(a def followed by a space) to \^s*end$
(a line starting with any number of spaces, followed by end
and the end of line).
/,/
is how range beginning and end are separated; the \v
is used to toggle the very magic
mode, which allows a less verbose regexp syntax (see :help \v
for more info).
Finally, our Ex command cmd is s/$\n/@@@
. It’s a simple substitution: replace each line ending with our defined pattern, @@@
.
2. Sorting collapsed lines Link to heading
This is easy. Just visually select the collapsed lines and issue
:'<,'>sort
3. Expand lines back with line returns Link to heading
Again, select the sorted lines (you can use gv
to redo the last visual selection) and issue this command:
:'<,'>s/@@@/\r/g
This is a simple substitution: it replaces our defined pattern, @@@
, with a line return (\r
).
I hope you’ve learnt something from this article, I love that even after many years of vim usage I’m still surprised by its powerfulness every day. Have a good day!