4

The task I have in mind is I have grown files containing multiline definitions. Currently I'm working on a file containing acronyms for latex - many entries like this, but most much more complex:

\DeclareAcronym{AUC}{
  short = {AUC},
  long = {Area Under Curve},
  extra = {long text with \many{macros} and $math$}}

The problem is by joining more definitions the entries get mixed up and harder to deal with. I would prefer them sorted.

I know vim has great functionality sorting lines - I could just join everything into one line, but then I would need to rearrange it afterwards. I suppose I could come up with something for the trivial entries but the complex extra blocks (and other non shown) give me a hard time.

Is there any functionality organizing such blocks in vim?

6

Peter Rincker's SortGroup is the go-to script for this kind of work.

https://gist.github.com/PeterRincker/582ea9be24a69e6dd8e237eb877b8978

Somewhat differently to vim's :sort, it takes a pattern which is supposed to match the text declaring lines as the start of a group. For example,

:SortGroup /^\DeclareAcronym{/

will sort all the DeclareAcronym commands intact, by the text on the line. If every line starts with DeclareAcronym, this will "do the right thing" and sort by the keys, but if lines might start with different commands, the command name will be used.

| improve this answer | |
4

There is no direct functionality for that. (At least non I know of.)

Assuming that none of the field short, long and extra contains any line-breaks:

First join the lines into a single line.

g/^\\DeclareAcronym/,/}}$/join

This selects the lines from \Declare to a line that ends with }} and joins those line into a single line.

Then

sort

And finally break the lines again:

%s/\([{,]\) \(short\|long\|extra\)/\1\r  \2/g

This inserts the line breaks and two space indent before short, long and extra. If any of the fields contains a line-break this last step would not recreate the original formatting.

| improve this answer | |
  • This is helpful, but I'm looking for a more general way - there are many optional fields that could occur and each could hold latex and span lines. – bdecaf May 2 at 16:37
2

The standard trick for doing this is to convert your blocks into single lines not by removing the linebreaks, but instead by replacing them with something you can find again easily after the sort.

e.g.

  1. Replace all linebreaks that don't follow a } with LINEBREAK:

    :%s/}\@<!\n/LINEBREAK
    
  2. Sort:

    :sort
    
  3. Split the blocks into multiple lines again:

    :%s/LINEBREAK/\r/g
    

You might need to tweak your regular expression in step 1., depending on the content of your more complicated blocks, but you’ve implied that joining the lines is feasible in your question, so I presume you’re comfortable doing this already. (But if not, I’d be happy to help if you add a few more examples.)

| improve this answer | |
  • I like the idea. It definitely solves the example given, but I was looking for a more general solution as I encounter this task in various contexts - like in bibtex, yaml, and so on. I would prefer not to join lines. – bdecaf May 2 at 16:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.