Alexei Danchenkov
Alexei Danchenkov

Reputation: 2082

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?

Upvotes: 35

Views: 24091

Answers (9)

Apiwat Chantawibul
Apiwat Chantawibul

Reputation: 1463

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

Upvotes: -1

Trevi&#241;o
Trevi&#241;o

Reputation: 3528

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

Upvotes: -1

elwint
elwint

Reputation: 34

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.

Upvotes: 1

ericbn
ericbn

Reputation: 10948

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

Upvotes: 36

Gijs
Gijs

Reputation: 434

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.

Upvotes: 3

RubenCaro
RubenCaro

Reputation: 1466

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.

Upvotes: 34

escrafford
escrafford

Reputation: 2393

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.

Upvotes: 19

trev9065
trev9065

Reputation: 3501

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.

Upvotes: 1

mike3996
mike3996

Reputation: 17497

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

Upvotes: 17

Related Questions