I had a look at the list of events autocmd can handle, but I could not find one about search queries.
What I would like to do is to add some custom behavior after each text search is performed. I was able to remap the * command with this command:
map * *<F11>
In this case I mapped <F11> to a :call My_function() which will do something with the search pattern contained in #/.
But I still need to add my custom behavior to the / command, which is more complicated, as before it's completed it's getting the input search pattern.
Do you have any hint on how to proceed? Can I use autocmd? Or maybe is there a map trick?
An (bad) way to do it would be to remap the return key (and the esc key)
when / is pressed, something like that:
function! MyCustomBehaviour()
echo "Oui oui"
endf
function! UnmapSearch()
cunmap <cr>
cunmap <esc>
endf
function! MapSearch()
cnoremap <cr> <cr>:call UnmapSearch()<bar>call MyCustomBehaviour()<cr>
cnoremap <silent> <esc> <c-c>:call UnmapSearch()<cr>
endf
noremap / :<c-u>call MapSearch()<cr>/
It's a bad way because it's quite buggy : if you press Ctrl-C while editing the
search, it won't unmap <cr> and <esc>, then the next time you will enter : (command-line) mode,
the mappings will still be active... That's a problem that can't be solved (<c-c> can't be
remapped).
It's also a bad way because remapping directly the / key this way, IMO, is not a good practice.
But... This was the only solution I found some times ago to half-solve this problem.
Another workaround (the one I finally choose) can be written in one line :
cnoremap <c-cr> <cr>:call MyCustomBehaviour()<cr>
Related
I'm using a plugin that performs multiple *noremap operations in its initialization. After I added the following mapping to YCM/UltiSnips:
inoremap <expr> <CR> pumvisible() ? "<C-R>=<SID>ExpandSnippetOrReturn()<CR>" : "\<CR>"
I've broken the other plugin's ability to see the <Enter> key, or rather I overrode/destroyed the original inoremap. I want to reenable that functionality, but without disabling ability to pick snippets from the auto-complete menu using Enter key. This keymap is effectively saying "if the menu is visible, select the option, otherwise simulate <Enter> key". What I need it to say instead is "if the menu is visible, select the option, otherwise perform whatever command <Enter> key is already mapped to". So basically, at the time of declaration of this inoremap, I need to expand existing inoremap for this key into the else.
I've looked at <C-R>=feedkeys('<CR>')<CR> and <C-R>=mapcheck('\<CR>', 'i')<CR> but couldn't get either to work. Can someone help me out?
Finally figured it out... this was way more vim troubleshooting than I needed for one day.
function! LoadPumvisibleEnter()
let smartmap = maparg("<Enter>", "i")
execute printf('inoremap <script> <expr> <CR> pumvisible() ? "<C-R>=<SID>ExpandSnippetOrReturn()<CR>" : %s', smartmap)
endfunction
au VimEnter * :execute LoadPumvisibleEnter()
throwing it in a function allowed me to stay sane with escapes and which mode I was in
autocommand is needed because vim apparently runs vimrc BEFORE loading any plugins (Does Vim load plugins after loading vimrc?), so without it the map will not yet be set
I am a happy VIM user, although I admit I'm quite far from being fluent. I found this nice post:
Vim clear last search highlighting and I thought I'd become a better person if I didn't have to hammer away a random character sequence every time I did a search. Now, I'm also using the vimrc config from here:
http://amix.dk/vim/vimrc.html
and the problem I have is that when I add the line nnoremap <esc> :noh<return><esc> to it (it doesn't seem to make a difference where I put it) I get awkward behaviour when I use arrows in command mode, namely letters from A to D appear in a newline and I get switched to insert mode.
There has to be some mapping conflict but for the life of me I can't figure out where it is.
EDIT: As it follows from the answers it turns out the Ultimate vimrc part is not relevant, the mentioned nnoremap command will cause altered arrow behaviour even if it's the only vimrc entry. Changing title to a more informative one.
PS. I know I shouldn't use arrows, hopefully I'll get there one day.
The mapping
nnoremap <esc> :noh<return><esc>
will conflict with so called "grey keys" and I believe that it should be used either in GVim only or in terminal Vim by someone who does not use special keys like arrows.
From what I know (and guess) how Vim processes keys, I would say that it's impossible to do anything with this. For Vim to recognize special key all its components should go in a row, so when you press Arrow Left Vim gets the following sequence of codes:
<esc> [ D
But after your mapping Arrow Left becomes:
: n o h l <cr> <esc>
[ D
Vim sees two separate sequences and treats <esc> as a single press of Escape key, thus next two codes of Left Arrow key lose their special meaning.
So I suggest you to map :noh to some other key sequence (e.g. to one starting with <leader>, see :help mapleader; I don't recommend you to use F-keys, using them is as bad as using of arrow keys).
The cause had been explained well, but solution was not mentioned. However there is a straight one.
If you’ll tell to Vim explicitly that there are key sequences starting from <esc>[
:nnoremap <silent><esc> :noh<CR>
:nnoremap <esc>[ <esc>[
than when single <esc> will be pressed Vim will wait for a second (or different time, see :h 'timeoutlen') or for a next key (second <esc> for example) and only then replace it with :noh<CR>.
This solution preserves the ESC mapping to :nohlsearch.
The comment on this answer explaining why this is happening tells us that the root cause is the TermResponse behavior of vim. This can be compensated for by wrapping the mapping in an autocommand for the TermResponse event.
This ensures that the binding doesn't happen until after the term response is set, which prevents Esc from also sending a string like ]>1;3201;0c to vim.
Change your line in vimrc to this:
augroup no_highlight
autocmd TermResponse * nnoremap <esc> :noh<return><esc>
augroup END
The augroup commands are not strictly necessary, but they prevent multiple mappings when you reload your vimrc without quitting vim.
EDIT: If you also use a graphical vim like Gvim or Macvim, the TermResponse event will not fire. Assuming you use a single vimrc, you'll need some additional code like
if has('gui_running')
nnoremap <silent> <esc> :nohlsearch<return><esc>
else
" code from above
augroup no_highlight
autocmd TermResponse * nnoremap <esc> :noh<return><esc>
augroup END
end
Problem is that when you press an arrow terminal emits something like <Esc>OA. Vim part that supports terminal seems to use the same mapping mechanism to do the job as you are using: while nmap <Esc>OA will tell you nothing, call feedkeys("\eOA") will move one line up and call feedkeys("\eOA", 'n') will add letter A beyond current line. With your mapping being noremappable you forbid vim to use <Esc> as a part of the key. The problem is that you need remappable mapping here, but can have remappable mapping without it being recursive as well only if it starts with {lhs}, but <Esc>:noh<CR>OA is not going to work. I thought the following code will (it uses <expr> and function with side effect to make <Esc> be the first character of the actual {rhs} and still launch :noh), but in fact it does not:
function s:NoHlSearch()
nohlsearch
return "\e"
endfunction
nmap <expr> <Esc> <SID>NoHlSearch()
. I have no other idea how to solve the problem of having non-recursive remappable mapping which includes {lhs} but not at the start.
I have had good luck with this
if $TERM =~ 'xterm'
set noek
endif
nnoremap <silent> <esc> <esc>:noh<cr>
The disadvantage is that function keys can not be used in insert mode.
:h ek
I use mappings to normal mode commands that I'd also like to work in insert mode. This can be done by adding <C-o> to insert mode mapping:
nmap <C-Up> 10<Up>
imap <C-Up> <C-o>10<Up>
But this means repeating each mapping twice.
To avoid repetition, I've tried to "overload" some other key, then use it for mode-specific part:
" F12 selects prefix suitable for current mode
nmap <F12> <Nop>
imap <F12> <C-o>
" single mapping relying on "overloaded" F12
map <C-Up> <F12>10<Up>
For some reason, it doesn't work. F2 in insert mode just inserts <F2> as text.
Any idea what's wrong and how to fix it?
Bonus points if you can extend the solution to visual mode.
As ZyX has already pointed out, there is no single :map command for all modes, because it mostly doesn't make sense. If you really want to define a mapping for all modes, use both :map and :map!; see :help map-modes.
As you typically define mappings only once in your .vimrc, I would not worry too much about the little duplication, but if you do, you can use a wrapper function to avoid this:
function! MapBoth(keys, rhs)
execute 'nmap' a:keys a:rhs
execute 'imap' a:keys '<C-o>' . a:rhs
endfunction
call MapBoth('<C-Up>', '10<Up>')
Original
nnoremap <F2> :w<CR>
inoremap <F2> <Esc>:w<CR>a
map sometimes does not set it for all modes. I don't know the exact reason, so to be sure I like to explicitly set all mapping in my configuration file. I suggest that you do the same as there are cases where you can get something unexpected due to different modes. That's why it is important to consider every remapping that you do for each particular mode with care.
In addition, favor *noremap command instead of just *map everywhere you can as recursive mapping is a known source of errors, especially for beginners.
Lastly, I don't know what are you trying to achieve by binding writing of a file in visual mode. Are you aiming for partial buffer writing (it's when you selected something in visual mode, then hit this file-writing shortcut and only selected text is written)? Or do you want the whole file to be written when you are in visual mode, regardless of whether you selected anything or not when you hit the file-writing shortcut? Provide more information on that. Personally, in either case it is weird mapping for visual mode, as it is really not indented for that. It's rather better to keep such stuff in normal mode.
Update
As others have already given exhaustive answers on your question, I just thought that it would be helpful if add my 2 cents, but in slightly different direction. By looking on what you are trying to do, namely mapping navigation features involving arrow keys in insert mode, I can infer that you are very new to Vim. As you probably already know, the philosophy behind Vim is that you should never ever touch mouse during your work inside Vim - call it a kind of golden rule.
What I want to point out now, is what I call a silver rule, and it basically looks like this:
noremap <Up> <Nop>
noremap <Down> <Nop>
noremap <Left> <Nop>
noremap <Right> <Nop>
inoremap <Up> <Nop>
inoremap <Down> <Nop>
inoremap <Left> <Nop>
inoremap <Right> <Nop>
In other words, prevent yourself from using arrow keys (everywhere except command-line mode). Your fingers should always be only in the region of character keys. Vim is all about modes. Insert mode is not for navigation - it is intended for bursts of typing. When you work with code or just text (doesn't matter) you spend most of your time in normal mode - navigating - looking through the file, seeking where to land next in order to edit something, add something, i.e. to do your next input burst for which you switch to insert mode, and when you are finished you switch back to normal mode to look for some more meat - like a predator. :)
So what is it all about? I just want to head you to the right direction right from the beginning. This way you can become intermediate Vim user very quickly - just a few days. In order to get better feeling of all the aforementioned I suggest that you should definitely watch Vim Novice Video Tutorials by Derek Wyatt where he talks about all that stuff in more detail and shows it in action in the screencasts. There are also Intermediate and Advanced tutorials by him which you might also look when you are comfortable with the basics.
I wish you happy vimming! :)
There are no commands to define mappings for all modes: :map maps for normal, operator-pending and visual modes (really visual and select at once) which is clearly stated in documentation. It does not make any sense to have same mapping for all modes, though unlike movement ones saving may be done in all modes with exactly the same rhs:
function s:Save()
update
return ''
endfunction
noremap <expr> <F2> <SID>Save()
noremap! <expr> <F2> <SID>Save()
. noremap! is another multi-mode mapping command, it covers insert and command mode now. You can’t move the cursor from <SID>Save() function (textlock) thus this method is not applicable for cursor movement commands, but you can use variables in order not to repeat the same thing twice:
let s:tendownlhs='10j'
execute ' noremap <C-Down> '.s:tendownlhs
execute 'inoremap <C-Down> <C-o>'.s:tendownlhs
. Now without command mode as this is tricky and likely useless.
If it is okay for the mapping to end up in normal mode, you could combine a for loop with <C-\><C-n> mappings. <C-\><C-n> switches from any mode to normal mode.
For example, this allows switching panes with Alt-{h,j,k,l} from any mode:
for map_command in ['noremap', 'noremap!', 'tnoremap']
execute map_command . ' <silent> <M-h> <C-\><C-n><C-w>h'
execute map_command . ' <silent> <M-j> <C-\><C-n><C-w>j'
execute map_command . ' <silent> <M-k> <C-\><C-n><C-w>k'
execute map_command . ' <silent> <M-l> <C-\><C-n><C-w>l'
endfor
noremap maps in Normal, Visual, and Operator-pending mode
noremap! maps in Insert and Command mode
tnoremap maps in Neovim's Terminal mode
I am a happy VIM user, although I admit I'm quite far from being fluent. I found this nice post:
Vim clear last search highlighting and I thought I'd become a better person if I didn't have to hammer away a random character sequence every time I did a search. Now, I'm also using the vimrc config from here:
http://amix.dk/vim/vimrc.html
and the problem I have is that when I add the line nnoremap <esc> :noh<return><esc> to it (it doesn't seem to make a difference where I put it) I get awkward behaviour when I use arrows in command mode, namely letters from A to D appear in a newline and I get switched to insert mode.
There has to be some mapping conflict but for the life of me I can't figure out where it is.
EDIT: As it follows from the answers it turns out the Ultimate vimrc part is not relevant, the mentioned nnoremap command will cause altered arrow behaviour even if it's the only vimrc entry. Changing title to a more informative one.
PS. I know I shouldn't use arrows, hopefully I'll get there one day.
The mapping
nnoremap <esc> :noh<return><esc>
will conflict with so called "grey keys" and I believe that it should be used either in GVim only or in terminal Vim by someone who does not use special keys like arrows.
From what I know (and guess) how Vim processes keys, I would say that it's impossible to do anything with this. For Vim to recognize special key all its components should go in a row, so when you press Arrow Left Vim gets the following sequence of codes:
<esc> [ D
But after your mapping Arrow Left becomes:
: n o h l <cr> <esc>
[ D
Vim sees two separate sequences and treats <esc> as a single press of Escape key, thus next two codes of Left Arrow key lose their special meaning.
So I suggest you to map :noh to some other key sequence (e.g. to one starting with <leader>, see :help mapleader; I don't recommend you to use F-keys, using them is as bad as using of arrow keys).
The cause had been explained well, but solution was not mentioned. However there is a straight one.
If you’ll tell to Vim explicitly that there are key sequences starting from <esc>[
:nnoremap <silent><esc> :noh<CR>
:nnoremap <esc>[ <esc>[
than when single <esc> will be pressed Vim will wait for a second (or different time, see :h 'timeoutlen') or for a next key (second <esc> for example) and only then replace it with :noh<CR>.
This solution preserves the ESC mapping to :nohlsearch.
The comment on this answer explaining why this is happening tells us that the root cause is the TermResponse behavior of vim. This can be compensated for by wrapping the mapping in an autocommand for the TermResponse event.
This ensures that the binding doesn't happen until after the term response is set, which prevents Esc from also sending a string like ]>1;3201;0c to vim.
Change your line in vimrc to this:
augroup no_highlight
autocmd TermResponse * nnoremap <esc> :noh<return><esc>
augroup END
The augroup commands are not strictly necessary, but they prevent multiple mappings when you reload your vimrc without quitting vim.
EDIT: If you also use a graphical vim like Gvim or Macvim, the TermResponse event will not fire. Assuming you use a single vimrc, you'll need some additional code like
if has('gui_running')
nnoremap <silent> <esc> :nohlsearch<return><esc>
else
" code from above
augroup no_highlight
autocmd TermResponse * nnoremap <esc> :noh<return><esc>
augroup END
end
Problem is that when you press an arrow terminal emits something like <Esc>OA. Vim part that supports terminal seems to use the same mapping mechanism to do the job as you are using: while nmap <Esc>OA will tell you nothing, call feedkeys("\eOA") will move one line up and call feedkeys("\eOA", 'n') will add letter A beyond current line. With your mapping being noremappable you forbid vim to use <Esc> as a part of the key. The problem is that you need remappable mapping here, but can have remappable mapping without it being recursive as well only if it starts with {lhs}, but <Esc>:noh<CR>OA is not going to work. I thought the following code will (it uses <expr> and function with side effect to make <Esc> be the first character of the actual {rhs} and still launch :noh), but in fact it does not:
function s:NoHlSearch()
nohlsearch
return "\e"
endfunction
nmap <expr> <Esc> <SID>NoHlSearch()
. I have no other idea how to solve the problem of having non-recursive remappable mapping which includes {lhs} but not at the start.
I have had good luck with this
if $TERM =~ 'xterm'
set noek
endif
nnoremap <silent> <esc> <esc>:noh<cr>
The disadvantage is that function keys can not be used in insert mode.
:h ek
I have these insert mode mappings in my .vimrc file:
imap <C-e> <C-o>A
imap <C-a> <C-o>I
They make Ctrl-A and Ctrl-E move the cursor to the start and end of the line without leaving insert mode, a la emacs keybindings.
However, I just realized that the Ctrl-E mapping introduces a conflict with the autocompletion submode. The documentation in :help complete_CTRL-E states:
When completion is active, you can use CTRL-E to stop it and go back to the originally typed text.
Thus, my Ctrl-E mapping interferes with this. Is there a way that I can make Ctrl-E jump to the end of the line only if auto-completion is not active?
There is no proper way to test whether the
Ctrl+X-completion mode is active or not.
However, the following two workarounds are possible.
1. If one uses the popup menu to choose from the list of available
completions (especially in the case of menuone set in the completeopt
option), an acceptable solution might be the mapping
inoremap <expr> <c-e> pumvisible() ? "\<c-e>" : "\<c-o>A"
2. A general solution can be based on a side effect: In the
completion submode, it is disallowed to enter Insert mode recursively
(see :helpgrep Note: While completion), so if an attempt to do so
fails, we can suppose that we are in the midst of a completion:
inoremap <c-e> <c-r>=InsCtrlE()<cr>
function! InsCtrlE()
try
norm! i
return "\<c-o>A"
catch
return "\<c-e>"
endtry
endfunction