I have a solution using operators and text objects, also working with visual-mode. I believe it uses less keystrokes and is more vim-like than the idedit solution, and becomes intuitive and quick to use.
function! GetTextObject(type, is_visual)
let sel_save = &selection
let &selection = "inclusive"
let reg_save = @@
if a:is_visual
silent execute "normal! gvy"
elseif a:type == 'line'
silent execute "normal! '[V']y"
else
silent execute "normal! `[v`]y"
endif
let text = @@
let &selection = sel_save
let @@ = reg_save
return text
endfunction
function! ReplaceOperator(type, ...)
let text = GetTextObject(a:type, a:0)
call feedkeys(":%s/".text."//g\<left>\<left>", "n")
endfunction
nnoremap gr :set opfunc=ReplaceOperator<cr>g@
vnoremap gr :<C-u>call ReplaceOperator(visualmode(), 1)<cr>
function! AppendReplaceOperator(type, ...)
let text = GetTextObject(a:type, a:0)
call feedkeys(":%s/".text."/".text."/g\<left>\<left>", "n")
endfunction
nnoremap gA :set opfunc=AppendReplaceOperator<cr>g@
vnoremap gA :<C-u>call AppendReplaceOperator(visualmode(), 1)<cr>
function! PrependReplaceOperator(type, ...)
let text = GetTextObject(a:type, a:0)
call feedkeys(":%s/".text."/".text."/g".repeat("\<left>", len(text) + 2), "n")
endfunction
nnoremap gI :set opfunc=PrependReplaceOperator<cr>g@
vnoremap gI :<C-u>call PrependReplaceOperator(visualmode(), 1)<cr>
Inserting this into your ~/.vimrc
or ~/_vimrc
or equivalent, this should give you three operators which work on text-objects in normal-mode, and selections in visual-mode. These operators are gr
, gA
, and gI
standing respectively for "go replace", "go Append replace", and "go Insert before replace". These may be intuitive because many operators are under the prefix g
, and r
replaces characters, A
appends and I
inserts before.
Now, you can simply move the cursor over the word you want to replace over the whole buffer, and type in normal-mode:
griwThing<cr>
to replace all instances of the word with "Thing". The other operators work similarly but put you in a substitute command with the text being replaced already there, with the cursor placed after or before the text.
So, for example, select your text in visual mode, for example the current Word until the end of the line:
viW$hgA_1<cr>
selects the text giving you a visual of what you will replace, then puts you in a substitute command letting you add, for example "_1" to the end of the replacement. You can also use this to easily remove characters from the end of each instance.
Explanation of the vimscript code:
Operators are implemented in a strange way in vim, using a setting called operatorfunc
or opfunc
which is called whenever you type @g
in normal-mode, passing in a type
of the text-object and some other parameters. Then, vim will set the bracket marks referencing the start and end of the text-object. The GetTextObject
function just simplifies this, pulled mostly directly from :help map-operator
, so operators can be made easily.
Then, for each operator there is a function for opfunc
to be set to, with the correct parameters, and they use feedkeys
to open up the command-mode with the correct text to define a substitute command, with the cursor placed correctly. Then the normal-mode mapping sets the opfunc
then activates it with g@
, while the visual-mode mapping opens the command-mode and clears the auto-inserted visual range using <C-u>
, then just calls it and tells it is being called from visual-mode.
One problem is that if there are any special characters (including newlines) or escape sequences recognized by the substitute command, then something may mess up, so I will expand on the answer soon to fix that.
(Also, it may not be neccessary to have gA
and gI
, if you don't mind using &
in a substitute command to reference the replaced text, so griw&_1<cr>
does the same as gAiw_1<cr>
).