Vim: remap on every mode except visual - vim

I am doing a key mapping when in visual mode:
:vnoremap Ó b
However, for all other modes, I need to have another mapping. Is there a way to do something like:
:'vremap
to specify all other modes? Currently I'm doing something very long-winded, like:
"Simulate option-shift arrow keys to highlight chunks of text
:vnoremap Ó bv
:vnoremap Ò el
:vnoremap Ô j
:vnoremap  k
:nnoremap Ó <Esc>vb
:nnoremap Ò <Esc>vel
:nnoremap Ô <Esc>vj
:nnoremap  <Esc>vk
:inoremap Ó <Esc>lvb
:inoremap Ò <Esc>lve
:inoremap Ô <Esc>vj
:inoremap  <Esc>vk

Is there a way to do something like :'vremap to specify all other modes?
As #Chelz pointed out, there is no map command for "all modes". There are, however, several ways to avoid having to define the same mapping multiple times for multiple modes.
In this answer, the author illustrates how to use a for loop to map to more than one mode at the same time:
for map_command in ['nnoremap', 'inoremap']
execute map_command . ' <silent> Ó <Esc>vb'
execute map_command . ' <silent> Ò <Esc>vel'
execute map_command . ' <silent> Ô <Esc>vj'
execute map_command . ' <silent>  <Esc>vk'
endfor
And in this answer, a wrapper function is used to achieve the same:
function! MapBoth(keys, rhs)
execute 'nnoremap' a:keys a:rhs
execute 'inoremap' a:keys a:rhs
endfunction
call MapBoth('Ó', '<Esc>lvb')
call MapBoth('Ò', '<Esc>lve')
call MapBoth('Ô', '<Esc>vj')
call MapBoth('', '<Esc>vk')
With these solutions, you will only have to define the mappings once.
Disclaimer: I have not tried the solutions above, but please let us know if they do not work for you.

take a look at the documentation :h map, there you will find the following:
:no[remap] {lhs} {rhs} |mapmode-nvo| *:no* *:noremap* *:nor*
:nn[oremap] {lhs} {rhs} |mapmode-n| *:nn* *:nnoremap*
:vn[oremap] {lhs} {rhs} |mapmode-v| *:vn* *:vnoremap*
:xn[oremap] {lhs} {rhs} |mapmode-x| *:xn* *:xnoremap*
:snor[emap] {lhs} {rhs} |mapmode-s| *:snor* *:snore* *:snoremap*
:ono[remap] {lhs} {rhs} |mapmode-o| *:ono* *:onoremap*
:no[remap]! {lhs} {rhs} |mapmode-ic| *:no!* *:noremap!*
:ino[remap] {lhs} {rhs} |mapmode-i| *:ino* *:inor* *:inoremap*
:ln[oremap] {lhs} {rhs} |mapmode-l| *:ln* *:lnoremap*
:cno[remap] {lhs} {rhs} |mapmode-c| *:cno* *:cnor* *:cnoremap*
:tno[remap] {lhs} {rhs} |mapmode-t| *:tno* *:tnoremap*
there does not seem to be an option for what you are looking for.

Related

Mapping Alt+n to pagedown in vim

