3

Let us say we have the following for loop in Vim:

for(int i = 0; i < len; ++i);

and I want to change the variable i to j.

I have to do it manually for each i. Is there a way in Vim so that when I change one i, and it also changes the rest?

I use ultisnips and when I create a for loop for example, I am able to change all i's at the same time, but I would also like to do that even once I'm done with the snippet. Is that possible?

Edit:

I've just realized what I should have asked instead for was a way to refactor the code like you can do in an IDE, but from what I can see this is not possible with vim, nonetheless, I appreciate all the useful tips for doing so in vim.

5

You can use the :substitute command (optionally with a suitable [range] if the loop variable is spread over multiple lines) with the g flag to replace all occurrences:

:s/\<i\>/j/g

Note the \<...\> for a full word match (to avoid changing int to jnt).

Plugin suggestion

My ChangeGlobally plugin provides a gc{motion} command that works like built-in change, but then applies that change to all other occurrences in the line. With it, your example can be edited via ^Wgclj<Esc>.

  • A friendly way to do this might be to hit V or va{ to select the lines that interest you (or drag-select them with the mouse), then do :s/\<i\>/j/gc. The c flag asks for confirmation of each change, so you can feel extra confident that you didn't change anything unwanted. If hlsearch is enabled, all the matches will be highlighted, so you can hit a if you see that you want to replace all of them. – joeytwiddle Mar 12 '15 at 18:10
  • Although FWIW, I also use a handy little plugin for this task. \r for whole file, \R for all buffers. But no option to cover only the visual selection (the visual selection is taken as the search pattern). – joeytwiddle Mar 12 '15 at 18:21
3

It's not really a good example, but you can make use of the gn operation, if you do not want to use the :s solution suggested above.

First search for your variable /\<i\> to make sure, only the single variable i will be caught and not e.g. a word like variable. Then do cgnj to change your first match to a j. Now you can repeat the change with the . command.

  • To avoid typing the variable, I often hover over it and hit *. Then N to go back to where I was. Then cwj<Esc> then n.n.n.n. :) – joeytwiddle Mar 12 '15 at 18:13
  • 1
    The advantage of using gn is, you do not have to type n.n. but only . – Christian Brabandt Mar 12 '15 at 21:30
  • I see, that is useful. I had better upgrade to Vim 7.4! – joeytwiddle Mar 15 '15 at 21:07
2

You could do it with a substitution:

:5,20s/\<i\>/j/g
  • 5,20: Between lines 5 and 20,
  • s: substitute,
  • /\<i\>/ all instances of the word i (the \< and \> match word boundaries,
  • j with the letter j,
  • /g: everywhere in the line.

If you don't want to use line numbers, you could instead first select the area where you want to make the substitution in visual mode, and then Vim will pre-populate the command line with a range specifying the selection when you press :.

If you want to make the replacement everywhere in the current buffer, you can use the % range, instead:

:%s/\<i\>/j/g
  • 1
    I am aware of the substitute command but I was hoping for something simpler... – fYre Mar 10 '15 at 15:14
1

To simplify the other substitute solutions given, one thing that no one has mentioned so far is that you can use the * command to search for the word under your cursor. This pulls the word into the "/ register WITH the \<\>, so you don't have to type it yourself.

Then, when you go to make your substitution, you can leave the search text blank (it will automatically search for what is in the "/ buffer). The process could look like this:

for(int i = 0; i < len; ++i);

/i <return>
*
:s//j/g

This finds i<space>, searches for \<i\>, and i with j on the current line, resulting in:

for(int j = 0; j < len; ++j);

You can combine this easily with line-wise visual selection (V) to select the lines you want to change. You could even v or ctrl+v to make a visual selection or visual blocks. With the latter two, if you have a match on the same line, but outside your visual selection, you'll need to use the \%V atom and paste (ctrl-r /) the / register in the search command to only substitute within the visual selection. For example:

for(int i = 0; i < len; ++i); i

/i <return>
*
vi(
:s/\%V<ctrl-r>//j/g

The last line becomes:

'<,'>s/\%V\<i\>/j/g

This finds i<space>, searches for \<i\>, selects inside the parentheses, and replaces i with j ONLY within the visual selection, resulting in:

for(int j = 0; j < len; ++j); i

But again, that only applies if you have matches on a selected line, but outside a visual selection (like that trailing i).

1

For a simple solution, you can check out the multiple-cursors plugin, allowing you to mouse over i, hit Ctrl-N a few times and changing the letter to j with cej.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.