How to quickly change variable names in Vim?
AFAIK, there is no actual refactoring support in VIM. When doing a rename with the intent of a refactor I usually take the following precautions:
- Limit the scope of the change my using marks.
- When entering the regex, bracket the name with \< and >. This will make it match an entire word which reduces the types of incorrect renames that will occur.
- Don't do a multiline replace to reduce chances of a bad replace
- Look through the code diff carefully if it's anything other than a small change.
My end change looks something like this
:'a,'bs/\<foo\>/bar
I would love to be wrong about there not being a refactoring tool for VIM but I haven't seen it.
I know it's an old question, and @mykola-golubyev's way obviously IS the best answer for the particular case in the OP question (which, I assume is going through obfuscated code where you're likely to have multiple blocks with same var names); but with the question name like that many people coming here from google searches probably look for a less situation-specific ways to rename variables in VIM -- and those can be more concise
I'm surprized no one suggested this way:
*
:s//
NEWNAME/gc
The *
is the same as gn
- it searches for the next occurence of the word under cursor AND it becomes the last searched pattern, so when you omit the search pattern in the substitute command, VIM assumes this is the pattern to search for.
For small amounts of var copies, an even quicker one:
*
cw
NEWNAME<esc>
then repeatn.
for other occurrences
Search for occurrence, cw
is the command for change word, n
goes to next occurrence of the last searched term and .
repeats the last command (which is change word to NEWNAME)
(Credits for me knowing all this go to @doomedbunnies on Reddit)
Another cool trick is this: (credits to @nobe4)
*
cgn
NEWNAME<esc>
then repeat.
for other occurrences
cgn
is "change whatever is the result of (find next occurrence)". Now that this is the last command, you don't need the n
to go to the next occurrence, so fewer strokes again, and, more importantly, no need to alternate n
and .
. But, obviously, this one has the drawback of not having a way to skip an occurrence.
Here are some benefits:
- no mapping, no .vimrc(or init.vim), so you can use it in any VIM copy you come across (e.g. a quick task on some VPS or your friend's machine where configuring VIM your way would defeat the purpose of 'quick')
- using
*
orgn
for word selection is very quick -- just one keystroke (well, let's say 1.5) - using
*
orgn
makes sure you don't get any matches inside other words, just as:%s/<C-R>//gc
does. Beats typing the:%s/\<OLDNAME\>/NEWNAME/gc
by hand: I personally tend to forget to use the\<
things to limit matches to whole words only. - Not using scope will only result in a few extra strokes of
n
to skip unwanted matches -- probably even fewer than the extra strokes needed to limit the scope. Under normal curcumstances, your variables are most likely somewhat localized to a certain code block anyway.
The following is how to rename a variable which is defined in the current scope {}
.
Move your cursor to the variable usage. Press gd
. Which means - move cursor to the definition.
Now Press [{
- this will bring you to the scope begin.
Press V
- will turn on Visual Line selection.
Press %
- will jump to the opposite }
thus will select the whole scope.
Press :s/
- start of the substitute command.
<C-R>/
- will insert pattern that match variable name (that name you were on before pressing gd
).
/newname/gc<CR>
- will initiate search and replace with confirmation on every match.
Now you have to record a macros or even better - map a key.
Here are the final mappings:
" For local replace
nnoremap gr gd[{V%::s/<C-R>///gc<left><left><left>
" For global replace
nnoremap gR gD:%s/<C-R>///gc<left><left><left>
Put this to your .vimrc
or just execute.
After this pressing gr
on the local variable will bring you to :s
command where you simply should enter new_variable_name
and press Enter.