Vim: Replacing a line with another one yanked before - vim

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

Related

How to yank the current line and the line above it in 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

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.

Prepending a character followed by the line number to every line

I'm hand-editing CNC Gcode text files and need a way to reference locations in the file and on the toolpath.
I want to modify every line in the text file so that it begins with the the upper case letter N followed by the line number, incremented in tens for each successive line, then a whitespace followed by the original text on that line. How can I do this in Vim?
I'm not sure about vi, but (since you're using the vim tag) Vim allows you to accomplish your task as follows:
Adjust the first line by hand (insert a N10 at the beginning of the line), then put the cursor at the beginning of the next line.
Press qb to start recording a macro (the b names the register used to store the macro; feel free to use a different letter -- and definitely do use a different letter if you've got something useful stashed away in b).
Move the cursor upward to the beginning of the previous line (which you have adjusted by hand). Press v to start visual selection mode, then f to move the cursor to the next space on the line (if you use a single space as your whitespace separator, that is; adjust this step if you're using a tab or multiple spaces).
Press y to yank the selected text. This will also remove the visual selection.
Move the cursor to the beginning of the next line. Press P to insert the previously yanked text before the cursor, that is, on the very beginning of the line.
Move the cursor to the numeric part of the line header. Press 10 C-a (1, 0, control + A) to increment that number by 10.
Move the cursor to the beginning of the next line. Press q to stop recording the macro.
Press 10000000 #b to execute the macro 10000000 times or until it hits the end of the file. This should be enough to take care of all the lines in your file, unless it is really huge, in which case use a bigger number.
...or use Vim to write a simple script to do the job in whichever language you like best, then run it from a terminal (or from withing Vim with something like :!./your-script-name). ;-)
The following command will prepend ‘N<line number * 10>’ to every line:
:g/^/exe 'normal! 0iN' . (line('.')*10) . ' '
You can do it easily in Vim with this:
:%s/^/\=line(".")*10 . " "/
This replaces the start of every line with the result of an expression that gives the line number times ten, followed by a space.
I have not timed it, but I suspect it might be noticeably faster than the other Vim solutions.
Cheating answer:
:%!awk '{print "N" NR "0", $0}'
There are two ways to implement that without resorting to external
tools: via a macro or by using Vimscript. In my opinion, the first way
is a little cumbersome (and probably not as effective as the solution
listed below).
The second way can be implemented like this (put the code into your
.vimrc or source it some other way):
function! NumberLines(format) range
let lfmt = (empty(a:format) ? 'N%04d' : a:format[0]) . ' %s'
for lnum in range(a:firstline, a:lastline)
call setline(lnum, printf(lfmt, lnum, getline(lnum)))
endfor
endfunction
The NumberLines function enumerates all lines of the file in a given
range and prepends to each line its number according to the provided
printf-format (N%04d, by default).
To simplify the usage of this function, it is convenient to create
a command that accepting a range of lines to process (the whole file,
by default) and a optional argument for the line number format:
command! -range=% -nargs=? NumberLines <line1>,<line2>call NumberLines([<f-args>])

How do I join two lines in vi?

I have two lines in a text file like below:
S<Switch_ID>_F<File type>
_ID<ID number>_T<date+time>_O<Original File name>.DAT
I want to append the two lines in vi like below:
S<Switch_ID>_F<File type>_ID<ID number>_T<date+time>_O<Original File name>.DAT
The second line got deleted and the contents of the second line was appended to the first line.
How could I do it using command mode in vi?
Shift+J removes the line change character from the current line, so by pressing "J" at any place in the line you can combine the current line and the next line in the way you want.
Vi or Vim?
Anyway, the following command works for Vim in 'nocompatible' mode. That is, I suppose, almost pure vi.
:join!
If you want to do it from normal command use
gJ
With 'gJ' you join lines as is -- without adding or removing whitespaces:
S<Switch_ID>_F<File type>
_ID<ID number>_T<date+time>_O<Original File name>.DAT
Result:
S<Switch_ID>_F<File type>_ID<ID number>_T<date+time>_O<Original File name>.DAT
With 'J' command you will have:
S<Switch_ID>_F<File type> _ID<ID number>_T<date+time>_O<Original File name>.DAT
Note space between type> and _ID.
This should do it:
J
In vi, J (that's Shift + J) or :join should do what you want, for the most part. Note that they adjust whitespace. In particular, you'll end up with a space between the two joined lines in many cases, and if the second line is indented that indentation will be removed prior to joining.
In Vim you can also use gJ (G, then Shift + J) or :join!. These will join lines without doing any whitespace adjustments.
In Vim, see :help J for more information.
Just replace the "\n" with "".
In vi/Vim for every line in the document:
%s/>\n_/>_/g
If you want to confirm every replacement:
%s/>\n_/>_/gc
If you want to join the selected lines (you are in visual mode), then just press gJ to join your lines with no spaces whatsoever.
This is described in greater detail on the vi/Vim Stack Exchange site.
Press Shift + 4 ("$") on the first line, then Shift + j ("J").
And if you want help, go into vi, and then press F1.
In Vim you can also use gJ.
ََ
Another way of joining two lines without placing cursor to that line is:
:6,6s#\n##
Here 6 is the line number to which another line will be join. To display the line number, use :set nu.
If we are on the cursor where the next line should be joined, then:
:s#\n##
In both cases we don't need g like :s#\n##g, because on one line only one \n exist.

Vim yanking range of lines

I'm a C# developer who has just recently decided to expand my knowledge of the tools available to me. The first tool I've decided to learn is Vi/Vim. Everything has been going well so far, but there are a couple of questions I can't seem to find the answer to:
Lets say I wanted to yank a range of lines. I know there are many ways of doing so, but I would like to do it by line number. I figured it would be similar to how the substitute commands work, something like 81,91y. Is there a way to do this?
I'm a little confused about the g command in normal mode. It seems to do a myriad of things and I can't really determine what the g command does at its core. I'm confused on whether or not it's a motion command or a kind of "catch all" for other commands ran through normal mode. Can someone please explain this or point me to a reference that gives a good explanation of the g command?
Yank lines 81-91
:81,91y<enter>
If your fingers don't like to find the : and , keys, this would work as well (go to line 81, yank 11 lines)
81gg11yy
My only use of g is 5gg. To go to the 5th line. 22gg: 22nd line. As jimbo said, it's really only a modifier for some other commands.
For completeness, (http://vim.wikia.com/wiki/Power_of_g) explains a lot of how g works in command mode.
You can also copy the current lines to your present cursor location using 't'.
:81,91t.<enter>
This will paste the lines 81-91 under the line the cursor is on.
I learned this from http://vimcasts.org which is an excellent resource on VIM.
I also like to use vim's relative line number option which means I can just enter:
:-10,-7ya a
to yank the text into named buffer a.
N.B. Specifying A will append what you're yanking to the current contents of buffer a.
Don't forget you can also copy blocks of text and move blocks of text around as well with the similar commands:
:-10,-7co .
means copy the four lines of text 10 lines above to below the current line, and
:-10,-7mo .
means move the four lines of text 10 lines above to below the current line.
The G command goes to a certain line number, if it's accompanied by a count value. 81G puts you on line 81.
The y command can be combined with a movement, like G. So to yank everything until line 91 you can use y91G.
Together you get:
81Gy91G
Go to line 81, then yank while going to line 91.
g doesn't do anything by itself. It's one of a couple meta-commands that holds a bunch of sorta-unrelated commands.
z is yet another command like that.
In addition to :91,96y a which yanks (y) lines 91 through 96 into register a, (pasted with "ap), the yanked lines can be appended to the register with:
:91,96y A
I.e. the capitalization of the A register causes an appending operation into register a instead of an overwrite. Capitalization of the register always works like this, e.g. :let #A=';' appends a ; to register a.
Using plus (+) or minus (-) references lines relative to the current cursor position:
:-10,+10y b
I.e. it would yank(y) 21 lines around the current cursor position and put them in register b.
An absence of input actually represents the current cursor position as well, which means that this:
:-5,y a
would yank the text from 5 lines above to current cursor position into named buffer a, and:
:,+5y a
would yank the 5 lines after the current cursor position into buffer a.
Note: If you have a macro in buffer a it was just overwritten by the previous yank, as yank registers and macro registers are really the same thing. Which is why, coincidentally, you can paste a macro, edit it, and then yank it back into it's register. I personally use letters reached by my left hand for yanks, and letters reached by my right hand for macros.
Moving blocks of text around, looks like this:
:+10,+13m.
which means move the four lines positioned 10 lines ahead of current cursor, to below the current line.
Addendum
I previously confused ya in :91,95ya a to be somehow synonymous with ya{motion} where the motion was supplied by 91,95. This was incorrect and the "a" in ya is completely unnecessary. In my defense, my help yank does not convey that ya is a possible alias of yank.
The best solution would be to enter "visual mode", by pressing v. And after selecting lines just copy them by pressing y. Then paste copied lines by pressing p.
Vim's :help index describes g as:
|g| g{char} extended commands, see |g| below
Scroll down (or :help g) for a list.
As a long time Vi/Vim user I tend to use 'marks' instead of line numbers (or 'line markers'). It works like this: m is the 'mark' character; then use any letter to identify/name the mark. To return to a mark preface the named mark with a single quote ( 'a)These marks can be used as the range. Examples:
File:
<line 1>
<line 2>
<line 3>
<line 4>
<line 5>
When in command mode move cursor to line 2, typema. scroll to line 4, typemb.
To yank from mark a to mark b type:
:'a,'byank
To delete from mark a to mark b type:
:'a,'bdel
To search from mark a to mark b and replace 'ine' with 'ink':
:'a,'bs/ine/ink/g
To copy mark a through mark b and paste below the current position (the 'dot' always references the line where the cursor currently is positioned):
:'a,'bco .
Shift lines of code, between mark a through mark b, one tab to the right (use opposite chevron, <, to move left):
:'a,'b>
In command mode you can move back to marks by simply typing 'a to move back to the line marked a. Typing '' moves you back to previous position (unfortuantely only remembers the previous position, not two back).
You can yank to named buffers, copy, delete lines, search&replace just portions of your code, etc. without needing to know the line numbers.
To yank lines from line number 81 to 91 :
approach 1: 81gg11yy
not bad but you have to do little bit of math to find out how many lines to yank
approach 2: 81gg then shift+v then 91gg then y
BEST IN MY OPINION because this is straight forward, you only have to know the obvious thing i.e from which line number to which line number you want to yank

Resources