I have a file that looks something like this:
dog{{{
blah blah blah
}}}
cat{{{
blah blah
}}}
aardvark{{{
blah blah blah blah
}}}
In my vimrc I have set foldmethod=marker
, so that the contents of the file are all folded at the curly braces. My question is, how can I sort the file based on the fold header? I want the aarvaark
section to come first, then cat
, then dog
.
Some folded sections have other folds within them. I do not want to sort those lower fold levels. The file should be sorted by level 1 folds only.
With all folds closed (zM
or :set foldlevel=0
), you can use delete dd
and paste p
to manually shift the folded blocks around. This is okay for small amounts of text.
For huge texts, you'd have to write a sort function yourself, as Vim does not offer such functionality. The following algorithm can be used:
<Nul>
).:sort
command.With error handling and corner cases, it's actually quite a bit of implementation effort. I've made an attempt here: https://gist.github.com/4145501
One approach would be as follows:
Search and replace the line endings so that the level-one folds are each on one line (i.e. replacing the line ending with a unique string that doesn't appear elsewhere in the file).
Use :sort
to sort the lines in the file, as usual.
Reverse the search and replace from Step 1 to reintroduce the line endings.
This could all be recorded as a Vim macro.
Steps 1 and 3 would be straightforward if there weren't nested folds, or if there was an easy way of distinguishing top-level folds from nested ones (e.g. if the level-one {{{ and }}} lines are flush left and the others have leading space). If this isn't the case, it's probably still possible but much more difficult.
I would use power of Vim macros.
Suppose that you do not have any other staff in your file except the records and first record starts on the first line. And that you do not have start of level 1 and end on the same line. And all your {} match well.
Go to the first entry and record a macro to register a (qa
- start recording q
- stop)
/{^MV%k:s/\n/EEEEEE/^Mj^
Copy mine or better record it yourself: (^M - stands for literal enter)
Run the macro starting from the second line (suppose that the first is processed already when you recorded the macro.) In normal mode 100000@a - use whatever number greater than number of your records. Macro will stop itself when all lines are processed if the first record is in the first line of file. As a side effect it will visually select the first line - unselect it.
Sort the file
:sort
Restore the end of lines: :%s/EEEEEE/^M/g
Note ^M should be literal enter. To type it use Ctrl-V Enter
It works with nested levels because % jumps to the matching closing }. That is why it is important that you have all the {} matched well.
Macro will stop when could not go up with k
that is why you must have the first record on the first line. Empty lines or anything that is not a record between records will be ignored by the macro.
The method above should work well for your file. If you want a more general approach with folds then use the following commands in the macro instead of /{ and %
Firstly open all folds
zj - go to the start of the next open fold
]z - go to the end of the current fold.
The rest of the macro is the same. This method is more general but I found it less reliable since it depend on all folds open, folding enable and so on.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With