Vim 8 - How do I re-number my list after reordering the list - manually or automatically?

73 views Asked by At

Say I have a list like this:

1. apple
2. banana
3. orange
4. plum

Now I want to reorder them by deleting/cutting lines and pasting them in the right spot, but the numbers are no longer in order:

2. banana
1. apple
4. plum
3. orange

How can I re-number this list or have Vim handle a numbered list automatically? (I'll add my answer, but I believe there should be a faster way)

3

There are 3 answers

2
wxz On BEST ANSWER

One slightly inefficient way is to reset the numbered list to zeros and then recreate them.

For instance, once the list looks like this:

2. banana
1. apple
4. plum
3. orange

do the following.

  1. Highlight list and run :s/[0-9]*\./0./ to substitute the numbered list for a list all beginning with 0.
0. banana
0. apple
0. plum
0. orange
  1. Highlight entire list again using gv (as suggested in comments) and do g and then <ctrl> + a to renumber list from 1-n

EDIT April 2nd, 2024 - Based on the suggestion from @romainl in the comments and from community help in these questions (one and two), I took my solution above and made a Vimscript function that can be added to a .vimrc .

vnoremap <C-L> :call ReNumberList()<CR>
function! ReNumberList() range
    execute a:firstline .. ',' .. a:lastline .. 's/[0-9]*\./0./'
    execute "normal! gvg\<C-A>"
endfunction

It works by remapping the shortcut ctrl+L (<C-L>) to the function ReNumberList(). That function does the number substitution on the range of lines, re-highlights the range again (with gv), and finally does the renumbering with g\<C-A>.

With this, you can highlight an out of order list and then type one shortcut to renumber the whole list!

2
romainl On

NOTE: this answer assumes that you are doing that in a markdown context.

FWIW, Markdown renderers are generally expected to ignore the actual numbers in your numbered list except the first one, which is used as a hint for how the output will be numbered.

This list:

2. banana
1. apple
4. plum
3. orange

is rendered as:

  1. banana
  2. apple
  3. plum
  4. orange

list

<ol start="2">
<li>banana</li>
<li>apple</li>
<li>plum</li>
<li>orange</li>
</ol>

but this list:

1. banana
1. apple
4. plum
3. orange

is rendered as:

  1. banana
  2. apple
  3. plum
  4. orange

list

<ol>
<li>banana</li>
<li>apple</li>
<li>plum</li>
<li>orange</li>
</ol>

or maybe:

<ol start="1">
<li>banana</li>
<li>apple</li>
<li>plum</li>
<li>orange</li>
</ol>

If your ultimate goal is to render your markdown to something else (meaning that your *.md is only read when editing, not on its own), I would suggest you give up on proper ordering in your source and only use 1. as a hint for the renderer:

1. banana
1. apple
1. plum
1. orange

and let it do its magic:

  1. banana
  2. apple
  3. plum
  4. orange

list

<ol>
<li>banana</li>
<li>apple</li>
<li>plum</li>
<li>orange</li>
</ol>
1
Friedrich On

As I said in a comment, this case is covered by How to search and replace with a counter-based expression in Vim?. That the list was ordered before is of no consequence. It's not as if those tiny list items carried a memory of their previous ordering.

The request was especially to make it simple. For a list with only four items, I'd actually just reorder it out-of-place and leave the numbers untouched.

Starting with the list below:

1. apple
2. banana
3. orange
4. plum

For that, I'd use blockwise Visual mode to select the list items, not the numbers. Put the cursor on the first list item, press <C-V>, select all the items by pressing }$ and cut them with d.

For the actual list operations, I'd paste the list items e.g. in a scratch buffer (see :help scratch-buffer); the bottom of the current buffer will also do nicely.

1. 
2. 
3. 
4. 

# somewhere else

apple
banana
orange
plum

Reorder the list items to your desired order, do a blockwise Visual selection again and delete them. Then paste them back after the first number of your original list.
Done:

1. banana
2. apple
3. orange
4. plum

If you ever needed to add to the list, you can append an item to its end and then reorder as outlined above.