How do I join two lines in vi? - vim

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.

Related

Vim: delete empty lines around cursor

Suppose I'm editing the following document (* = cursor):
Lions
Tigers
Kittens
Puppies
*
Humans
What sequence can I use to delete the surrounding white space so that I'm left with:
Lions
Tigers
Kittens
Puppies
*
Humans
Note: I'm looking for an answer that handles any number of empty lines, not just this exact case.
EDIT 1: Line numbers are unknown and I only want to effect the span my cursor is in.
EDIT 2: Edited example to show I need to preserve leading whitespace on edges
Thanks
Easy. In normal mode, dipO<Esc> should do it.
Explanation:
dip on a blank line deletes it and all adjacent blank lines.
O<Esc> opens a new empty line, then goes back to normal mode.
Even more concise, cip<Esc> would roll these two steps into one, as suggested by #Lorkenpeist.
A possible solution is to use the :join command with a range:
:?.?+1,/./-1join!
Explanation:
[range]join! will join together a [range] of lines. The ! means with out inserting any extra space.
The starting point is to search backwards to the first character then down 1 line, ?.?+1
As the 1 in +1 can be assumed this can be abbreviated ?.?+
The ending point is to search forwards to the next character then up 1 line, /./-1
Same as before the 1 can be assumed so, /./-
As we are using the same pattern only searching forward the pattern can be omitted. //-
The command :join can be shorted to just :j
Final shortened command:
:?.?+,//-j!
Here are some related commands that might be handy:
1) to delete all empty lines:
:g/^$/d
:v/./d
2) Squeeze all empty lines into just 1 empty line:
:v/./,//-j
For more help see:
:h :j
:h [range]
:h :g
:h :v
Short Answer: ()V)kc<esc>
In normal mode, if you type () your cursor will move to the first blank line. ( moves the cursor to the beginning of the previous block of non-blank lines, and ) moves the cursor to the end (specifically, to the first blank line after said block). Then a simple d) will delete all text until the beginning of the next non-blank line. So the complete sequence is ()d).
EDIT: You're right, that deletes the whitespace at the beginning of the next non-blank line. Instead of d) try V)kd. V puts you in visual line mode, ) jumps to the first non-blank line (skipping the whitespace at the beginning of the line), k moves the cursor up one line. At this point you've selected all the blank lines, so d deletes the selection.
Finally, type O (capital O) followed by escape to crate a new blank line to replace the ones you deleted. Alternatively, replacing dO<Escape> with c<Escape> does the same thing with one less keystroke, so the entire sequence would be ()V)kc<Esc>.
These answers are irrelevant after the updated question:
This may not be the answer you want to hear, but I would make use of ranges. Take a look at the line number for the first empty line (let's say 55 for example) and the second to last empty line (perhaps 67). Then just do :55,67d.
Or, perhaps you only want there to ever be one empty line in your whole file. In that case you can match any occurrence of one or more empty lines and replace them with one empty line.
:%s/\(^$\n\)\+/\r/
This answer works:
If you just want to use normal mode you could search for the last line with something on it. For instance,
/.<Enter>kkVNjd
I didn't test so much, but it should work for your examples. There maybe more elegant solutions.
function! DelWrapLines()
while match(getline('.'),'^\s*$')>=0
exe 'normal kJ'
endwhile
exe 'silent +|+,/./-1d|noh'
exe 'normal k'
endfunction
source it and try :call DelWrapLines()
I know this question has already been resolved, but I just found a great solution in "sed & awk, 2nd Ed." (O'Reilly) that I thought was worth sharing. It does not use vim at all, but instead uses sed. This script will replace all instances of one or more blank lines (assuming there is no whitespace in those lines) with a single blank line. On the command line:
sed '/ˆ$/{
N
/ˆ\n$/D
}' myfile
Keep in mind that sed does not actually edit the file, but instead prints the edited lines to standard output. You can redirect this input to a file:
sed '/ˆ$/{
N
/ˆ\n$/D
}' myfile > tempfile
Be careful though, if you try to write it directly to myfile, it will just delete the entire contents of the file, which is clearly not what you want! After you write the output to tempfile, you can just mv tempfile myfile and tada! All instances of multiple blank lines are replaced by a single blank line.
Even better:
cat -s myfile > temp
mv temp myfile
cat is awesome, yes?
Bestest:
If you want to do it inside vim, you can replace all instances of multiple blank lines with a single blank line by using vim's handy feature of executing shell commands on a range of lines within vim.
:%!cat -s
That's all it takes, and your entire file is reformatted all nice!

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

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>])

Resources