2

Is there a simple way of taking a previously issued command and converting it into a .vimrc-friendly keybinding?

For example, I have a simple substitution utilizing regular expressions that won't work when remapped:

# find all lines containing only a comment char: "#" "," ";"
# and replace with that char and --- ie: #---

:%s/^\(#\|\"\|;\)$/\1---/g<CR>

This works great if manually typed in.

After attempting to convert it to a binding (not a let @x persistent macro), it doesn't work:

nnoremap <silent> <leader>tb :%s/^\(#\|\"\|;\)$/\1---/g<CR><CR>

I've read you need to convert the | to <Bar> I believe it was, but that had zero affect.

Is there a vim-plugin or built-in feature that would allow me to convert anything in history to a keybind without manipulation?

0

1 Answer 1

3
# find all lines containing only a comment char: "#" "," ";"
# and replace with that char and --- ie: #---

:%s/^\(#\|"\|;\)$/\1---/g

The comment says the command should replace these characters:

  • #
  • ,
  • ;

But the next command replaces these characters:

  • #
  • "
  • ;

Which one tells the truth?


After attempting to convert it to a binding (not a let @x persistent macro), it doesn't work:

nnoremap <silent> <leader>tb " :%s/^\(#\|"\|;\)$/\1---/g<CR>

Why is there an orphan double quote between the lhs and rhs of the mapping?

nnoremap <silent> <leader>tb " :%s/^\(#\|"\|;\)$/\1---/g<CR>
                             ^
                             ?

I've read you need to convert the | to I believe it was, but that had zero affect.

This seems to work:

nnoremap <silent> <leader>tb :%s/^\(#\<bar>"\<bar>;\)$/\1---/g<CR>

Tip: after installing a mapping, ask Vim to print how it was installed in the mappings table:

:nno <leader>tb

If the result does not contain the exact sequence of keys you want to be executed, adapt the rhs accordingly.


Is there a vim-plugin or built-in feature that would allow me to convert anything in history to a keybind without manipulation??

Move the rhs of the mapping in a function. The function call will still be subject to the usual mapping parsing, but whatever the function does in its body escape that parsing:

nnoremap <silent> <leader>tb :call Func()<cr>

fu Func()
    %s/^\(#\|"\|;\)$/\1---/g
endfu

BTW, this regex:

^\(#\|"\|;\)$

Can be simplified using a bracket expression:

^[#";]$

Also, if you have the patch 8.2.1978, use the pseudo-key <cmd> to execute an Ex command:

nnoremap <leader>tb <cmd>call Func()<cr>
                    ^---^

It reduces side-effects (no Cmdline* events, no display on the command-line so no need of <silent>, ...).

If you can't use <cmd>, then add <c-u> to kill a possible range inserted in front of :call if you hit a count by accident (see :h c^u):

nnoremap <silent> <leader>tb :<c-u>call Func()<cr>
                              ^---^
5
  • Ah! We got <cmd>! Now to remind myself why we needed it and what I need to go editing in my vim files to use it ...
    – D. Ben Knoble
    Commented Jan 24, 2021 at 14:34
  • Yes, that was a major change. The credit goes to Yegappan Lakshmanan for porting the feature to Vim. There are 3 benefits: 1. it does not trigger the Cmdline* events; 2. it makes <silent> no longer necessary; 3. it makes <c-u> no longer necessary.
    – user938271
    Commented Jan 24, 2021 at 14:54
  • 1
    There are 2 gotchas: <cmd> does not make you quit visual mode, so the marks '< and '> are not set. If your visual mapping refers to these marks, you need to make it press <Esc> first; otherwise, you have to play with line('v') and line('.'). And special keys are not allowed between <cmd> and <cr>; things like <F1>, <Up>, <Plug>(foo). If you really need them (e.g. inside a feedkeys() call), you need to delay their processing via <lt>: <F1> = "bad", <lt>F1> = "good".
    – user938271
    Commented Jan 24, 2021 at 14:54
  • Thanks! That’s helpful to know
    – D. Ben Knoble
    Commented Jan 24, 2021 at 15:08
  • Thank you for the A+ response. The poor formatting in my question was due to attempted troubleshooting and giving up in frustration to ask a superior for help. I also removed unnecessary text from the original to simplify my question, which inevitably made things worse. You nailed it though :). Super helpful.
    – bmilcs
    Commented Jan 25, 2021 at 18:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.