0

I'm trying to create maps for moving the selection up or down. Moving all selected lines 1 line up is easy:

vnoremap <silent> <M-k> :m--<CR>gv

But moving the lines downwards isn't as easy. The move command requires the same amount of "+" as the amount of lines moved. If I have 10 lines selected, I have to write :m++++++++++ to move them down once.

Alternatively I could write :m line("'>")+1 or in other words, "move selection to the line below the last line in the selection". Unfortunately it just results in "E14: Invalid address" for some reason.

I can't use :exec ... to build a command because I just get "E481: No range allowed" because Vim automatically inserts :'<,'> when I hit colon and I don't know how to prevent that.

Any ideas? I just want a map to move the selected lines down once.


Edit: Thanks to the :<C-u> trick in the accepted answer, I now have these 4 key binds that appear to work perfectly:

" Move lines
nnoremap <silent> <M-j> :m+<CR>
nnoremap <silent> <M-k> :m--<CR>
vnoremap <silent> <M-j> :<C-u>exec "'<,'>m " . (line("'>") + 1)<CR>gv
vnoremap <silent> <M-k> :m--<CR>gv
Hubro
  • 56,214
  • 69
  • 228
  • 381

1 Answers1

3

First of all, you don't need to implement this yourself, the Transposing page on the Vim Tips Wiki covers this and also has links to several plugins that provide such mappings.

The key to handling the move down in visual mode is indeed to use the '> mark. However, you indeed need to use :execute to get that result to the :move command.

The '<,'> added range in the visual mode mappings can be cleared by starting the right-hand side with :<C-u>execute ...; this is a well-known idiom.

If you want to learn more, have a look at some of the plugins' implementations.

Ingo Karkat
  • 167,457
  • 16
  • 250
  • 324