12

I'm trying to understand how can I use operator with subsequent motion inside a mapping. For example:

nmap /c c{here we pending for a motion}/<C-r>"<CR>

The map should do the following:

  1. Activate c operator and listen for the next motion;
  2. Eg, I can type here t, to change everything before the next comma;
  3. Go to insert mode deleting everything between cursor and the comma;
  4. Deleted text is automatically searched as a pattern

So to put it simple, after motion text is removed, I'm leaved in insert mode with highlighted occurrences of the deleted text. I would be very grateful if somebody help me to puzzle out this case.

UPDATE

The answers are almost what I want. But! When I press /cw, type something instead of the word, then press <Esc>. After I expect to do the same with the next occurrences. But after presing n (go to next occurrence) and . (repeat last command) it just prepend last typed text instead of replacing it. The main goal of the mapping is using it with n/N and . to repeat. Have I missed something?

9

vim supports operator-mapping :h map-operator.

What you need is an operatorfunc, and a mapping. for your needs, the followings codes work. Well it is just an example, you refine further.

nmap  <silent> /c :set opfunc=SpecialChange<CR>g@
function! SpecialChange(type)
    silent exec 'normal! `[v`]d'    
    silent exec 'let @/=@"' 
    startinsert
endfunction

Note that exec 'let @/=@"' just for highlighting the codes in buffer. If you don't want to see the highlighting immediately, you can just let @/=@"

  • I've update my question. It seems your answer is the closest one to my needs, but it doesn't do the same with the next occurrence, so I've explained that moment in the question. – Timur Fayzrakhmanov Nov 16 '15 at 15:19
  • You have two operators (the /c and i) vim's . just repeats the last one. If you want to extend it, check repeat plugin. @TimurFayzrakhmanov also there are :g and :s commands, may help you too. – Kent Nov 16 '15 at 15:20
  • Is there odd " in your code 'let @/=@""'? I thought it is possible, for example silent exec 'normal! [v]c', because c operator do what I expect, except it doesn't add the changed text to the search pattern. – Timur Fayzrakhmanov Nov 16 '15 at 15:32
  • 1
    @TimurFayzrakhmanov the "" was a typo.. fix.. I came up with c too, however it added a space, because there is mode change n-i-n-i I guess... do some test you will see. – Kent Nov 16 '15 at 15:34
  • @TimurFayzrakhmanov you can make it repeatable without any plugin by changing d to y and startinsert to call feedkeys("cgn", 'n') (see my answer below) – Jerome Dalbert Jul 9 '16 at 10:26
4

It is easier to implement (and to document) complex mappings by using functions:

function! DoMagic()
   execute "normal! d".input("enter motion: ")
   let @/=@"
   startinsert
endfunction

Then make your mapping call that function:

nmap /c :call DoMagic()<CR>

Edit:

If your intention is to perform search & replace in a large number of places you should try the substitute command: :s. You could change your mapping to copy the visual selection to the search pattern:

function! DoMagic2()
   normal! gv"ay
   return @a
endfunction

vmap /c :<c-w>%s/<C-r>=DoMagic2()<CR>//gc<left><left><left>
  • 1
    this is even with a "nice" UI, works for OP's need, and can be "more" than expected, depends on what you input. E.g. when one see enter motion:, he gave: t,ggVGJZZ ^_^ It is a common problem for command concatenation – Kent Nov 16 '15 at 15:09
  • That is almost what I want. Eg: I press /cw then type something instead of the word, then press <Esc>. After I want to do the same with next occurrences. But after presing n (go to next occurrence) and . (repeat last command) it just prepend last typed text instead of replacing it. The main goal of the mapping is using it with n/N and . to repeat. Have I missed something? – Timur Fayzrakhmanov Nov 16 '15 at 15:13
  • 1
    This function is to clarify the idea of using functions when you have trouble with complex mappings. You should change it to meet your needs; try following Kent's advice to make the . repeat your command. – mMontu Nov 16 '15 at 15:22
  • Thank you for the answer. It's useful too, but I accept the @Kent 's one, because it do motion immediately after I type them (without pending <CR> from input()). – Timur Fayzrakhmanov Nov 16 '15 at 15:41
  • 1
    @TimurFayzrakhmanov you could also try the substitute, as explained in the update. – mMontu Nov 16 '15 at 15:42
1

This solution works with "repeat last command" (aka .):

nmap <silent> /c :set opfunc=ChangeOccurence<CR>g@

function! ChangeOccurence(type)
  exec 'normal! `[v`]y'
  let @/ = @"
  call feedkeys('cgn', 'n')
endfunction

When repeating, you don't even need to use n, you can just use . to directly fetch and replace the next occurence if you want to go faster.

Optionally, if you like having highlights of the matching words, you can replace 'cgn' by 'n``cgn'.

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.