2

Let's say I have a bunch of vim mappings (although it could be code in any language), each of which with a comment line or lines above them:

(using # not " so the comments get highlighted nicely)

# A comment
nnoremap <Leader>a ...
# D comment
nnoremap <Leader>d ...
# B comment
nnoremap <Leader>b ...
# H comment
nnoremap <Leader>h ...
# C comment
#   comment cont'd
#   comment cont'd
nnoremap <Leader>c ...
# F comment
nnoremap <Leader>f ...
# G comment
nnoremap <Leader>g ...
# E comment
nnoremap <Leader>e ...

How do I sort these lines, while preserving the association of comments with the first non-comment line below them?

i.e. I want this output:

# A comment
nnoremap <Leader>a ...
# B comment
nnoremap <Leader>b ...
# C comment
#   comment cont'd
#   comment cont'd
nnoremap <Leader>c ...
# D comment
nnoremap <Leader>d ...
# E comment
nnoremap <Leader>e ...
# F comment
nnoremap <Leader>f ...
# G comment
nnoremap <Leader>g ...
# H comment
nnoremap <Leader>h ...
3

Visually select your lines, then run:

" join the comments and the related command
*g/^\s*#/,/^\s*[^# ]/-s/\n/\="\x01"

" sort the lines
*sort

" split back the lines
*s/\%x01/\r/g

To operate on the whole buffer rather than the visual selection, replace the * range with %.

Note that ā€“ in Vim ā€“ the comment leader is ", not #; unless you're writing a Vim9 script (:h vim9-differences).

| improve this answer | |
  • 1
    I edited the comments a bit; OP was explicitly using lang-bash, and Iā€™d rather not confuse people :) – D. Ben Knoble Jun 18 at 11:36

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