How g makes loop in Vim ex command script

前端 未结 2 1346
没有蜡笔的小新
没有蜡笔的小新 2021-02-10 03:08

Consider the following Vim ex command,

:let i=1 | \'<,\'>g/^/ s/^\\ *-/\\=i/ | let i+=1

It replaces the heading dash with ordered number

相关标签:
2条回答
  • 2021-02-10 03:48

    This is the general pattern of a :global command:

    :g/foo/command
    

    Because everything after the second separator is considered as one command, the counter is incremented each time the command is executed: one time for each matching line.

    0 讨论(0)
  • 2021-02-10 03:50

    The pattern of a global command is:

    :range g[lobal][!]/pattern/cmd
    

    The global commands work by first scanning through the [range] of of the lines and marking each line where a match occurs. In a second scan the [cmd] is executed for each marked line with its line number prepended. If a line is changed or deleted its mark disappears. The default for the [range] is the whole file. (see http://vimregex.com/#global for more details)

    Now let's analyse

    :let i=1 | '<,'>g/^/ s/^\ *-/\=i/ | let i+=1
    

    step by step.

    1. let i=1 is a single command executed setting the basic number for the loop. We can just execute it alone at the very beginning. Then '<,'>g/^/ s/^\ *-/\=i/ | let i+=1 looks a little more like a global command.
    2. '<,'>g defines the range. '< represents the first line and '> represents the last line of the selected area. (:help '< for more details)
    3. ^ of course matches every line in range.
    4. s/^\ *-/\=i/ | let i+=1 is the [cmd], the number of times it will be executed equals to the number of lines in the selected area, and this is the most important reason why the loop took place.
    5. The part before | is a typical substitute command :range s[ubstitute]/pattern/string/ (see http://vimregex.com/#substitute for more details)
    6. ^\ *- matches 0 or more whitespace followed by a dash at the beginning of a line. We substitute \=i for this pattern. (:help :s\= for more details)
    7. After s/^\ *-/\=i/, let i+=1 is executed. Then the next line, ... , till the last line of selected area.
    8. For better understanding that s/^\ *-/\=i/ | let i+=1 is a [cmd] as a whole, we can change the order of the two [sub-cmd], obtaining let i+=1 | s/^\ *-/\=i/. But for the same effect, let i=0 at the very beginning is essential.
    0 讨论(0)
提交回复
热议问题