I want to map the Alt+n key combination in insert and escape mode to pagedown (moving down by large amount of lines) .
I have tried adding following lines to .vimrc file but not working.
:map <M-n> <PageDown>
:map <A-n> <PageDown>
:imap <M-n> <PageDown>
:noremap <A-n> <PageDown>
Is there some way I can map Alt+(some alphabet) (not a system key binding) to other key in vim ?
I found the solution afterwards at https://vi.stackexchange.com/questions/2350/how-to-map-alt-key .
When Alt+alphabet is pressed, characters sent by the keyboard are ^[+key , so we first map the Alt+key to it's corresponding equivalent and then use noremap.
For example to map Alt+n to pagedown, this will word
execute "set <M-n>=\en"
nnoremap <M-n> <PageDown>

How to map <c-leader> in vim?

I would like to map ctrl+leader key. Is it possible?
Tried: :nnoremap <c-leader> :CtrlP<CR>
And it does not work.
(ctrlp bindings conflict with yankring bindings)
<Leader> is a special key notation in Vim; as such, it cannot be combined with modifiers such as C-. Assuming the default setting for it (i.e. \), you can use this:
nnoremap <c-\> :CtrlP<CR>
There are two issues, here:
You didn't read CtrlP's documentation where you would have found this:
Use this option to change the mapping to invoke CtrlP in Normal mode:
let g:ctrlp_map = '<c-p>'
<leader> is supposed to be a cross-platform alternative to using the common modifier keys (Alt, Ctrl, Shift, Cmd) in mappings.
Normally, you would use <leader> in place of <Ctrl> as in:
nnoremap <leader>p :CtrlP<CR>
This line in your ~/.vimrc will probably solve your problem:
let g:crtlp_map='<F11>'
Though it won't help much here are my mappings for CtrlP:
nnoremap <leader>f :CtrlP<CR>
nnoremap <leader>b :CtrlPBuffer<CR>
nnoremap <leader>m :CtrlPMRUFiles<CR>
nnoremap <leader>t :CtrlPTag<CR>
For example to map leader key to space try this ...
let mapleader=" "

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 do I configure matchit.vim to use <tab> instead of %?

I'm a big fan of the matchit.vim plugin, but I prefer to jump between matching delimiters with the <tab> key. However, it seems that matchit is hard-coded to activate when pressing the % key.
My first thought would be that I would simply put this line in my .vimrc, and change '%' to '<tab>', thus binding the Match_wrapper call to the tab key:
nnoremap <silent> % :<C-U>call <SID>Match_wrapper('',1,'n') <CR>
However, this doesn't seem to work; I'm guessing it has got something to do with the <SID> (which as far as I understand is an ID unique to the script?) or the fact that Match_wrapper is script-local. (I'm pretty new to Vimscript)
Thus far I've managed to get by mapping <tab> to % with 'nmap', but it's a pretty fragile hack.
Anyway, any help would be greatly appreciated! :)
Well, if you know that % will always be remapped, then using
map <Tab> %
is safe (absence of n in front is intentional: % is defined in all modes covered by :map). But what you can always do is to replace <SID> with <SNR>{N}_ where {N} is the number of the matchit script in the outputs of :scriptnames. In a newer vim you can also use maparg('%', 'n', 0, 1), it will output a dictionary that among other values contains lhs and sid. In this case code may look like this:
for s:mode in ['n', 'v', 'o']
let s:map=maparg('%', s:mode, 0, 1)
execute s:mode.'noremap <Tab> '.substitute(s:map.lhs, '<SID>', '<SNR>'.s:map.sid.'_', 'g')
endfor
In this case
for s:mode in ['n', 'v', 'o']
execute s:mode.'noremap <Tab> '.maparg('%', s:mode)
endfor
is also acceptable as “old” (without fourth argument) behavior of maparg is to expand <SID>.
Here's what I did:
" <C-I> and <TAB> are the same thing.
" So, I changed <C-I> to <C-O><C-I> and <C-O> to <C-O><C-O> to match.
" I didn't want to lose the <C-I> jump functionality.
noremap <C-O><C-O> <C-O>
noremap <C-O><C-I> <C-I>
" This is what the plugin sets on %. I just set it on <TAB>
onoremap <TAB> :<C-U>call <SNR>41_Match_wrapper('',1,'o')<CR>
nnoremap <TAB> :<C-U>call <SNR>41_Match_wrapper('',1,'n')<CR>
vnoremap <TAB> :<C-U>call <SNR>41_Match_wrapper('',1,'v')<CR>m'gv``
Or, just in case, you can also use these mapping (tested with Vim 8.0):
nnoremap <silent> <Tab> :normal %<CR>
xnoremap <silent> <Tab> :normal %<CR>m`gv``

Resources