Vim: Why does noremap not work in insert mode? - keyboard

Consider the unbinding of the arrow keys using
noremap <Left> <NOP>
noremap <Right> <NOP>
noremap <Up> <NOP>
noremap <Down> <NOP>
This works in normal mode, but it does not work in insert mode: one can still navigate with the arrow keys. As a countermeasure, one must include
inoremap <Left> <NOP>
inoremap <Right> <NOP>
inoremap <Up> <NOP>
inoremap <Down> <NOP>
But this doesn't really make sense to me, since I assume map and noremap should work in all modes, while prepending n/v/x/s/o/i/l/c specifies the mapping to work only within that specific mode. Is there a reason for this?

why there isn't an all-inclusive modal map, rather than issuing both map and map!
That's easy to explain: In insert mode mappings, Vim doesn't automatically switch to normal mode (you may want to stay in insert mode, though text translations are typically done via :iabb, not via :imap), so the set of applicable commands is totally different. For example, in normal mode Ctrl-U scrolls upwards, but in insert mode it deletes the entered characters in the line!
Prefixes like <C-O> temporarily switch from insert mode to normal mode. Actually, one often even has to define a different prefix for command line mode, too, as shown by this example:
noremap <C-Tab> :<C-U>tabnext<CR>
inoremap <C-Tab> <C-O>:tabnext<CR>
cnoremap <C-Tab> <C-C>:tabnext<CR>
So when defining mappings, always consider in which modes they are needed and whether they need remapping (:nmap vs. :noremap, prefer the latter).

:help map-overview
map (and noremap) are for normal, visual, select and operator-pending modes.

