How to remap arrow keys in Vim in insert mode? - vim

When I am in insert mode I want to use the keys h, j, k and l to behave as the arrow keys.
I want to achieve this by holding the ctrl key and then ctrl + k would move the line upwards in insert mode. Since these four keys are already mapped to move the lines when not in insert mode, how can I achieve this behavior when I am in insert mode?

You can use imap for that like this:
inoremap <C-h> <Left>
inoremap <C-j> <Down>
inoremap <C-k> <Up>
inoremap <C-l> <Right>

Related

How do I rebind `hjkl` to `jkl;`

I've been trying to rebind to proper touch typing keys, and
it's actually more complicated I expected. This is my init.vim:
" Normal mode
nmap ; <Right>
nmap l <Up>
nmap k <Down>
nmap j <Left>
nnoremap h ;
" Visual mode
vmap ; <Right>
vmap l <Up>
vmap k <Down>
vmap j <Left>
vnoremap h ;
" Rebind the window-switching movements
nnoremap <C-w>; <C-w>l
nnoremap <C-w>l <C-w>k
nnoremap <C-w>k <C-w>j
nnoremap <C-w>j <C-w>h
nnoremap <C-w>h <C-w>;
Looks fine, right? Except it's not. By default in vim, when you press Ctrl + W + k, your window will switch, regardless if you pressed k with Ctrl + W already being pressed down or in succession to Ctrl + W. However, with my key rebinds, the movement key must be pressed after releasing Ctrl + W. This ruins my workflow, as sometimes, I try to quickly switch window, and I fail because I didn't release Ctrl + W quick enough.
How can I achieve a proper keybind without making window-switching less convenient? Thanks.
If you look at :help CTRL-W_j and its friends, you will see that they all have a bunch of alternatives. The important one is <C-w><C-j>, which is what lets you keep your left pinky on Ctrl while you press j with the right index or keep your left pinky and index on Ctrl and w while you press j with the right index.
Therefore:
[...]
nnoremap <C-w>j <C-w>h
nnoremap <C-w><C-j> <C-w>h
[...]

How to unbind h and l in vim?

I'm learning vim and I would like to unbind h and l (left and right movements).
What should I include in my .vimrc?
Note: By doing that I'm forcing myself to use w, W, b, B, e, and other movements to move horizontally.
Use nop to suppress the effect of a command:
nnoremap h <NOP>
nnoremap l <NOP>
You could study/enhance the "dogmatic.vim: Arrow keys are heretical" plugin, which not only disables the keys but also displays a message to remind you. You would need to duplicate the following lines:
noremap <silent> <right> <Esc>:call dogmatic#TrackArrowPress('right')<cr>
noremap <silent> <left> <Esc>:call dogmatic#TrackArrowPress('left')<cr>
noremap <silent> <up> <Esc>:call dogmatic#TrackArrowPress('up')<cr>
noremap <silent> <down> <Esc>:call dogmatic#TrackArrowPress('down')<cr>
If you follow this approach you could consider providing a patch/pull request to the plugin author, possible by creating an option which allows the plugin user to enable/disable your modifications.

Mapping <Shift>-Arrows to selecting characters/lines

