newline

Table of Contents

  1. Visual block increment
  2. Global-substitute with expression

A useful Vim idiom: insert an incrementing number throughout a file

Vim, Shell

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.

Visual block increment

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 item

Global-substitute with expression

But 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:

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