Contrary to what you might expect, noremap and map do not actually apply to all modes. Based on the very useful summary from :help map-listing, here is a list of the characters that can be prefixed (or suffixed in the case of !) to map, noremap, unmap, and mapclear, along with the modes that they apply to:
(none) – Normal, Visual, Select, and Operator-pending
n – Normal
v – Visual and Select
x – Visual
s – Select
o – Operator-pending
! – Insert and Command-line
i – Insert
c – Command-line
l – ":lmap" mappings for Insert, Command-line, and Lang-Arg
So a noremap mapping will have no effect in Insert or Command-line mode, and without consideration, may not work as intended in Visual, Select, or Operator-pending mode either.
However, mappings can be adapted to work in different modes, simply by changing mode and back in the mapping. For example, noremap mappings that issue command-line commands but only work in Normal mode can adapted to also work in the other modes as shown by this example:
noremap <C-Tab> :<C-U>set list!<CR>
inoremap <C-Tab> <C-O>:set list!<CR>
cnoremap <C-Tab> <C-C>:set list!<CR>:<Up>
noremap applies to the Normal, Visual, Select, and Operator-pending modes, for which :<C-U> enters Command-line mode then clears the current line in case Vim inserts a range; inoremap applies to Insert mode, for which <C-O>: temporarily exits to Normal mode then enters Command-line mode; and cnoremap applies to Command-line mode, for which <C-C>: exits and re-enters Command-line mode to clear the line but, unlike <C-U>, retain it in the command history so that :<Up> can bring it back.
These three mappings cover all six modes. (Apparently ‘Lang-Arg’ isn't a mode.) There are some corner-cases where it doesn't work, but then there are also some cases it works when I'd have thought it wouldn't, and I don't understand why. Also, most of the modes will loose little things like selections and pending operators, even if the mapped command wouldn't otherwise loose these things. For instance, when in Insert mode, I don't see why the example I've given would need to break the current edit into separate changes in the undo/redo history (try typing i123<C-O><Esc>456<Esc>u). To be honest using key mappings to run commands in this way seems like a bit of a hack to me, but I don't know another way.

Related

Vim: Remap Ctrl-W in insert mode to behave as it does in normal mode

I would like Ctrl-W to allow me to switch windows even when I am in insert mode. How can I make this change?
My motivation is to not need to press escape before shifting windows.
For <c-w><c-j> (as an example), you can do:
inoremap <c-w><c-j> <esc><c-w><c-j>gi
Then you can repeat this kind of mapping for every command you use:
inoremap <c-w><c-k> <esc><c-w><c-k>gi
inoremap <c-w><c-w> <esc><c-w><c-w>gi
inoremap <c-w>+ <esc><c-w>+gi
inoremap <c-w>- <esc><c-w>-gi
...
If you choose this simple solution, then you can finally add this mapping to inhibit the native <c-w> key (= delete the last word):
inoremap <c-w> <nop>
More "smart" solutions could be written, but they would imply a bit more code.
Note 1: as noted in the comments, the mappings to choose depend on which mode you want to reach after the keystroke: the suffix gi in the commands above means that you want to go back to insert mode in the new window; but you can remove this suffix if you want to be in normal mode.
Note 2: the suffix gi could be simply i, depending on the case : see :h i and :h gi

Tab Navigation mapping is not working

NOTE: I am using Terminator instead of terminal. But as all other mappings are working fine why does these are not working.
I have tried to use these mappings in my vimrc file to be able to use Tab Navigation. But its not working at all.
nnoremap <C-S-tab> :tabprevious<CR>
"nnoremap <C-tab> :tabnext<CR>
nnoremap <C-tab> :tabn<CR> "I also tried this
nnoremap <C-t> :tabnew<CR>
inoremap <C-S-tab> <Esc>:tabprevious<CR>i
inoremap <C-tab> <Esc>:tabnext<CR>i
inoremap <C-t> <Esc>:tabnew<CR>
inoremap <C-S-w> <Esc>:tabclose<CR>
"Also to go to the nth tabpage Use <A-Fn>
nnoremap <A-F1> 1gt
nnoremap <A-F2> 2gt
nnoremap <A-F3> 3gt
nnoremap <A-F4> 4gt
nnoremap <A-F5> 5gt
nnoremap <A-F6> 6gt
nnoremap <A-F7> 7gt
nnoremap <A-F8> 8gt
nnoremap <A-F9> 9gt
nnoremap <A-F10> 10gt
NOTE: I have ctags and cscope installed. So I think there might be some confliction as ctrl-t is to jump back from a certain tag. And only this mapping is working for new tab.
Also I have checked ctrl-PageDown is working fine for the same purpose.
2nd Question:
How does this key notation works in vimrc.
Is it something like this:
All modifier keys should be used in Caps like
C for Ctrl.
A for Alt.
S for Shift.
And other keys are all in small.
But what about keys like:
Home
End
Backspace
Escape
PageUp
PageDown
Tab
Function keys etc.
How to use them?
Here
I read that how these should be used in mapping but even they have used tab instead of Tab in mappings.
Brace yourself for disappointment.
The terminal keycodes
Vim accepts terminal keycodes, so not all key combinations are possible. The best way to figure out which keys are recognizable is to open insert mode and press ctrl+v followed by your key combination. This will show you the raw codes. Do this for another key combination. If the raw codes are the same then Vim can not distinguish between them. e.g. ctrl+v ctrl+shift+tab.
Your mappings
You should probably avoid doing insert mode mappings to switch tabs. It simply isn't the Vim Way as insert mode should only be used in short bursts.
Your :tabprev and :tabnext mappings can simplified into gT and gt mappings. Personally I do not mind the default gt or gT mappings.
<key> notation
As far as I know the case does not matter. All my mappings are lowercase. For a list of <> notation please see :h key-notation.
You are correct on the <c-..> for control, <a-...> for alt, and <s-...> for shift. Example combination would be <c-s-space>. Note: most <c-s-...> mappings are going to fail.
Using Tabs
Vim's tabs are not like most text editors tab. They are more like viewports into a group of windows/splits. Additionally, Vim is buffer centric, not tab centric like most editors. For example using features like Vim's quickfix list is often easier without tabs (See :h 'switchbuf if you must use tabs). Vim's tabs often get in the way of using a splits as there are better window and buffer navigation commands available. I personally have many files open (sometimes 100+) using no tabs and use on average 1-2 splits without any issue.
Bottom line: Learn to use buffers effectively.
Conclusion
I would suggest you break this tab workflow quickly and learn to love buffers. You won't really need your mappings and you will not be working against Vim's nature.
Read :help key-notation for an explanation of… Vim's key notation.
It is generally a good idea to play it safe so I recommend to follow these conventions when mapping combos:
always use an uppercase letter for the modifier key, C for Control, S for Shift, A for Alt, D for Command (MacVim GUI only), M for Meta,
always use a lowercase letter for the alphabetical keys, abc…xyz,
always capitalize the first letter of "special" keys, Tab, Space, Up, etc.
Examples:
<S-Up>
<C-r>
<A-LeftMouse>
However, the following notation works just as well so… whatever notation you choose, try to be consistent:
<s-UP>
Using multiple modifiers in a single mapping doesn't work reliably so you will be better in the long run if you completely avoid them.
nnoremap <C-S-j> :echo "csj"<CR>
nnoremap <C-j> :echo "cj"<CR>
now press <C-j> and <C-S-j> in normal mode.
<C-S-w> is indistinguishable from <C-w>.
:verbose map <C-t>
shows you what is mapped to <C-t> and where the mapping occurred. You can use it to debug your mappings.
And I agree with Peter, you are using both tab pages and insert mode wrongly.

gvim: make <S-Up>, <S-Down> move in screen lines

I chose to use gvim as my primary text editor, but still would like it to behave more like other visual editors I'm used to. One aspect of that is that when I have wrap enabled (set linebreak) and use the arrow keys <Up> and <Down> in insert mode, I'd like to move the cursor to the previous / next screen line, not logical line. This can be achieved using the mappings:
inoremap <Up> <C-O>gk
inoremap <Down> <C-O>gj
...and everything is fine.
Except, in select mode. While using <S-Right>, <S-Left> works as expected, <S-Up> and <S-Down> still move in terms of logical lines. On http://vim.wikia.com I found the following suggestion for additional mappings:
noremap <S-Up> vgk
noremap <S-Down> vgj
inoremap <S-Up> <C-O>vgk
inoremap <S-Down> <C-O>vgj
The two latter mappings now enable that when I start a selection by pressing <S-Down> in insert mode, I get a selection from the previous position to the same position in the next screen line. But when I already have a selection (already am in select mode), pressing <S-Down> moves one line down but loses the selection.
I would expect to achieve this it would be necessary to have specific mapping for select mode (snoremap), but wasn't able to figure out how to do it.
Because of the discussion with glts whether select mode is useless or not, maybe some background information is in order: Select mode appears to be vim's attempt to provide something close to the selection behavior found in most other visual editors on MS Windows, Mac OS, and even Linux, which in turn is inspired by IBM's CUA. Since it is only really useful with the accompanying keyboard mappings ^C, ^X, ^V, it is meant to be used in conjunction with mswin.vim which provides these mappings. My question is motivated by an attempt to complement these mappings such that select mode works as expected also for wrapped text.
For Select mode, if that is really what you mean, these mappings would work:
vnoremap <S-Up> gk
vnoremap <S-Down> gj
imap <S-Up> <Esc>gh<S-Up>
imap <S-Down> <Esc><Right>gh<S-Down>
nmap <S-Up> gh<S-Up>
nmap <S-Down> gh<S-Down>
Note the gh command (Select mode) instead of v (Visual mode).
But be warned that – and this is an assumption on my part – the general populace of Vim users shun Select mode, seeing as it runs counter to the Vim way.
Visual mode is much more powerful, since in addition to replacing text, you can also yank it into a register, make it uppercase or lowercase, change the extent of the Visual selection, etc. etc. Have a look at :h vim-modes.
Here is what I came up with myself:
Make <Up> and <Down> move to previous / next screen line. (In insert mode, <C-O> switches to normal mode for one command. In normal mode, gj and gk are the 'move by screen line' commands.)
inoremap <Up> <C-O>gk
inoremap <Down> <C-O>gj
Same for <S-Up> and <S-Down> in insert mode, entering select mode. (In normal mode, v enters visual mode. gj and gk work also in visual mode. In visual mode, <C-G> enters select mode.)
inoremap <S-Up> <C-O>vgk<C-G>
inoremap <S-Down> <C-O>vgj<C-G>
Same for <S-Up> and <S-Down> in select mode. (In select mode, <C-O> switches to visual mode for one command.)
snoremap <S-Up> <C-O>gk
snoremap <S-Down> <C-O>gj

Map :w to Escape in insert mode and normal mode

In order to save time in Vim, I came up with an idea. To map :w key binding to Esc in both normal mode and insert mode. However it only works in insert mode whereas in normal mode things are getting messy when I open a new file. This is what I added in .vimrc:
:inoremap <Esc> <Esc>:w<CR>
:nnoremap <Esc> :w<CR>
As I said the first command alone, works fine. But adding the second command, keys are messed up ESPECIALLY when I open a new file. For instance, although I have explicitly added in .vimrc:
map <up> <nop>
map <down> <nop>
map <left> <nop>
map <right> <nop>
by adding the second command for the normal mode, pressing up down left or right keys cause to enter in insert mode and add A B C D.
Could you help me to achieve my idea?
Information on Vim FAQ 10.9 may be useful:
10.9. When I use my arrow keys, Vim changes modes, inserts weird characters
in my document but doesn't move the cursor properly. What's going on?
There are a couple of things that could be going on: either you are using
Vim over a slow connection or Vim doesn't understand the key sequence that
your keyboard is generating.
If you are working over a slow connection (such as a 2400 bps modem), you
can try to set the 'timeout' or 'ttimeout' option. These options, combined
with the 'timeoutlen' and 'ttimeoutlen' options, may fix the problem.
The preceding procedure will not work correctly if your terminal sends key
codes that Vim does not understand. In this situation, your best option is
to map your key sequence to a matching cursor movement command and save
these mappings in a file. You can then ":source" the file whenever you work
from that terminal.
For more information, read
|'timeout'|
|'ttimeout'|
|'timeoutlen'|
|'ttimeoutlen'|
|:map|
|vt100-cursor-keys|
From :h vt100-cursor-keys:
Other terminals (e.g., vt100 and xterm) have cursor keys that send <Esc>OA,
<Esc>OB, etc. ...
So probably your nnoremap is causing the Esc on the arrow's key sequence to save the file, and the remaining characters are being interpreted alone, so the A is entering insert mode.
You could consider using option 'autowriteall', or using a different mapping to save your file; these are defined in $VIMRUNTIME\mswin.vim:
" Use CTRL-S for saving, also in Insert mode
noremap <C-S> :update<CR>
vnoremap <C-S> <C-C>:update<CR>
inoremap <C-S> <C-O>:update<CR>
The :update command is similar to :w, but only writes only if the file has been modified.
Also, you can use
autocmd InsertLeave * write

Vim: overloaded mapping for multiple modes

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

Resources