Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting Vim Folds

Tags:

vim

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.

like image 408
user1311904 Avatar asked Nov 25 '12 18:11

user1311904


3 Answers

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:

  1. Join all folded lines together with a delimiter that does not exist in the text (e.g. <Nul>).
  2. Execute the :sort command.
  3. Un-join the range on the special delimiter.

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

like image 56
Ingo Karkat Avatar answered Nov 13 '22 12:11

Ingo Karkat


One approach would be as follows:

  1. 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).

  2. Use :sort to sort the lines in the file, as usual.

  3. 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.

like image 1
Matthew Strawbridge Avatar answered Nov 13 '22 14:11

Matthew Strawbridge


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)

  • /{^M find next {
  • V%k select line-vise till the end of level 1 but not the closing line with }}}
  • :s/\n/EEEEEE/^M change symbol 'end of line' to some unique string inside selection
  • j^ go one line down and to the begging of the line in case the previous record had leading spaces.

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.

like image 1
ISQ Avatar answered Nov 13 '22 13:11

ISQ