Vim: arrow keys to move within a line in insert mode - vim

I have <Up> and <Down> nnoremapped to gk and gj but this won't let me use them while in edit mode. I tried using inoremap but that just types out gk or gj.
So I could certainly do something like inoremap <Up> <ESC>gki. Is this the best and only reasonable way to do it? I don't like this method because it isn't apparent to somebody reading the settings file what it does. Not that I could say that about any bit of vim setting file I have ever seen.

To execute a normal mode command in insert mode, use
Control+o. Straight from the help:
CTRL-O execute one command, return to Insert mode *i_CTRL-O*
So something like this:
inoremap <Up> <C-O>gk
inoremap <Down> <C-O>gj
Might be more readable.

Related

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>

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

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>

Best of both worlds: arrow keys for cursor movement or flipping through buffers

I really like this vim trick to use the left and right arrows to flip between buffers:
"left/right arrows to switch buffers in normal mode
map <right> :bn<cr>
map <left> :bp<cr>
(Put that in ~/.vimrc)
But sometimes I'm munching on a sandwich or something when scrolling around a file and I really want the arrow keys to work normally.
I think what would make most sense is for the arrow keys to have the above buffer-flipping functionality only if there are actually multiple buffers open.
Is there a way to extend the above to accomplish that?
I'd rather have a completely different mapping because:
cursors are really useful, and not having them because you have a hidden buffer will annoy you a lot
some plugins use <left> and <right> because they are less obfuscated than l and h; those plugins are likely to break with such mappings
Anyway, you can try this:
nnoremap <expr> <right> (len(filter(range(0, bufnr('$')), 'buflisted(v:val)')) > 1 ? ":bn\<cr>" : "\<right>")
nnoremap <expr> <left> (len(filter(range(0, bufnr('$')), 'buflisted(v:val)')) > 1 ? ":bp\<cr>" : "\<left>")
To see documentation on the pieces above:
:h :map-<expr>
:h len()
:h filter()
:h range()
:h bufnr()
:h buflisted()
I use alt-direction to switch between buffers.
nmap <A-Left> :bp<CR>
nmap <A-Right> :bn<CR>
If you modifying hl's defaults, then the arrows would feel more useful. (Like changing whichwrap to allow hl to go past the end of line.)
I do something similar with jk to make them different from my arrows:
" work more logically with wrapped lines
set wrap
set linebreak
noremap j gj
noremap k gk
noremap gj j
noremap gk k
That will wrap long lines and jk will move to what looks like the line below. (If you have one long line, then you'll move to the part of that line below the cursor.) Great for editing prose or long comments.
See also
help showbreak
I map Tab and Shift+Tab to switch buffers when in normal mode (makes sense to my brain and the keys are not doing anything useful otherwise).
Add this to your .vimrc
" Use Tab and Shift-Tab to cycle through buffers
nnoremap <Tab> bnext<CR>
nnoremap <S-Tab> :bprevious<CR>

Resources