Consider the following Vim ex command,
:let i=1 | '<,'>g/^/ s/^\ *-/\=i/ | let i+=1
It replaces the heading dash with ordered number in selected lines.
I don't understand why this command works as a loop from the first line to the last line of the selected lines. That is, how g can repeat let i+=1 over and over again.
The g command first scans all lines in range and marks those that match pattern . It then iterates over the marked lines and executes cmd . (See multi-repeat in vim's documentation). If cmd happens to delete a marked line, the mark disappears.
An exclamation mark ( ! ) tells ex to create a shell and to regard what follows as a Unix command: :! command. So if you are editing and you want to check the time or date without exiting vi, you can enter: :!date.
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.
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.'<,'>g defines the range. '< represents the first line and '> represents the last line of the selected area. (:help '< for more details)^ of course matches every line in range.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.| is a typical substitute command :range s[ubstitute]/pattern/string/ (see http://vimregex.com/#substitute for more details)^\ *- 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)s/^\ *-/\=i/, let i+=1 is executed. Then the next line, ... , till the last line of selected area.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.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With