How do I swap two lines in vim? - vim

I have this:
pick 887b66f add 222 Dziewiecsil to flowers new title
pick dc331cb new name of beginning commit
And I want to get this:
pick dc331cb new name of beginning commit
pick 887b66f add 222 Dziewiecsil to flowers new title
Is there a way to do this in a quick way using keyboard shortcuts?

To swap the current line with the next one, type ddp while in command mode.
dd - delete line (actually called cut in other editors) and save it in register
p - paste line from register

dd deletes the current line, then you can paste the removed line using p. There's another way though using m. With m you can move lines around i.e.
:m 1 will move the current line after line 1
:m 0 will move the current line to top
:m $ will move the current line to bottom
In your example, place the cursor in the first line and type :m $
More info: http://vim.wikia.com/wiki/Moving_lines_up_or_down

Example:
1. one
> 2. two
with :m-2, switch (current line - 2)
> 2. two
1. one
with :m+1 switch (current line + 1)
1. one
> 2. two
You could map this if you want.

Despite the fact that question is quite old and marked as answered, I'd like to extend the answer by saying that you can use normal mode commands, which were provided by Sven Marnach with nnoremap like so:
:nnoremap <C-Up> <Up>ddp<Up>
:nnoremap <C-Down> ddp
This will allow you to move lines with Ctrl + Up and Ctrl + Down within your file. However this will overwrite #" register, which stores your last copied string/word/letter/etc. So by adding "(reg) before dd and p commands we can fix this:
:nnoremap <C-Up> <Up>"add"ap<Up>
:nnoremap <C-Down> "add"ap
Here we add "a before delete and paste commands to store our line in #a register, so your default copy register will not be overwritten. However it may overwrite contents of #a register (who knows, but you may use it for something important in your use-case, but this step bit paranoid, you can skip it if you want to), let's fix that too:
:nnoremap <silent><C-Up> :let save_a=#a<Cr><Up>"add"ap<Up>:let #a=save_a<Cr>
:nnoremap <silent><C-Down> :let save_a=#a<Cr>"add"ap:let #a=save_a<Cr>
(<silent> needed to prevent echoing our commands to message-line at the bottom.)
Now we have two mappings which allow us to move lines within the file with keyboard shortcuts. You can redefine buttons, I use Alt + j/k, which would be <A-j> and <A-k> for those commands. However not all terminal emulators support Alt key mappings AFAIK.

The mappings proposed in the Vim wikia page are actually the best way to map key combinations that emulate the way Sublime and other editors implement this feature.
This includes an indentation action after the move, which is also great (that's the double equal == signs, in case you don't want that).
It also supports visual and insert modes, so that you can move lines while editing or with fulblocks.
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
I personally mapped them to <D-J> and <D-K> on my Mac, instead of <A- which maps to the Alt key. That way I use Cmd + Shift + j/k, which feels more natural to my fingertips.

Related

Is there a way to copy a selected area up or down in vim?

