Vim - How to make your own mapping repeatable? - vim

I have following mappings in my vimrc:
nmap <Leader>h1 yyp<c-v>$r=
nmap <Leader>h2 yyp<c-v>$r-
I'd like to repeat <Leader>h1/2 with .
There exist the repeat.vim plugin by Tim Pope with following usage line
silent! call repeat#set("\<Plug>MyWonderFulMap", v:count)
I tried using it in the following way:
nnoremap <silent> <Plug>MyWonderfulMap :normal yyp<c-v>$r=
silent! call repeat#set("\<Plug>MyWonderfulMap", v:count)
nmap <Leader>h1 <Plug>MyWonderfulMap
It does not work.
I know it is not a serious complication, however, I am interested to use the repeat.vim for own mappings.

The repeat#set() invocation must be done after the mapping invocation, not just once after the mapping definition. With :normal, you'd have to wrap this with :execute to be able to append the :call, but actually your mapping doesn't need to use :normal at all:
:nnoremap <silent> <Plug>MyWonderfulMap yyp<c-v>$r=:silent! call repeat#set("\<Plug>MyWonderfulMap", v:count)<CR>
:nmap <Leader>h1 <Plug>MyWonderfulMap

Related

How to avoid remap in vim

I have the following on my .vimrc
au FileType ruby nnoremap <expr> <leader>t ':!rspec ' . expand('%') . ':' . line('.')
This executes rspec on the line specified, and gives me option to edit the line before pressing enter. But I have to be on the test file so it get the file name and line number correctly.
While developing I run nnoremap <leader>t :!rspec some/spec/file.rb:123 manually to run the test I want from anywhere in the code. So I can code and fire the test without need to visit the test file.
The problem is that if I visit another ruby file the mapping in .vimrc runs again and I loose the nnoremap command I used before. Is there a command to only map (in normal mode) if there isn't already a map for that sequence?
Regards,
This should be a buffer-local mapping. Use <buffer>:
au FileType ruby nnoremap <buffer> <expr> <leader>t ':!rspec ' . expand('%') . ':' . line('.')
We can do better!
Use an augroup and make is self clearing to make it safe to re-:source.
augroup ruby_testing
autocmd!
autocmd FileType ruby nnoremap <buffer> <expr> <leader>t ':!rspec ' . expand('%') . ':' . line('.')
augroup END
Even better forgo the autocmd and put this mapping in the after directory. Add the following line to ~/.vim/after/ftplugin/ruby.vim:
nnoremap <buffer> <expr> <leader>t ':!rspec ' . expand('%') . ':' . line('.')
For more help see:
:h :map-local
:h :augroup
:h after-directory
Vim has the :help :map-<unique> modifier which makes the mapping fail if such mapping already exists.
au FileType ruby nnoremap <unique> <expr> <leader>t ...
You can suppress the error message with :silent!:
au FileType ruby silent! nnoremap <unique> <expr> <leader>t ...
Alternatively (and this is slightly better because it doesn't suppress any other errors in the mapping definition, like syntax errors), you could explicitly check for the mapping's existence via maparg():
au FileType ruby if empty(maparg('<leader>t', 'n')) | nnoremap <expr> <leader>t ... | endif
Note that this literally implements that (I understand) you're asking for; i.e. the first Ruby file will define the mapping, and any subsequent Ruby files are ignored; the mapping will always use the first file's name and line number. If you instead want to have different right-hand sides for the same mapping, depending on the currently edited file, the solution is a buffer-local mapping as per #PeterRincker's answer. But with that, you have to be inside the original Ruby buffer to trigger the correct mapping.
A remedy for that might be to recall the executed command-line from the command-line history (should happen automatically for your incomplete mapping, else via histadd()), so that you can easily recall the command from another file.

use specific search with no highlight

For example I'm in python code and want to jump between classes:
nnoremap <buffer> [c /^\s*class\ <CR>
How to prevent them from highlight in more elegant way than :nohl at the end of command each time?
You can avoid highlighting search matches by using the :help search() function or writing your own function.
With search()
nnoremap <buffer> <silent> [c :<C-u>call search('^\s*\zsclass\s')<CR>
With your own function
" with ':help :normal'
function! JumpToNextClass()
normal! /^\s*\zsclass\s
endfunction
" with ':help search()'
function! JumpToNextClass()
call search('^\s*\zsclass\s')
endfunction
nnoremap <buffer> <silent> [c :<C-u>call JumpToNextClass()<CR>
But none of that really matters since Vim already comes with ]] and [[.

How do I debug a non-functioning keymap in Vim?

I ask this question generally, but I will put it in terms of the specific problem I'm having.
I'm using the vim-lawrencium plugin for a project under Mercurial source control. I use the :Hgstatus command to open the status buffer.
The status buffer comes with some nice keymaps to make it easy to add files to the commit, look at diffs, and finalize the commit.
nnoremap <buffer> <silent> <cr> :Hgstatusedit<cr>
nnoremap <buffer> <silent> <C-N> :call search('^[MARC\!\?I ]\s.', 'We')<cr>
nnoremap <buffer> <silent> <C-P> :call search('^[MARC\!\?I ]\s.', 'Wbe')<cr>
nnoremap <buffer> <silent> <C-D> :Hgstatustabdiff<cr>
nnoremap <buffer> <silent> <C-V> :Hgstatusvdiff<cr>
nnoremap <buffer> <silent> <C-U> :Hgstatusdiffsum<cr>
nnoremap <buffer> <silent> <C-H> :Hgstatusvdiffsum<cr>
nnoremap <buffer> <silent> <C-A> :Hgstatusaddremove<cr>
nnoremap <buffer> <silent> <C-S> :Hgstatuscommit<cr>
nnoremap <buffer> <silent> <C-R> :Hgstatusrefresh<cr>
nnoremap <buffer> <silent> q :bdelete!<cr>
Most of these seem to work. I've successfully tried diffing, adding, and q to close the status, but the <C-S> shortcut doesn't work at all. I can manually run the :Hgstatuscommit command it's mapped to. I've also looked at :map to verify the key is actually mapped for that buffer, and it does show up in the list.
What is my next step in debugging this? I want to fix this specific problem, but I also want to know how to fix it in the event I run across broken shortcuts in the future. I'm new to Vim, so I'm at a bit of a loss at this point.
UPDATE: Output of :verbose map <C-S>
v <C-S> *#:Hgstatuscommit<CR>
Last set from ~/.spf13-vim-3/.vim/bundle/vim-lawrencium/plugin/lawrencium.vim
n <C-S> *#:Hgstatuscommit<CR>
Last set from ~/.spf13-vim-3/.vim/bundle/vim-lawrencium/plugin/lawrencium.vim
SOLUTION: Turned out the problem was that my shell was intercepting Ctrl-S and it was never getting to Vim.
I added a Vim alias to my .zshrc to fix:
alias vim="stty stop '' -ixoff ; vim"
ttyctl -f
Found the fix on the Vim Wikia which also has a solution for bash shells.
Software Flow Control
If you are using using a terminal then it is often the case that <c-s> is being used for terminal's software flow control (XON/XOFF). Which makes <c-s> a trickier key to map.
Turn off flow control by adding the following to some startup script (e.g. ~/.bash_profile or ~/.bashrc):
stty -ixon
If you have frozen your terminal then you can unfreeze it by pressing <c-q>.
Generic map debuging
You can debug pretty much any custom vim mapping via the following command:
:verbose map
This will list out each key/chord ({lhs}) maps to what command ({rhs}), mode, and file the mapping was sourced from. For more information on this listing see :h map-listing and :h :map-verbose.
We can filter this list in a few ways:
Supplying a mode. e.g. :verbose nmap for normal mode and :verbose imap for insert mode.
Proving the key we want to query for. e.g :verbose nmap <c-s>
Can also see buffer specific mappings by adding <buffer>. e.g. :verbose nmap <buffer> <c-s>
So for your question the best way to debug what your mapping is set to would be to run the following query:
:verbose nmap <buffer> <c-s>
Note: Vim's native command are not listed via :verbose map. The best way to find one of Vim's native commands is to help. See :h for more.
First, check that <C-S> still mapped to :Hgstatuscommit
map <C-S>
Hgstatuscommit calls s:HgStatus_Commit. Open its definition on line 1134 and put some debugging print outs:
echom a:linestart
echom a:lineend
echom a:bang
echom a:vertical
After using the mapping, check :messages.
I’d suspect that <C-S> is mapped to something else. You can use :map
<C-S> to check how (or if) its mapping is configured. Even better, you can
add the prefix to see where the mapping was set from, e.g., when I run
:verbose map <C-L>, the following is displayed:
<C-L> * :noh<CR><C-L>
Last set from ~/.vimrc
By contrast, I haven’t set a mapping for <C-S> so when I run, :map <C-S>,
I get:
No mapping found
Prepending verbose to a command is a useful general debugging technique as it can show where any Vim option was set, e.g., :verbose set background? shows what the background option is currently set to and which Vim configuration file it was set in:
background=dark
Last set from ~/.vimrc

vim : <silent> nmap

In vim I have this nmap
nmap <silent> ,mu : marks ABCDEFGHIJKLMNOPQRSTUVWXYZ<CR>
If I don´t have Upper marks and try ,mu I get
E283: No marks matching "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
why don't show the Error output ?
Try
nnoremap <silent> ,mu :execute "try\nmarks ABCDEFGHIJKLMNOPQRSTUVWXYZ\ncatch /\\V\\^Vim(marks):E283:/\nendtry"<CR>
By the way, is there a reason for writing :nmap instead of :nnoremap? You should not do this if you don't have a reason unless you want to run in the situation where you can't predict what will be the result of adding another mapping (directly to vimrc or by installing a plugin).
Edit (sehe)
To make things more readable, I'd suggest using a snippet like this in your $MYVIMRC:
function! ShowGlobalMarks()
try
marks ABCDEFGHIJKLMNOPQRSTUVWXYZ
catch /E283:/
endtry
endfu
nnoremap <silent> ,mu :call ShowGlobalMarks()<CR>

Unable to eliminate T in Vim's Taglist

I have the following code in .vimrc
" to eliminate the effect of the line 1560 in taglist.vim
if v:version >= 700
nnoremap <buffer> <silent> t
\
nnoremap <buffer> <silent> <C-t>
\
endif
The command does what it should do. However, the command gives also me the following error at Vim's startup
No mapping found
No mapping found
How can you eliminate the keyboard shortcut, such that you do not get the message in Taglist but you can still use the default "T" for browsing up in Dvorak?
Delete it. I don't use taglist, but the example you gave in your post does nothing.
It is supposed to map something to something, but the right side is missing, i.e. something is supposed to being mapped to "t" and "C-t", but that something isn't defined.
Or, you can do this:
:silent nnoremap <buffer> <silent> t (and analoguous for the second line)
(mapping stays but the message will not be displayed)

Resources