Search code examples
searchvimreplace

How to search and replace globally, starting from the cursor position and wrapping around the end of file, in a single command invocation in Vim?


When I search with the / Normal-mode command:

/\vSEARCHTERM

Vim starts the search from the cursor position and continues downwards, wrapping around to the top. However, when I search and replace using the :substitute command:

:%s/\vBEFORE/AFTER/gc

Vim starts at the top of the file, instead.

Is there a way to make Vim perform search and replace starting from the cursor position and wrapping around to the top once it reaches the end?


Solution

  • 1. It is not hard to achieve the behavior in question using a two-step substitution:

    :,$s/BEFORE/AFTER/gc|1,''-&&
    

    First, the substitution command is run for each line starting from the current one until the end of file:

    ,$s/BEFORE/AFTER/gc
    

    Then, that :substitute command is repeated with the same search pattern, replacement string, and flags, using the :& command (see :help :&):

    1,''-&&
    

    The latter, however, performs the substitution on the range of lines from the first line of the file to the line where the previous context mark has been set, minus one. Since the first :substitute command stores the cursor position before starting actual replacements, the line addressed by '' is the line that was the current one before that substitution command was run. (The '' address refers to the ' pseudo-mark; see :help :range and :help '' for details.)

    Note that the second command (after the | command separator—see :help :bar) does not require any change when the pattern or flags are altered in the first one.

    2. To save some typing, in order to bring up the skeleton of the above substitution command in the command line, one can define a Normal-mode mapping, like so:

    :noremap <leader>cs :,$s///gc\|1,''-&&<c-b><right><right><right><right>
    

    The trailing <c-b><right><right><right><right> part is necessary to move the cursor to the beginning of the command line (<c-b>) and then four characters to the right (<right> × 4), thus putting it between the first two slash signs, ready for the user to start typing the search pattern. Once the desired pattern and the replacement are ready, the resulting command can be run by pressing Enter.

    (One might consider having // instead of /// in the mapping above, if one prefers to type the pattern and then type the separating slash oneself, followed by the replacement string, instead of using the right arrow to move the cursor over an already present separating slash starting the replacement part.)