I started to use vim recently, but I miss the character/line selection methods from other text editors. By default vim maps <S-Up>, <S-Down> to jumping one page up/down and I want to remap these to text selection.
Is there a way to do that?
I completed #escrafford mapping with insert mode's ones:
" shift+arrow selection
nmap <S-Up> v<Up>
nmap <S-Down> v<Down>
nmap <S-Left> v<Left>
nmap <S-Right> v<Right>
vmap <S-Up> <Up>
vmap <S-Down> <Down>
vmap <S-Left> <Left>
vmap <S-Right> <Right>
imap <S-Up> <Esc>v<Up>
imap <S-Down> <Esc>v<Down>
imap <S-Left> <Esc>v<Left>
imap <S-Right> <Esc>v<Right>
Also mapping usual copy/cut/paste like this you can return to insert mode after select+copy, for example.
vmap <C-c> y<Esc>i
vmap <C-x> d<Esc>i
map <C-v> pi
imap <C-v> <Esc>pi
imap <C-z> <Esc>ui
Now you can start a shift+arrow selection from any mode, then C-c to copy, and then C-v to paste. You always end in insert mode, so you have also C-z to undo.
I think this approaches more to the 'expected standard' behaviour for a text editor yu are asking for.
There's an specific option for this: keymodel:
'keymodel' 'km' string (default "")
global
{not in Vi}
List of comma separated words, which enable special things that keys
can do. These values can be used:
startsel Using a shifted special key starts selection (either
Select mode or Visual mode, depending on "key" being
present in 'selectmode').
stopsel Using a not-shifted special key stops selection.
Special keys in this context are the cursor keys, <End>, <Home>,
<PageUp> and <PageDown>.
The 'keymodel' option is set by the |:behave| command.
TL;DR: To enable the behavior you want, use:
set keymodel=startsel
If you also want to leave visual mode when using <Up> or <Down> without <Shift> pressed, you can use:
set keymodel=startsel,stopsel
Slightly different from progo's answer - this gives the same feel as mac apps normally have:
nmap <S-Up> v<Up>
nmap <S-Down> v<Down>
nmap <S-Left> v<Left>
nmap <S-Right> v<Right>
vmap <S-Up> <Up>
vmap <S-Down> <Down>
vmap <S-Left> <Left>
vmap <S-Right> <Right>
The differences being switch to visual mode instead of visual line mode, and not losing the initial up/down etc keystroke.
Vim doesn't bend to that easily in my opinion. The terminal one doesn't even recognize Shift-Up in my case! I thought the v (character-wise selection) or V (line-wise selection) was among the easier concepts to learn about vi/vim.
If this works (can't test right now), this is something you'll want:
" activate visual mode in normal mode
nmap <S-Up> V
nmap <S-Down> V
" these are mapped in visual mode
vmap <S-Up> k
vmap <S-Down> j
"
" etc...
" similarly <S-Left>, <S-Right> for v
I found another solution that is easier to execute. The command ':behave mswin' does all that is needed to use shift plus cursor keys to select text. Works from any mode. It also supports Cmd-c, Cmd-v and Cmd-x. It works in MacVim but I did not try other platforms.
It is definitely recommended that you don't remap this feature. Simply switching to visual mode and using v and the arrow keys is a better idea. V will select the entire line, v$ will select to the end of the line and vw will select the next word. There are many more commands you can use to select different lines and words. Learning these commands will not only be useful for selecting but also useful for editing your files more efficiently.
This mapping keeps insert mode during selection (visual mode) and it starts on the correct position. You can also select a word to the left or right using Ctrl-Shift-Left/Right (if your terminal supports it):
" Select with shift + arrows
inoremap <S-Left> <Left><C-o>v
inoremap <S-Right> <C-o>v
inoremap <S-Up> <Left><C-o>v<Up><Right>
inoremap <S-Down> <C-o>v<Down><Left>
imap <C-S-Left> <S-Left><C-Left>
imap <C-S-Right> <S-Right><C-Right>
vnoremap <S-Left> <Left>
vnoremap <S-Right> <Right>
vnoremap <S-Up> <Up>
vnoremap <S-Down> <Down>
" Auto unselect when not holding shift
vmap <Left> <Esc>
vmap <Right> <Esc><Right>
vmap <Up> <Esc><Up>
vmap <Down> <Esc><Down>
This may be useful for quickly selecting small parts when you're in insert mode but I recommend using the default commands for selecting larger parts.
I've written this to be able to navigate using Alt+hjkl (and friends) and select using Alt+HJLK when both in insert, visual and normal mode.
So the same can be applied to normal arrow keys as well
let hjklfriends = ['h','j','k','l','w','e','b','W','E','B', 'n', 'N', 'y', 'Y', 'p', 'P']
" define if using alt (it works in neovim) or Escape key.
function! Meta(key)
if has('nvim')
return "<A-" . a:key . ">"
else
return "<Esc>" . a:key
endif
endfunction
execute 'noremap! ' . Meta('h') . ' <left>'
execute 'noremap! ' . Meta('j') . ' <down>'
execute 'noremap! ' . Meta('k') . ' <up>'
execute 'noremap! ' . Meta('l') . ' <right>'
execute 'noremap! ' . Meta('b') . ' <C-Left>'
execute 'noremap! ' . Meta('w') . ' <C-Right>'
execute 'noremap! ' . Meta('e') . ' <C-Right>'
for k in hjklfriends
execute 'imap ' . Meta(k) . ' <C-o>' . k
if k =~ '[a-z]'
execute 'imap ' . Meta(toupper(k)) . ' <C-o>v' . k
execute 'vmap ' . Meta(toupper(k)) . ' ' . k
execute 'nmap ' . Meta(toupper(k)) . ' v' . k
endif
endfor
Modified from #RubenCaro's answer.
The issue is: when escaping from insert mode, the cursor will be shifted to the left by one. This makes the behaviour of the keys , , and in insert mode different from the behaviour of other generic text editors.
Assuming that the goal is to make those keys behave like generic editor, the mapping should be slightly modified to:
" shift+arrow selection
nmap <S-Up> v<Up>
nmap <S-Down> v<Down>
nmap <S-Left> v<Left>
nmap <S-Right> v<Right>
vmap <S-Up> <Up>
vmap <S-Down> <Down>
vmap <S-Left> <Left>
vmap <S-Right> <Right>
imap <S-Up> <Esc>v<Up>
imap <S-Down> <Esc>vlvv<Down>
imap <S-Left> <Esc>v<Left>
imap <S-Right> <Esc>vlvv<Right>
vmap <C-c> y<Esc>i
vmap <C-x> d<Esc>i
map <C-v> pi
imap <C-v> <Esc>pli
imap <C-z> <Esc>ui

how can i intuitively move cursor in vim?(not by line)

if some lines are too long, it will be forced to be newlined.
for example, normally a long line will looks like this
1 first line
2 this is the long second line of the file
3 third line.
but, if the window of a vim are too narrow, it will looks like this
1 first line
2 this is the long
second line of the file
3 third line
the problem arise from this.
let's assume the vim cursor are located at before 't' in 'third line'. if i type 'k', cursor will move to before 's' in 'second line of the file'. after that, if i type 'k' again, cursor will move to 'f' in 'first line'!, not 't' in 'this is the long'. what i want is that the cursor move to 't' in 'this is the long', it is more intuitive process for me. how can set my vim to works like this?
In Vim, the gj and gk commands move by line on the screen rather than by line in the file. This sounds like it probably matches your description.
You can modify your keys like this:
:map j gj
:map k gk
No, if some lines are too long and you have set wrap on they will be shown on "two lines", so to say, but there won't be a newline character between them. If you turn off wrap with set nowrap you'll see the effect.
Normally, k and j move you up and down. If you want to navigate wrapped lines use gk or gj, or just as some like it, map it to for example, the cursor keys.
nmap <up> gk
nmap <down> gj
To move in vim in a natural way is possible.
What I did was, and I suggest you, to modify (or create) your "~/.vimrc" and add these two lines:
map <C-Up> g<Up>
map <C-Down> g<Down>
This will map you control-up and control-down to the movements commands (this is coherent with control-right and control-left to move around long lines)
If you add these other two lines, you can use the same command to move in insertmode:
imap <C-Up> <C-[> g<Up> i
imap <C-Down> <C-[> g<Down> i
(VIM is great !)
Greg Ruo
This answer is derived from #mario-rossi 's answer (Kudo to him), with minor midification.
I use the normal UP and DOWN arrow key, rather than CTRL+up and CTRL+down. And somehow I need to remove one excess space in the INSERT mode mapping to avoid an off-by-one behavior.
Put the following into your ~/.vimrc:
" When a long line is wrapped, the "gk" and "gj" allow you to move up and down
" a visual line, while normal "k" and "j" move a physical line.
" The following settings map "gk" and "gj" to cursor <up> and <down>.
map <up> gk
map <down> gj
" And the following lines enables same <up> and <down> behavior in INSERT mode
imap <up> <C-[> <up>i
imap <down> <C-[> <down>i
Took this from vim.fandom.com:
There are several cases to remap up and down movements. First, you probably should remap both k/j and / arrows. Second, you should coose vim modes that requires remap. Basic modes are Normal (nmap), Insert (as after i command, imap) and Select (as after v command, vmap). To remap all three:
nnoremap j gj
nnoremap k gk
vnoremap j gj
vnoremap k gk
nnoremap <Down> gj
nnoremap <Up> gk
vnoremap <Down> gj
vnoremap <Up> gk
inoremap <Down> <C-o>gj
inoremap <Up> <C-o>gk
There's also one significant Operator mode (as in dj or, to say, y4k), remapping operator (omap) breaks vim experience/habits dramatically and not recommended.
Personally I prefer to remap Insert mode only, to keep my editorial habits intact.

How to disable Esc and cursor keys in vim

There is an opinion that when working in vim you should not use Esc key (use ctrl+c instead) and don't use arrow keys (use h,j,k,l) on you keyboard. But it is difficult to not to use those keys. I thought that there is a way to disable those keys in .vimrc so there will be no other option but to use ctrl+c and hjkl.
I've searched a bit and found a solution on this link.
So I've inserted the following in my .vimrc file:
inoremap <Up> <NOP>
inoremap <Down> <NOP>
inoremap <Left> <NOP>
inoremap <Right> <NOP>
inoremap <Esc> <NOP>
noremap <Up> <NOP>
noremap <Down> <NOP>
noremap <Left> <NOP>
noremap <Right> <NOP>
noremap <Esc> <NOP>
But this does not work. Adding this to my .vimrc breaks my mapping to the
function keys. The another problem is that it does not block the function of arrow keys rather when I press Down in normal mode multiple actions are performed - the cursor goes up one line, the new line is created and the character 'B' is inserted.
How can I disable in my vim 7.2 the cursor keys and Esc key without breaking anything else?
If you're using vim in a terminal you should absolutely not remap Escape. Because of the way keys are handled in vim (and probably terminals in general), remapping it will break all kinds of keys you didn't intend on changing. To see what I mean, do the following.
Open up vim with no startup files: vim -u NONE --noplugin -N.
Enter insert mode.
Press Ctrl-v followed by any of the function keys, such as <F2>.
Notice the sequence that is entered. It very likely begins with ^[ which is a literal Escape.
Now open try the following:
:inoremap <esc> NO ESCAPE FOR YOU
Enter insert mode.
Press any of the function keys, like <F2>.
If the previous sequence showed the escape character as part of the <F2> key press, you'll now see our new string printed to the screen. In fact, now that you have the mapping, try to move around using the cursor keys. You'll probably notice the same bizarre behavior.
In conclusion, don't remap escape, I almost guarantee you will have unexpected consequences.
Here's a non-geeky way of achieving what you want: Crumple pieces of paper to the size of your thumb and tape them to the keys. The moment your finger tries to reach them you'll bump into the paper instead. They'll become a good reminder. Keep them taped there until you stopped bumping into them.
What you had was close:
inoremap <esc> <NOP>
inoremap <Left> <NOP>
inoremap <Right> <NOP>
inoremap <Up> <NOP>
inoremap <Down> <NOP>
nnoremap <Left> <NOP>
nnoremap <Right> <NOP>
nnoremap <Up> <NOP>
nnoremap <Down> <NOP>
This line was causing you trouble:
noremap <Esc> <NOP>

Resources