How to map vim visual mode to replace my selected text parts?

2.9k views Asked by At

I wish to replace part of my words, as selected by visual mode. E.g.:

I've got a simple text file:

------------------
hello there hehe
She's not here
------------------

I need to change all "he" into "her".

What I wish to do is not to type %s command, but under visual mode:

  1. v to select "he"
  2. Press some hot key, and vim prompts me to input the new text
  3. I type the new text, press Enter, done.

I guess we can do it with vmap? But how to achieve it? Thanks!

5

There are 5 answers

2
Meninx - メネンックス On BEST ANSWER

To get the solution all credits go to User @xolox from his answer which I developed to get the required task:

vnoremap ; :call Get_visual_selection()<cr>


function! Get_visual_selection()
  " Why is this not a built-in Vim script function?!
  let [lnum1, col1] = getpos("'<")[1:2]
  let [lnum2, col2] = getpos("'>")[1:2]
  let lines = getline(lnum1, lnum2)
  let lines[-1] = lines[-1][: col2 - (&selection == 'inclusive' ? 1 : 2)] 
  let lines[0] = lines[0][col1 - 1:] 
  let selection = join(lines,'\n')
  let change = input('Change the selection with: ')
  execute ":%s/".selection."/".change."/g"
endfunction

You can change the mapping ; to any hot key you want.

enter image description here

0
Kent On

You can add this mapping:

vnoremap <F7> :s/he/&r/g<cr>

Then when you press <F7> in visual mode, vim will do the text substitution on selected lines.

Note that, the :s cmd in above mapping is just example, it replaces all he into her, no matter if he is a part of other word, E.g. She's -> Sher's

2
Ingo Karkat On

I think you're looking for something like this:

:vnoremap <F7> y:%s/<C-r><C-r>"//g<Left><Left>

This yanks the selected text, and then builds an (incomplete, with the cursor inside the replacement part) :%s command-line. You just need to fill in the replacement and press Enter.

Open issues

  • Clobbers the default register. You can use the function from @Meninx's answer, or ingo#selection#Get() from my ingo-library plugin.
  • Uses the selected text as a regular expression pattern. To use as literal text, this needs escaping (also for any newlines in a multi-line selection). Again, I have a ingo#regexp#EscapeLiteralText() in my plugin.
0
Andrew Radev On

I see you've already picked an answer that works for you, just wanted to also leave this plugin here: https://github.com/AndrewRadev/multichange.vim.

It does basically the same thing. Works on just words by default, allows you to select text to change in visual mode as well. It also has some some additional features, like printing how many substitutions were made off-screen.

0
Alexander van Trijffel On

Here is a key binding for a combination of the leader key and the s key to achieve what you want.

With lua:

vim.keymap.set("x", "<leader>s", '"zy<Esc>:%s/<C-R>z//g<Left><Left>')

The same in Vimscript:

xnoremap <leader>s '"zy<Esc>:%s/<C-R>z//g<Left><Left>

This yanks the selection to the z registser, escapes visual mode and prepares a substitute command with the selection as the text to be substituted.

Use the following command to set your leader key, in this example to the space key:

With lua:

vim.g.mapleader = " "

With Vimscript:

let mapleader = " "