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

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

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

How do I map keys not simultaniously in vim?

I don't know if sequentially is the right word, but I'd like to nnoremap Ctrl+t to Ctrl+y and then a comma. Is that possible or do I need to do this another way?
Yes, add
nnoremap <C-t><C-y>, a
to your ~/.vimrc, where <C-t> and <C-y> are ctrl+t and ctrl+y, respectively, and a is whatever action you want to have the keys map to.
You map the keys you want to press to what you want to happen.
If you want Ctrl+t to happen when you press Ctrl+y then ,, then your mapping should look like this:
nnoremap <C-y>, <C-t>
If you want Ctrl+y then , to happen when you press Ctrl+t, then your mapping should look like this:
nnoremap <C-t> <C-y>,
The concept of mapping is introduced in chapter 40 of the user manual, which you should have read, and further discussed under :help mapping.
But, judging by your comments under the other answer, creating a normal mode non-recursive mapping is not the solution to your problem.
First, because the plugin exposes <C-y>, in normal, visual, select, and insert modes so you must cover all of them:
" insert mode
inoremap <C-t> <C-y>,
" visual mode and select mode
vnoremap <C-t> <C-y>,
" normal mode
nnoremap <C-t> <C-y>,
Second, because <C-y>, is itself a mapping so you want your custom mapping to be recursive:
imap <C-t> <C-y>,
vmap <C-t> <C-y>,
nmap <C-t> <C-y>,
While the mappings above work, the whole idea a bit shortsighted because:
The <C-y> in <C-y>, is a "leader" that is common to all the mappings exposed by that plugin. You can now press <C-t> instead of <C-y>, but all the other functionalities of that plugin are still behind that <C-y> leader and still follow that <leader><key> pattern so your system is now inconsistent.
You are overriding <C-t> in normal and insert modes, where it is pretty useful.

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.

Vim: Why does noremap not work in insert mode?

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.

Navigating in Vim's Command Mode

I am a long time emacs user learning Vim. Emacs lets me navigate in the mini-buffer (where I issue commands like C-x C-s) using the same navigation keyboard shortcuts as in any other buffer. For example, I can navigate forward one character using C-f, even while in the mini-buffer. I could also use the arrow keys, but they are too far away.
Is there any keyboard shortcut to navigate in Vim's command mode (:), without using the arrow keys -- equivalent to emacs C-f, C-b? Thanks.
Adding to Greg Hewgill's answer, you can use q: to open the command-line window, where you have any Vim editing power at your hand.
Some from the Vim help:
CTRL-B or <Home>
cursor to beginning of command-line
CTRL-E or <End>
cursor to end of command-line
CTRL-H
<BS> Delete the character in front of the cursor (see |:fixdel| if
your <BS> key does not do what you want).
<Del> Delete the character under the cursor (at end of line:
character before the cursor).
CTRL-W Delete the |word| before the cursor. This depends on the
'iskeyword' option.
CTRL-U Remove all characters between the cursor position and
the beginning of the line.
I have these in my .vimrc
cnoremap <C-a> <Home>
cnoremap <C-e> <End>
cnoremap <C-p> <Up>
cnoremap <C-n> <Down>
cnoremap <C-b> <Left>
cnoremap <C-f> <Right>
cnoremap <M-b> <S-Left>
cnoremap <M-f> <S-Right>
With the default key bindings, vim does not offer non-arrow-key navigation of the command line editing. However, see :help cmdline-editing for an example of how to use the :cnoremap command to set up alternate key bindings.
I achieved that with <C-p> and <C-n> to navigate previous and next commands respectively.
P.S I'm not making any custom binding like Tassos did.

Resources