February 15, 2026
One common text editing task is inserting an incrementing number throughout a file.
Think for example, a numbered list that you want to re-number, or a sequential list of steps in a procedure.
Vim has a few tools with which you can make that edit: visual block mode, macros, and the :g command.
I cover them at a high level in this post.
Let’s start with something basic. Consider a list like this that you want to convert to a numbered list:
- first item
- second item
- third item
- fourth item
In this case, I would reach for visual-block-increment (:help v_g_CTRL-A).
Position the cursor on the first line, then press <c-v> to enter visual block mode.
Press 3j to select the first character of all 4 lines.
Press s, and then type 1. and hit <esc> to prefix each line with 1..
Press gv to re-select the range, press o to move the cursor to the start of the visual block, press j to deselect the first line.
Then press g<c-a> to increment numbers on each line.
The result should be:
1. first item
2. second item
3. third item
4. fourth itemBut the first example was the simplest case. Consider something like:
title: Test procedure
author: me
steps:
step_1:
action: Do a thing
result: Achieve a result
step_2:
action: Do a second thing
result: Achieve a second result
step_3:
action: Do a third thing
result: Achieve a third result
And then you want to add a step between steps 2 and 3, and then renumber all of the steps:
title: Test procedure
author: me
steps:
step_1:
action: Do a thing
result: Achieve a result
step_2:
action: Do a second thing
result: Achieve a second result
step_3:
action: Insert a new step
result: And now all the step numbers are screwed up
# Oops: duplicate step number
step_3:
action: Do a third thing
result: Achieve a third result
Of course, in this example it’s still easy, but imagine that there are 20 steps instead, and you have to renumber all steps after step 3.
A “brute force” (but still totally fine) approach would be to record a macro, and then replay it on each line.
There’s not much more to say about it – you record it once with q and either execute recursively, with :norm, or just directly with @.
But there is an idiom specifically suited for this editing task, which consists of two lines of Vim script that you run in command mode (:):
let counter=1
g/text you search for/s/text to replace/\="text to replace"..counter/ | let counter+=1
The first command just sets a counter variable. The second command breaks down as:
g/search/s/A/B/ | let counter += 1: on every line that matches search, substitute A with B, and then increment the counter (the pipe in Vimscript chains statements like a semicolon in Bash, JavaScript, Java, and many other languages). See :help :g; this is one of Vim’s most powerful commands.s/text to replace/\="text to replace"..counter/: replace text to replace with the result of evaluating a Vimscript expression (see :help sub-replace-expression). In this case, the expression is a concatenation of the string text to replace and the value of the counter variable. In Vimscript, .. means string concatenation.Adjusted to our case, the idiom can be something like:
let n=1
g/step_\d/s/step_\d*:/\="step_"..n..":"/ | let n+=1
And the result of running this is:
title: Test procedure
author: me
steps:
step_1:
action: Do a thing
result: Achieve a result
step_2:
action: Do a second thing
result: Achieve a second result
step_3:
action: Insert a new step
result: And now all the step numbers are screwed up
# And now the step number is fixed
step_4:
action: Do a third thing
result: Achieve a third result