I actually have a pretty similar workflow to yours, (copying and pasting blocks that are similar, then using :s
to change variable names) especially when I'm writing lots of lines that are similar except for which variable they use. But there are a couple things I do that you might find useful.
General vim things
The first thing that will help you is realizing that :s//foo/g
will fill in whatever search term you used last and replace that with foo. That alone can save a lot of time, but when you combine it with the asterisk command (search for the word under the current cursor) it saves tons of time. For example, to change all foo
to spam
, instead of doing
:%s/foo/spam/g
Which requires you to type out both foo and spam (which may be long variables), you can simply navigate to foo, and do:
*:%s//spam/g
This way, you can quickly get the name of the variable you're changing by searching for it, then you won't need to type it out. This will also work nicely with your current workflow of using n
a lot. It's also helpful to have hlsearch
on, because then you can visually tell where the variables you're replacing are.
(side note: The asterisk command will add word boundaries, that is \<
and \>
around the word under the cursor. If you don't want this, use g*
instead.)
-
it would be much preferable if I could repeat the replacement action with a single keystroke
You can use @:
to redo the last substitute command. That is nice if you want to do an :s
command on lots of lines, but not all of them so :%s
will not work. Another option is the confirmation flag, i.e. :%s///gc
. This will allow you to type y
or n
on each occurrence to decide if you want to replace it or not.
As Desty pointed out, you can also do & to re-run the last substitute command, but note that this will not keep your flags (such as global
or confirm
). Whether that is good or bad depends on your personal opinion. If you would like to use this but have it keep your flags also, you could do
nnoremap & :&&<cr>
If you want to change every occurrence in a block, but not every match in the file, you could always use a visual selection of the block, which will fill in
:'<,'>
to your substitute, which restricts it to the lines you have selected. When combined with the asterisk approach, I find this extremely useful. Additionally, if you are making multiple substitute commands on the same block of lines, you can use gv to reselect the same lines to do another command. (whether it's a :substitute
or a normal command)
If you do another substitute command, you do not need to reselect the same lines, because :'<,'>
will still operate on the same lines. However, it is more convenient to type
gv:s
rather than
:'<,'>s
Plugins/Mappings I like
I have the following mapping in my .vimrc
which extends the asterisk approach so that I only have to type the new desired name:
"(R)eplace all
nnoremap <leader>r yiw:%s/\<<C-r>"\>//g<left><left>
To use this, just put your cursor on the word you want to change, and type <leader>rNewVarName<cr>
and you're done. Note that this will replace all matches without giving you an option to confirm them, so you might not like it as much. Of course, to allow for the confirm option, you could just change it to
nnoremap <leader>r yiw:%s/\<<C-r>"\>//gc<left><left><left>
edit: Following both Mass's answer and rcorre's comment, you could also write this as
nnoremap <leader>r :%s/\<<C-r><C-w>\>//g<left><left>
which has the advantage of keeping your unnamed (yank) register the same.
If you're renaming groups of similar variables at the same time, for example, changing
fooSuffix
PrefixFoo
foo1
SHOUTINGFOO
to
barSuffix
PrefixBar
bar1
SHOUTINGBAR
it can be a pain to substitute all of them individually. This is where tpope/vim-abolish comes in handy. You can replace all of these in one command with:
:%S/foo/bar/g
and it takes care of the capitalization for you.
These should help you a lot, but let me know if there's anything about these approaches you don't like or feel is lacking. I'm happy to talk about more approaches. :)
Recommended Reading:
.
repeats the last "command block" (not sure of the exact term. for example: move + action + text. for exemple:cwtoto<Esc>
(change from cursor to end of the word with "toto"),c/foo<enter>bar<Esc>
(change from cursor to just before "foo", and replace with "bar"). you can then move (with cursor, hjkl, or a number+hjkl (does it n times), G (go to end of the file), /something (go just before "something"), etc) and then press.
to redo the same "command block"n
ve
"0p
. Which unfortunately can't be replicated with just a.
n ce ctrl-r 0 <esc> n.n.n.n.n.n.