In VSCode you can copy and paste selected lines of text up or down using Alt+Shift + Up or Down.
I switched to vim a few months ago, and I really miss this feature.
I found out you can move selected lines in visual mode up or down using these visual mode bindings,
vnoremap J :m '>+1<CR>gv=gv
vnoremap K :m '<-2<CR>gv=gv
but it'd be great if you could copy and paste up and down as well without using yy and p because when you're done yanking, the cursor is placed at the initial position, exiting visual mode and reducing productivity.
Well, that, here, is the problem with copying and pasting random snippets from the internet without understanding what they do: they are little black boxes that one can't modify or extend at will by lack of knowledge.
Let's deconstruct the first mapping:
vnoremap J :m '>+1<CR>gv=gv
:[range]m {address} moves the lines covered by [range] to below line {address}. Here, the range is automatically injected by Vim: '<,'> which means "from the first line of the latest visual selection to its last line", and the address is '>+1, meaning "the last line of the latest visual selection + 1 line". So :'<,'>m '>+1<CR> effectively moves the selected lines below themselves,
gv reselects the latest visual selection,
= indents it,
gv reselects it again for further Js or Ks.
Now, we want a similar mapping but for copying the given lines. Maybe we can start with :help :m and scroll around?
Sure enough we find :help :copy right above :help :move, which we can try right away:
xnoremap <key> :co '>+1<CR>gv=gv
Hmm, it doesn't really work the way we want but that was rather predictable:
the address is one line below the last line of the selection,
the selection is reselected and indented, which is pointless.
We can fix the first issue by removing the +1:
xnoremap <key> :co '><CR>gv=gv
and fix the second one by selecting the copied lines instead of reselecting the latest selection:
xnoremap <key> :co '><CR>V'[=gv
See :help :copy and :help '[.

Is there a native way to shift text vertically in Vim while exchanging with an adjacent line?

Consider the following text file:
--> Foobar
Barfoo
I would like to transform this text to
Foobar
--> Barfoo
There are several ways to do this. One possibility is to use REPLACE mode to overwrite the first line with three spaces, and then use REPLACE mode.
However, I'm wondering if there's a native way to select the array text (maybe in visual block mode) and pull it down to an adjacent line.
After learning about visual re-selection (gv), I figured out how to do this in a way that generalizes to any kind of visual selection (the first step is different depending on what one wants to select and move).
Select the block visually: 0vf>
Yank the block into a register: y
Re-select the block: gv
Replace all the text with a space character: r[Space]
Move down a line: j
Enter Replacement mode with [Shift]R.
Paste the register contents [Control]R"
I recorded this as a macro and it works reasonably well.
While sticking to native vim has it merits, sometimes it's not worth being such a purist. Visual blocks are one area worth enhancing with plugins. In your case, I recommend vim-schlepp based on Damian Conway's dragvisuals.vim plugin which makes dragging and duplication of visual blocks a joy. For more ideas on visual block plugins, just watch Conway's demo here.
You could use a binding:
nnoremap <silent> <A-j> :m .+1<CR>==
nnoremap <silent> <A-k> :m .-2<CR>==
inoremap <silent> <A-j> <Esc>:m .+1<CR>==gi
inoremap <silent> <A-k> <Esc>:m .-2<CR>==gi
vnoremap <silent> <A-j> :m '>+1<CR>gv=gv
vnoremap <silent> <A-k> :m '<-2<CR>gv=gv
With this bind, you can use Alt + j and Alt + k to move a line up or down in normal and visual mode(for multiple lines).
This binding was taken from the Vim Wiki.

vim move a block of selected code up or down

There is a way to move highlighted code up or down with arrow keys. Even the indentation would be correct on dropping the block.
For the life of me I do not remember how to do it.
Can someone please tell me how to do it.( suitably embarrassed asking this).
Here's the link that'll help you
link
You can move a line, or a block of lines, with the :m command. Examples:
:m 12 move current line to after line 12
To move a block of lines, use the same command but visually select the lines before entering the move command. You can also use arbitrary ranges with the move command. Examples:
:5,7m 21 move lines 5, 6 and 7 to after line 21
why not use d+p if you had chosen the block code
If you want to do it with arrow keys, you can try Tim Pope's vim-unimpaired plugin, which you can find on Github.
Then you can use mappings similar to these (except map them to whatever keys you like).
" ^U moves lines up, ^D moves lines down.
" Works in normal or visual select modes.
nmap <C-u> [e
nmap <C-d> ]e
vmap <C-u> [egv
vmap <C-d> ]egv
Cutting a block of text in visual mode and then pasting:
Go to command mode by pressing Esc if you're not already in it
Move to the start or end of where you want to go
Press V to switch to visual mode
Move with arrows or H,J,K,L to the other end of the block you want to move
Press D to cut it, it will switch back into command mode
Move to where you want to put it and press P to paste what you cut
It seems like a lot of steps but it's just a verbose explanation.
Here is my configurations, There is a nice configuration that I am using to map Ctrl+J to move a block of code up and Ctrl+K to move a block down. I am using currently NVIM but I think the same configuration setting is applicable for VIM as well.
Setting on NVIM
The location that I am using on macOS Catalina for the NVIM is located at:
.config/nvim/init.vim
nnoremap K :m .-2<CR>==
nnoremap J :m .+1<CR>==
vnoremap K :m '<-2<CR>gv==gv
vnoremap J :m '>+1<CR>gv=gv
for vim I think you can change the setting on
.vimrc located under the home directory.

How can I move a selection of lines 1 line down? [duplicate]

This question already has answers here:
Move entire line up and down in Vim
(21 answers)
Closed 8 years ago.
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
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.

Vim: how to create key mapping to :edit and jump to last line?

I mapped key F2 to refresh (:edit) currently opened file. I'm using this when watching a log file to update the screen when file has been updated outside (new lines added at the end of a log file).
nnoremap <silent> <F2> :edit<CR>
I would like to jump to the end of the file after it has been refreshed.
How do I create key mapping which does :edit and jump to end of the file (shortcut G) at the same time?
An idiomatic way to position the cursor in the just opened (or reopened) file
is to use the +-argument of the :edit command (see :help +cmd).
Although the general syntax allows to execute any command, there are special
cases for navigating to a certain line by a pattern matching text on that line
(+/ followed by the pattern), or by a line number (+ followed by the
number). If the number is omitted in the latter form, it is assumed to be the
last line of the file.
In such a way, to reload the current file positioning the cursor on the last
line, one can use the command
:edit +$
or
:edit + %
It is possible to shorten these commands by using :e instead of :edit and
leaving out an optional space before the +-argument.
:e+$
or
:e+ %
The corresponding mappings would take the form
:nnoremap <silent> <F2> :edit +$<CR>
and
:nnoremap <silent> <F2> :edit + %<CR>
Note that this +-argument syntax is also valid for opening a file from the
command line, so
$ vim + filename
works as well.
This is what I'd use:
nnoremap <silent><F2> :edit<bar>$<CR>
You can chain commands in a map by using <bar>. This mapping does what you want:
:nnoremap <silent> <F2> :edit <bar> :normal! G<enter>
It's important to use normal! instead of normal in mappings/scripts because the prior will not take user defined mappings into account. Even if there is a mapping for G in this case, vim will treat G as if it were not mapped at all.
You can use :normal to use the normal-mode G motion:
:nnoremap <silent> <F2> :edit<CR>:norm! G<CR>
Perhaps better would be to use the :$ command to go to the end of the file:
:nnoremap <silent> <F2> :edit<CR>:$<CR>
In Vim '|' can be used to separate commands, much like many flavors of Linux/Unix. For more information about the use of the bar check out :help bar
Example:
:edit | normal! G
If you wish to use this in a key mapping You may find that your ~/.vimrc doesn't like maps utilizing |, or \|. In order to make this work use the equivalent <bar> instead.

Resources