How to yank the current line and the line above it in Vim? - vim

What I need is to yank the current line and the line just above it.
For instance, in the following example:
3 My test line
4 Line above current line
5 My current line |(cursor)
6 Line below current line
How do I yank lines 5 and 4 when my cursor is located on line 5?

yk should do it, as in Yank in the direction of up one line, since y will accept the next keystroke as a motion, and k alone represents motion up one line.
If you need your cursor to return to its original position, just add a j as ykj. You will probably see the cursor move inelegantly on screen, but it gets the job done.

For this simple case, yk will do the trick. This is yank followed by a motion of up one line.
Generally, use yNk, e.g. y3k to yank the current line and the preceding 3 lines.
If you need to return to the cursor position after the yank, set a mark and return to the mark after the yk:
mmyk`m
If you need only remain on the same line where you began the yank, not the same cursor position, ykj is shorter.

In addition to the Normal mode commands already mentioned in other answers,
one can use the :yank Ex command on a corresponding range of lines. For
example, to copy the current line along with the line above it (without moving
the cursor) run
:-,y

Related

VIM: Why is the dot operator working differently?

I want to understand what gets stored in Vim's dot(.) register.
Consider the following text:
This is Line one
This is Line two
This is Line three
With the cursor on the first line, if I do A;<esc> I can repeat the same action for the next line by j.
However, if I do the action like removing the last character on the first line by $x and then try to repeat it for the next line by j., it is not removing the last character of the line, instead it just deletes the character under the cursor.
So why is dot command able to remember the position in the first example A;<esc> whereas not able to do the same for $x ?
From :help .:
. Repeat last change, with count replaced with [count].
Also repeat a yank command, when the 'y' flag is
included in 'cpoptions'. Does not repeat a
command-line command.
With A;, the change is to insert a ; at the end of the current line. A moves the cursor and switches to insert mode.
With $x, the $ first moves the cursor, then the x command deletes a character. They are not linked together, so the change is only the deletion of the character at the current cursor position.
(Put another way, the motion is only part of the change if the command takes a motion operator after the command, like d, or if the motion is implicit in the command, like with A.)

In Vim, can I move a line to current line without leaving the current line?

The title says it all: is there a way in Vi(m) to move a line, by number, to my current line?
I could move to my source line first, then use the :m command to move that line. But that involves leaving my target line. Or, I could :Nd, but that also moves me off of my current line and on to the deleted line number N.
It's frustrating looking at a line and thinking "move here" and not knowing how :D.
:3m . moves line 3 to your current line.

What is the best way to refactor a Ruby ‘if’ statement into one-line shorthand form in Vim?

I have the following Ruby code:
if some_cond && another
foo_bar
end
and I want to change it to:
foo_bar if some_cond && another
What are the most idiomatic ways to do that in Vim?
Assuming that the cursor is located at the if-line prior to
refactoring (not necessarily at the beginning of that line),
I would use the following sequence of Normal-mode commands:
ddjVpkJ<<
or this chain of Ex commands:
:m+|-j|<|+d
Here the if-line is first moved down one line by the :move + command.
The :move command cuts a given range of lines (the current line, if
not specified) and pastes it below the line addressed by the argument.
The + address is a shorthand for .+1 referring to the next line
(see :help {address}).
Second, the line containing the body of the conditional statement is
joined with the just moved if-line. The :join command concatenates
a given range of lines into a single line. The - range is a shortened
form of the .-1 address referring to the line just above the cursor
(see :help {address}).
Third, the newly joined line is unindented by one shiftwidth using
the :< command.
Finally, the remaining end-line, which can now be addressed as +,
is removed by the :delete command.
I see few (probably non-optimal) solutions:
cursor in first character in first line:
D - remove if condition but leave cursor in same position (don't delete line)
J - join next line to current
A <Space> <ESC> - append space and exit to Normal mode
p - paste if condition
and then remove remaining end with jdd
cursor in first character in first line, as previously:
j - move to next line
dd - remove this line
k - move back to if condition
P - paste removed line before actual line, cursor should be placed to pasted line
J - join next line to current
== or << - unindent current line
and then remove remaining end with jdd
another solution:
j - move to second line
JD - join line with next, remove what was joined
dd - remove current line
k - step to previous line
PJ<< - paste, join and unshift
It's probably not optimal, but I do it without thinking, because most of this commands are in my muscle memory (you don't think how to move around you, how to yank/delete and paste most of the time, and joining line is also helpful to remember).
If you have virtualedit enabled in config, instead of A <Space> <Esc> you can $ <Space>, but I find $ harder to use than A followed by Ctrl-[ (it's simmilar to ESC).
As an advice: if you use some upper letter commands, try to chain them if it's possible, so you only need to keep Shift pressed and then execute some commands, instead of mixing upper and lower letter commands and pressing two keys at a time (upper letter is 2 key press, one is Shift). Once I found combo helpful for restarting server in console Ctrl+cpj, which sends Ctrl+c, Ctrl+p (previous command) and Ctrl+j (Enter key) with single Ctrl press. Since then I try to find simmilar time-saving combination in Vim too mostly with Shift, as Ctrl is not much used in Vim.
Yet another way:
ddpkJjdd
ddp swap the two lines
kJ move up and join the lines
== re-indent the line
jdd move down and delete the last line
There are probably 30 ways to do this.
Here is one, assuming you are starting from the end of the word end in normal mode:
dd (delete last line)
"aD (delete and copy foo_bar to buffer a)
dd (delete now-empty line 2)
"aP (paste from buffer a before caret)
aSpaceEsc (insert space and return to normal mode)
Again, "properly" rarely applies in Vim because there are so many ways to accomplish something. This is so small a change that even re-typing foo_bar could be justifiable.

move cursor to next line after input from filter command in vim

In vim I filter, say the current single line, using !! through a Unix command. To achieve this I defined the following shortcut in .vimrc
:map <Enter> !!mycommand<CR>:,+1<CR>
Pressing <Enter> this takes me to the line below the current if mycommand replaces my single input line be exactly one output line. If the output has more lines (number of lines unknown before command execution) it will still take me to the line below the current.
Now, I would like to know how I can always get to the first line below the inserted output of mycommand.
The modified shortcut would then allow me to 'execute' the text file line by line using just <Enter> displaying the output each time.
If there is no way to do this without any previous knowledge of the output of mycommand, maybe there is one knowing say the first character of each output line.
Thanks a lot!
You can use the special marks '[ and '], which mark the start and end of the last changed (or yanked) text. Change your map to:
:map <Enter> !!mycommand<CR>']+
Note that I'm using + in place of your ex command. This will jump to the first non-blank character in next line. If that's not what you want, you may try simply j or, use a shorter version of your original map:
:map <Enter> !!mycommand<CR>']:+1<CR>
You don't really need the comma, to make this a range. This command is just a simplified :#, where # is a line number to jump. Here you can use . meaning "current line", and then :.+1 moves to the next line. But you can omit the dot, and that's why :+1 does the same.

Vim: Replacing a line with another one yanked before

At least once per day i have the following situation:
A: This line should also replace line X
...
X: This is line should be replaced
I believe that I don't perform that task efficiently.
What I do:
Go to line A: AG (replace A with the line number)
Yank line A: yy
Go to line X: XG (replace X with the line number)
Paste line A: P
Move to old line: j
Delete old line: dd
This has the additional disadvantage that line X is now in the default register, which is annoying if I find another line that should be replaced with A. Yanking to and pasting from an additional register ("ayy, "aP) makes this simple task even less efficient.
My Questions:
Did I miss a built-in Vim command to replace a line yanked before?
If not, how can I bind my own command that leaves (or restores) the yanked line in the default register?
Vp: select line, paste what was yanked
What I would do :
36G (replace 36 with the line number you want to go to)
Y
70G (replace 70 with the line number you want to go to)
Vp
You don't have to leave normal mode, but it does yank the line. You can however use V"0p which will always put the line yanked in step 2.
This has the additional disadvantage
that line X is now in the default
register, which is annoying if I find
another line that should be replaced
with A.
To delete text without affecting the normal registers, you can use the Black hole register "_:
"_dd
Building on the answers that suggest using Vp or VP to paste over a line -- to avoid changing the contents of the yank register I find the most ergonomic command is simply:
VPY
yy
j (move to the line you want to replace),and then
Vp (uppercase v and then p, will replace with the yanked content)
I would use commandline (Ex) mode and do the following two commands
:XmA
:Ad
This simply moves line X to just under A, then deleting A moves that line up
For example
:7m3
:3d
Move to the start of the first line.
y, $ – copy the line without the linebreak at the end
Move to the start of the target line.
V, p – replace just one target line
c, c, Ctrlr, 0, Esc – replace the target line with the original yank
Move to the start of the next target line.
. – repeats the command issued at 4.2.
Notes:
4.1 is y, $ because if you do y, y or Y you will copy the linebreak, and Ctrlr, 0 actually adds the linebreak below your target line.
4.2 replaces V p, which doesn’t work with repeat because technically the last action is delete, so . would just delete a line.
If anyone knows how to issue ‘replace current line with register’ from EX mode (command line), I would like to hear from you (and to know where you found the documentation). There may be a repeatable EX command which is faster than 4.2 and/or does not have the linebreak caveat.
You can also do:
Vy (in normal mode at the line you want to copy)
Vp (in normal mode at the line you want to replace)
Doesn't create spaces or line ends.
Cursor is placed at the start of the copied text.
The same keys can be used to yank/paste more than one line.
V (in normal mode at what you want to yank)
(use jk to move the selection)
y (to yank the selection)
V (in normal mode at where you want to paste)
(use jk to move the selection)
p (to replace the selection with the yanked lines)
Here's what I would do
Move beginning of line A, AG (where A is a line number obviously)
Yank line to some register, e.g. a (without new line). Type "ay$
Move to insert line, XG
Substitute line, S
Insert from register a, Ctrl-Ra
You can use this with visual mode.
Go to line A: AG
Select the line with visual mode: VESC
go to line X: XG
Enter substitute mode for the line: S
Paste the line you copied: shift+insert (or whatever other you mapping you have for pasting from the clipboard).
In light of the recent comment by cicld (thank you!), I see that I didn't grasp the original issue fully. Moving the line is not appropriate, but copying is (since the line is yanked.) So I would revise it to:
:1t20:20d_
Copy the 1st line (:t command is an alias for :copy) after line 20 (will place it on line 21)
Delete line 20, putting the deleted line into the 'blackhole' register (_) (i.e. not affecting the current yank buffer)
As mentioned in the recent comment, this will not affect the current cursor position.
You can use this commands in Normal Mode:
:AmX | Xd
the m command is for m[ove], which moves the line number A after the line number X, if you want to copy instead of move the line, use co[py]. the d command is for d[elete].
You can move(copy using co) a range of lines using
:start,end m X
:ay (where a is the line number. Example :20y). This yanks a line(pun intended).
Vp
I find it easier to use Ex command for this; ex. to move line 9 to 46:
:46|9m.|-1d
This will move the cursor to line 46, move line 9 below the current,
then delete the previous line (since moved line is the current one).
Or using mark(s), using mark 'a':
:46ma a|9m'a|'ad
I often have to Y one line and replace it in multiple places, each of which have a different value (which means that I can't do a regex).
Y to yank the desired original line
and then on every line that you'd like to replace, VpzeroY
i would simple use the "Black hole" register:
given:
nnoremap < C-d > "_dd
the solution would be:
< C-d >yy
If you only want to change part of the line you can do that this way:
Move to position of what part of text you want to copy
y,$ - Yank from cursor to EndOfLine
move to position where you want to replace
v,$,p - replace from cursor to EndOfLine with contents of register

Resources