Bloerg
       

Shift lines and selections faster with vim-move

One of my students showed me a cool Sublime Text feature that made editing a bit more efficient than Vim: Instead of moving lines by deleting them with dd, jumping to the desired location and pasting them, he just had to press a key combination. Because it looked so intuitive, I had to figure out how to emulate that with Vim.

First thing I stumbled upon and never knew before, is the :m[ove] command. It takes a range (or the current line) and moves the lines in that range to some target “address”. The simplest possible movement is the :m+1 shortcut, that swaps the current line with the one right below. Typing the command manually is a chore but mapping that command and its inverse :m-2 is pretty straightforward once you take care of the top and bottom boundaries. Moving whole selections up and down is more interesting. Fortunately, you can get easily retrieve selected range in a function and adaptively call :m.

To make these mappings more manageable, I wrote a simple but pretty effective plugin called vim-move. Put the matze/vim-move repo into your Vundle bundle and this is what you get:

2013-08-10/play-demo.png

By default, alt+k and alt+j move the current line in normal mode1 whereas ctrl+k and ctrl+j shift a selection in visual mode. You can prefix the calls with a count, e.g. 5ctrl+j which will then shift the line or selection relative by that number. To remap the keys you should

let g:move_map_keys = 0

and then map the keys, for example

vmap <C-j> <Plug>MoveBlockDown
vmap <C-k> <Plug>MoveBlockUp
nmap <A-j> <Plug>MoveLineDown
nmap <A-k> <Plug>MoveLineUp

Hope you like the plugin. If you have any suggestions or problems, open an issue on the issue tracker.

  1. In some environments I have to use the GNOME terminal and need to re-map the normal mode keys because I am not able to stop the terminal from intercepting the alt key. If you know how to let the GNOME terminal use the alt key, I’d pay you a beer. Update: you can keep your wallets closed ;-)

Discussion

Dario
Sun, Sep 01 2013

Hi Matthias,

I recently installed your Vim plugin ‘vim-move’ v1.2 and I find it very nice and useful. It generally works pretty well, although I have stumbled into an small glitch when editing read-only files ( http://ge.tt/9Ycxviq/v/0 ) .

I hope you can fix it in the following versions.

Thank you very much !!!

Matthias
Sun, Sep 01 2013

Hi Dario,

thanks for pointing that issue out. I will fix it ASAP and update the plugin.

Dario
Sun, Sep 01 2013

It seems you’re disabling the plugin for read-only files … that’s a real pity …

I regularly update read-only files with Gvim saving changes with ‘:w!’ … it probably isn’t very orthodox, but it’s helpful. I guess there are considerable technical obstacles to adapt the plugin for this kind of files.

Is it very serious the problem in version 1.2 ? …. I am considering staying in that version if the actual bug is not very dangerous. Am I loosing any kind of INTEGRITY ?

Thank you Matthias.

Matthias
Sun, Sep 01 2013

Yes, I was a bit shortsighted with that change. The latest commit silences the :m commands which in turn will not let the plugin throw an error when a warning is encountered.

In any case, the “bug” was not really a bug. Any change to a read-only file causes Vim to output a warning the first time a change is made. If a warning happens inside a function, it will throw an error, so no harm to be done.

Dario
Sun, Sep 01 2013

Uh !!

That sounds much better !!

I appreciate that.

Sudharshan
Mon, Jan 27 2014
nmap <A-j> MoveLineDown
nmap <A-k> MoveLineDown

The above line must be corrected to

nmap <A-k> MoveLineUp
Matthias
Mon, Jan 27 2014

Thanks for the hint, I’ll correct that.

anon
Sun, Mar 09 2014

No need for a plugin, it should work the same way:

nnoremap <A-j> :m .+1<CR>==
nnoremap <A-k> :m .-2<CR>==
inoremap <A-j> <Esc>:m .+1<CR>==gi
inoremap <A-k> <Esc>:m .-2<CR>==gi
vnoremap <A-j> :m '>+1<CR>gv=gv
vnoremap <A-k> :m '<-2<CR>gv=gv

http://vim.wikia.com/wiki/Moving_lines_up_or_down#Mappings_to_move_lines

Matthias
Sun, Mar 09 2014

Yes, you can use these mappings to achieve a similar effect, however, there are some corner cases that the plugin fixes: 1) moving to the top or bottom gives an error because the target address is invalid (okay, that one could probably silence), 2) the mappings fail with a count argument and 3) I can easily move half-page wise.

PierreR
Sun, Apr 06 2014

In Sublime Text you can move one line or a selected block with the same key binding (c-s-up and c-s-down).

Is this possible in gvim (in vim terminal it looks tricky to map c-s-up/down apparently)

PierreR
Sun, Apr 06 2014

Ok forget about my previous comment. You can just map both c-s-down to MoveBlockDown and MoveLineDown for instance.

Post a comment

Name required

E-mail required, not published

Website optional

Comment Markdown accepted


This post might also have some comments at Google+.