Properly remap vim numpad keys when numlock is off - vim

I want to remap my numpad so that even if numlock is off, I still have it print numbers.
This is obviously a fairly common task - it has been asked multiple times around the internet, and has its own page dedicated to it (though the page is putty-specific):
https://vim.fandom.com/wiki/PuTTY_numeric_keypad_mappings
Whenever it gets asked online, the answer seems to always be the same - a copy-paste of the lines from that guide:
:inoremap <Esc>Oq 1
:inoremap <Esc>Or 2
:inoremap <Esc>Os 3
:inoremap <Esc>Ot 4
:inoremap <Esc>Ou 5
:inoremap <Esc>Ov 6
:inoremap <Esc>Ow 7
:inoremap <Esc>Ox 8
:inoremap <Esc>Oy 9
:inoremap <Esc>Op 0
:inoremap <Esc>On .
:inoremap <Esc>OQ /
:inoremap <Esc>OR *
:inoremap <Esc>Ol +
:inoremap <Esc>OS -
:inoremap <Esc>OM <Enter>
Unfortunately, that doesn't always work. It certainly works for putty - I can confirm that, but right now, I'm using Fedora 31, with the regular Gnome Terminal, and with those lines in my .vimrc file, if I hit a numpad key with the numlock disabled, the keys either act as arrow keys (2,4,6,8), or Home, End, Pg Up, Pg Down.
One thing I can do is this instead (or in addition to the other mappings):
inoremap ^[OF 1
inoremap ^[OB 2
inoremap ^[[6~ 3
inoremap ^[OD 4
inoremap ^[OE 5
inoremap ^[OC 6
inoremap ^[OH 7
inoremap ^[OA 8
inoremap ^[[5~ 9
inoremap ^[[2~ 0
inoremap ^[[3~ .
inoremap ^[Oo /
inoremap ^[Oj *
inoremap ^[Ok +
inoremap ^[Om -
inoremap ^[OM <Enter>
I got these key combinations but simply hitting Ctrl+V, and my numpad keys to see what signal was being sent when the numlock was off. This works, and my numpad keys work as expected now. Except there's a problem. These signals are exactly the same as the other keys send. This means that now, if I actually hit my left arrow key in insert mode, it prints 4 instead of moving left. Same for the other arrow keys, and the Home/End/PageUp/PageDown keys.
This is obviously inconvenient, because in insert mode, you can't use hjkl to navigate, and now, the arrow keys don't work either.
I understand the reason this happens - with numlock off, my 7 key on the numpad sends the exact same code that the Home button does, so if I override that, it effects both the 7 button (when the numlock is off), and the actual Home button.
Is there any kind of smart fix for this? Or is this inherently impossible to map without effecting the real arrow buttons, and Home/End/PgUp/PgDown buttons?
Failing that, is vim capable of enabling numlock when it starts up?

Related

Vim: temporary normal mode while holding Alt in insert mode

I wonder if there's a way to make the Alt (or another key) work like Ctrl-o, but for as long as the key is pressed. For example, if you're in insert mode and want to move 10 lines down and 2 words forward, you could hold Alt, press 10jww and then release the Alt key. It is much faster than pressing Ctrl-o before each movement or leaving insert mode and having to enter it back again.
I did some remappings to use the main movement keys from insert mode while holding Alt:
inoremap <A-h> <C-o>h
inoremap <A-j> <C-o>j
inoremap <A-k> <C-o>k
inoremap <A-l> <C-o>l
inoremap <A-w> <C-o>w
inoremap <A-e> <C-o>e
inoremap <A-b> <C-o>b
But that is limited, if I wanted to use numbers to move multiple steps for example, I would need to map a new key binding for each movement and for each number.
If it was possible to do something like enter normal mode on Alt (keydown) and go back to insert on Alt (keyup), then all normal mode key bindings should be available only by holding one key.

Remapping <ESC> breaks <S-TAB> mapping in vim

I had the following mapping on my vimrc
nnoremap <TAB> gt
nnoremap <S-TAB> gT
Then I mapped ESC to clear highlights as:
noremap <silent> <ESC> :noh<return>
And then <S-TAB> wont work anymore. If I remove <silent> from <ESC> mapping I see :noh when I press <S-TAB>. I don't know if <S-TAB> and <ESC> has something in common. I'm on Linux, using vim on gnome-terminal.
You're right in assuming that <S-TAB> and <ESC> have something in common. S-TAB is an escape-prefixed keycode.
The ESC keycode is ^[, while S-TAB is ^[[Z. You can see the first part of the S-TAB key code matching the ESC keycode.
See a full table of combinations here.
So you just can't remap the escape key while also remapping one of the key codes including it. Either pick a different key to clear highlights or a different way of switching tabs.

what is the definition of a "change" in vim in terms of undo?

I'm trying to understand multi-level undo in vim.
I opened vim and typed:
1
2
3
4
5
6
7
and then I typed:
:u 1
I got message:
0 changes; before #1 22:53:11
and when I typed:
:u 2
I saw:
E830: Undo number 2 not found
my understanding is every vi command or character typed in edit mode is counted as a "change" but obvious that is not the case.
Could any seasoned vim expert clarify?
In general, a single change is every normal mode command that changes your buffer.
For insert mode, everything typed is considered a single change, until you leave insert mode. There are exceptions however. Using the cursor keys breaks the undo sequence. Another exception is, if you press Ctrl+gu which will intentionally break the undo sequence. Also when temporarily leaving insert mode using e.g. Ctrl+o this will break a change.
You can modify undo behavior like this (in your ~/.vimrc):
inoremap <BS> <c-g>u<BS>
inoremap <CR> <c-g>u<CR>
inoremap <del> <c-g>u<del>
inoremap <c-w> <c-g>u<c-w>
For more information see: :h i_Ctrl-g_u and read this link on vim wiki.
If you are using some completion plugin like me, you have to make more than that. I am using deoplete and in this case I had to do this:
" <CR>: close popup and save indent.
" Now each Enter creates a undo point ":h i_Ctrl-g_u"
inoremap <silent> <CR> <C-r>=<SID>my_cr_function()<CR>
function! s:my_cr_function()
return deoplete#mappings#smart_close_popup() . "\<C-g>u\<CR>"
endfunction

Vim: Map Esc Without Affecting Terminal Control Characters

I'm trying to map <Esc> to turn off search highlighting in Vim. The problem is that keys simulated by the terminal with +Esc are affected.
The terminal sends characters much fast than I type. Is there perhaps a way to map key + timeout in vim?
The same question was asked 4 years ago and the answer was that it can't be done. Is this (still) true?
Mapping :nohlsearch to escape key
Your troubles are being caused by some plugin or other, native vim handles this fine. Start vim with vim --noplugin, or if that's not enough then bypass your vimrc with vim -u NONE (or gvim -U NONE) and :source this:
set nocp " life's too short for pure vi-compatibility mode
set timeout ttimeout " enable separate mapping and keycode timeouts
set timeoutlen=250 " mapping timeout 250ms (adjust for preference)
set ttimeoutlen=20 " keycode timeout 20ms
nno <ESC> :nohls<CR>
I've never seen and can't reproduce the interference you're describing so I don't know what's causing it, all I can suggest is binary search with your plugin set.
Yes, it's still not possible for the reason given by ZyX in his answer.
<Esc> is "special" because its behavior sits between a "normal" key like a (you can map it to whatever you want) and a modifier key (it's used by the terminal to represent a lot of special keys like <Up>).
Safely mapping <Esc> to do anything else/more than <Esc> is possible but you'll have to noremap all the affected keys. Here is what I have in my vimrc to mitigate that side effect:
nnoremap <Esc>A <up>
nnoremap <Esc>B <down>
nnoremap <Esc>C <right>
nnoremap <Esc>D <left>
inoremap <Esc>A <up>
inoremap <Esc>B <down>
inoremap <Esc>C <right>
inoremap <Esc>D <left>

Mapping keys on numerical keypad

For years now I've been using laptops - without numerical keypads on their keyboards. Having recently acquired a dekstop keyboard ... just today I found out that Vim's mapping to numbers (1 ... 9, 0) don't work on their numerical keypad equivalents. What I mean?
nmap 1 Dj
doesn't work on the numerical keyboard 1?
Is there any solution to this problem (not really a "problem", but annoying)?
This works for me on Windows: nmap <C-k5> :tabnew<CR>
The keypad identifiers are k1, k2, etc. Also kPlus and so on. As far as I can tell, the mappings fail when NumLock is off.
I have had some keyboards and terminals where I was unable to map via the k* identifiers. To map them in that situation, use Ctlv in order to input the correct escape code
So for example to map 1 on the keypad to perform Dj, enter:
:map
Then type Ctlv, which will leave open an escape sequence with ^[. Then press 1 on the keypad. The resultant code will look something like ^[Ow. Complete your mapping as normal:
:map ^[Ow Dj
You can map in vi (e.g. in ~/.vimrc) the NUM keys in the following way:
inoremap <Esc>Oq 1
inoremap <Esc>Or 2
inoremap <Esc>Os 3
inoremap <Esc>Ot 4
inoremap <Esc>Ou 5
inoremap <Esc>Ov 6
inoremap <Esc>Ow 7
inoremap <Esc>Ox 8
inoremap <Esc>Oy 9
inoremap <Esc>Op 0
inoremap <Esc>On .
inoremap <Esc>OQ /
inoremap <Esc>OR *
inoremap <Esc>Ol +
inoremap <Esc>OS -
inoremap <Esc>OM <Enter>
This setting is an example for using the NUM key as they should be. Of course you can change the mappings.
I also use keypad mappings a lot. To help you get started with figuring out mappings, you can see what keys vim "knows about" and what there current mappings are with:
:h keycodes
Hopefully this will list you keypad keys as etc etc. If that is the case, then you can easily (don't have to worry about finding out and using their escape sequences) remap them using map <k0> :wincmd w<CR> for instance.
For years I was using the Ctrl-v followed by a key to get the XXXX mappings previously until I found about the keycodes command, and the really helpful definitions.
Hope that might help!

Resources