Mapping <Shift>-Arrows to selecting characters/lines - vim

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

Related

How to remap arrow keys in Vim in insert mode?

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>

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>

Move visually selected text to end of line

How to move visually selected text to end of line, which command or keys I should use?
e.g. /text3<CR> note that ** is a selected text, not part of it.
**text3** text1 text2
**text3** text1 text2
and move to this:
text1 text2 **text3**
text1 text2 **text3**
I tried: :%s/\(text3\)\(.*\)/\2 \1/ any other ways to do it?
Basically you can do it (after selecting your text visually like put the cursor on your word then hit viw) with d$p. Any you can create a macro for it, I used to go with something like this in simillar cases: qq/SEARCHTERMENTERviwd$pj0q. Now you can execute it as NUMBER(s)#q.
But as a more general solution:
:%s_\(YOUR_TEXT_TO_MOVE_TO_THE_EOL\)\(.*\)_\2\1
Should work just fine.
You could use the :global command to select lines with the matching pattern and :normal to operate on those lines. For example:
:g/^text3 /norm! dt p d0$p
Explanation
:g/^text3 /<command>
Runs the specified <command> on all lines starting with text3 followed by a space. See :help :global for more information.
norm!
Executes the following commands in normal mode. See :help :normal.
dt p d0$p
Delete to the first space, paste that after said space, move forward one character and delete to the beginning of the line. Move to the end of the line and paste.
You can use Damian Conway's dragvisuals.vim
After installation add the following (uncommented) to your .vimrc
runtime plugin/dragvisuals.vim
vmap <expr> <LEFT> DVB_Drag('left')
vmap <expr> <RIGHT> DVB_Drag('right')
vmap <expr> <DOWN> DVB_Drag('down')
vmap <expr> <UP> DVB_Drag('up')
vmap <expr> D DVB_Duplicate()
" Remove any introduced trailing whitespace after moving...
let g:DVB_TrimWS = 1
Or, if you use the arrow keys for normal motions, choose four
other keys for block dragging. For example:
vmap <expr> h DVB_Drag('left')
vmap <expr> l DVB_Drag('right')
vmap <expr> j DVB_Drag('down')
vmap <expr> k DVB_Drag('up')
Or:
vmap <expr> <S-LEFT> DVB_Drag('left')
vmap <expr> <S-RIGHT> DVB_Drag('right')
vmap <expr> <S-DOWN> DVB_Drag('down')
vmap <expr> <S-UP> DVB_Drag('up')
Or even:
vmap <expr> <LEFT><LEFT> DVB_Drag('left')
vmap <expr> <RIGHT><RIGHT> DVB_Drag('right')
vmap <expr> <DOWN><DOWN> DVB_Drag('down')
vmap <expr> <UP><UP> DVB_Drag('up')
To use
Select with visual mode and move the block with h, l, j or k etc.
The solutions involving iw will work if the text is text3, but they will fail on two words.
None of the methods involving $p will add a space, as your :s command does. You could use A <C-R>"<Esc> instead.
If you want to do it on a single line, and the text is already selected in Visual mode, then x$p is pretty easy.
If the text is "selected" in the sense that you have just searched for it, and it is highlighted with the Search highlight group, and you want to make the change on a single line, then you could use d/<C-R>//e<CR>$p. The <C-R>/ will be replaced by the current search pattern, so you will get something like d/text3/e<CR>$p.
If you want to do it on all matching lines in the buffer, then a slight simplification of your solution is
:%s/\v(<C-R>/)(.*)/\2 \1
:help i_CTRL-R
:help c_CTRL-R
:help /\v

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

easier way to navigate between vim split panes

I am using NERDTree on vim and usually open files with i
Is there an easy way to switch between different panes? Currently I use CTRL+W+W to move from one pane to another.
Long ago I found a tip (once on vim.org, now on wikia, apparently) that I've stuck with. Remap ctrl-[hjkl] to navigate splits. It has served me well.
" Use ctrl-[hjkl] to select the active split!
nmap <silent> <c-k> :wincmd k<CR>
nmap <silent> <c-j> :wincmd j<CR>
nmap <silent> <c-h> :wincmd h<CR>
nmap <silent> <c-l> :wincmd l<CR>
I prefer hitting single keys over hitting key-chords. The following maps pane movement to arrow keys:
" Smart way to move between panes
map <up> <C-w><up>
map <down> <C-w><down>
map <left> <C-w><left>
map <right> <C-w><right>
I know this is an old question, but I have a perfect way. Using the number of the split.
split_number C-w C-w
The panes are numbered from top-left to bottom-right with the first one getting the number 1.
for example to go to split number 3 do this 3 C-w C-w, press Ctrl-w twice.
Key mappings are definitely the way to go. I use the mappings mentioned by overthink. I also include the following mappings in my vimrc to move the splits themselves.
" Move the splits arround!
nmap <silent> <c-s-k> <C-W>k
nmap <silent> <c-s-j> <C-W>j
nmap <silent> <c-s-h> <C-W>h
nmap <silent> <c-s-l> <C-W>l
This makes it so that if the split opens in the wrong spot (lets say the left side and I want it on the right) I go to that split and hit <C-S-l> and the split moves where I want it to.
In order to be consistent with changing tabs via gt & gT, I'm currently trying out the g mappings for changing splits. I tend to hit the shift key as I go for the Ctrl key so this helps me avoid that mistake until I get better at not doing so.
nnoremap gh <C-W><C-H>
nnoremap gj <C-W><C-J>
nnoremap gk <C-W><C-K>
nnoremap gl <C-W><C-L>
I have mapped ctrl+w ctrl+w to <tab> (under normal mode as in normal mode tab does not have any use)and that's have made my life easier as now I can switch between panes easily by pressing <tab>.
For switching to a particular pane, I can press <i> + <tab> to switch between panes as split window panes also got their own number which can replace i.
Ex. i = 1,2...n.
Very easy way of achieving it. Type this shortcut twice, and that should work
ctrl+w ctrl+w

Resources