Vim: sorting with levels

Viewed 43

I have the following file with Markdown markup:

* [B](B)
  * b
  * c
* [C](C)
* [A](a)
  * a

I try to sort it and get the following result:

* [A](a)
  * a
* [B](B)
  * b
  * c
* [C](C)

It is necessary to sort only the main levels, and sub-levels must follow the main levels, i.e., stay at the levels where they were. The first thing that comes to mind is of course :sort; but unfortunately this will also sort the sub-levels. We will get:

  * a
  * b
  * c
* [A](a)
* [B](B)
* [C](C)

Are there any tricks or plugins for this kind of sorting? Thx!

1 Answers

The usual approach for this class of problems is to inline each block, then sort them, and then "de-inline" them back to their original state.

First step: inline each block.

We do this by replacing each EOL followed by SPACE-SPACE-STAR with some fancy symbol unlikely to be found in our document:

:%s/\n\(  \*\)/§\1

Which gives us the following:

* [B](B)§  * b§  * c
* [C](C)
* [A](a)§  * a

Second step: sort the buffer.

We simply use :help :sort:

:sort

to obtain this:

* [A](a)§  * a
* [B](B)§  * b§  * c
* [C](C)

Third step: revert each "block" to its initial state.

We do this by reverting the substitution above with another, much simpler, one:

:%s/§/\r

which gives us the desired outcome:

* [A](a)
  * a
* [B](B)
  * b
  * c
* [C](C)

A couple of notes:

  • The exact pattern to use in the first substitution depends on the exact structure of your document. That part is, IMO, too highly contextual to be generalisable.
  • § is just an example, use whatever symbol you want.
Related