This is kind of a follow on to the question about deleting every second line in a file.
How to do it in Vim:
Before:
aaa
bbb
ccc
ddd
eee
fff
(Say, it's a part of a visual selection.)
After:
aaa
ccc
eee
bbb
ddd
fff
How can I do this macro-style (delete every other line but store
deleted lines to buffer such that deleted lines are pasted in order)?
Also, if you could do this in a visual selection that would be really
handy (to parse a certain file)!
1. When the lines to reorder are the only ones present in the
buffer, one can use the command
:g/^/+m$
2. In general, when those lines are surrounded with other text,
one can either select the target range of lines to reorder and then run
:exe"'<,'>g/^/+m"line("'>")
or select all of the lines to reorder except for the first one of them
and then run
:'<,'>-g/^/+m'<-
instead.
In either case, the reordering is done efficiently and in a single run.
Type :let #e=''<CR> to empty the e register (assuming you don't care about its previous content).
Place your cursor on aaa.
Type qa (or any other letter instead of a) to record your macro.
Type j"Edd to go down one line and delete it while appending it to the e register.
Type q to stop recording
Visually select the whole thing.
Apply the macro with :'<,'>norm #a<CR>, this will delete every other line.
Type "ep.
You don't really need a macro for that.
We need a temporary register to put the results in, say register e (as proposed by romainl).
empty the register (the register must be empty since we're going to use the uppercase register name which means to append instead of overwrite)
:let #e=''ENTER
visually select the area to work on (i.e. lines aaa through fff)
delete every second line and append that line to register e:
:g/^/+d E
Now, register e holds the deleted content
paste register e where you need it using "ep
Discussion
we need to empty the register before using it since we're using the uppercase register name which means to append to the register (see section Named registers on :he registers)
type :he :global go learn more about the incredibly powerful :g command (and it's not less useful friend :v
99% of the actual answer are already covered in that unfortunately not accepted but excellent answer to your referenced question. The only extension that you need is to accumulate the deleted lines instead of throwing them away (exactly: storing the last deleted line in the default register)
Try this command:
:'<,'>g/^/+m$
It will move them to the end of file. Then you can move them back easily.
Related
I’d like to merge two blocks of lines in Vim, i.e., take lines k through l and append them to lines m through n. If you prefer a pseudocode explanation: [line[k+i] + line[m+i] for i in range(min(l-k, n-m)+1)].
For example,
abc
def
...
123
45
...
should become
abc123
def45
Is there a nice way to do this without copying and pasting manually line by line?
You can certainly do all this with a single copy/paste (using block-mode selection), but I'm guessing that's not what you want.
If you want to do this with just Ex commands
:5,8del | let l=split(#") | 1,4s/$/\=remove(l,0)/
will transform
work it
make it
do it
makes us
harder
better
faster
stronger
~
into
work it harder
make it better
do it faster
makes us stronger
~
UPDATE: An answer with this many upvotes deserves a more thorough explanation.
In Vim, you can use the pipe character (|) to chain multiple Ex commands, so the above is equivalent to
:5,8del
:let l=split(#")
:1,4s/$/\=remove(l,0)/
Many Ex commands accept a range of lines as a prefix argument - in the above case the 5,8 before the del and the 1,4 before the s/// specify which lines the commands operate on.
del deletes the given lines. It can take a register argument, but when one is not given, it dumps the lines to the unnamed register, #", just like deleting in normal mode does. let l=split(#") then splits the deleted lines into a list, using the default delimiter: whitespace. To work properly on input that had whitespace in the deleted lines, like:
more than
hour
our
never
ever
after
work is
over
~
we'd need to specify a different delimiter, to prevent "work is" from being split into two list elements: let l=split(#","\n").
Finally, in the substitution s/$/\=remove(l,0)/, we replace the end of each line ($) with the value of the expression remove(l,0). remove(l,0) alters the list l, deleting and returning its first element. This lets us replace the deleted lines in the order in which we read them. We could instead replace the deleted lines in reverse order by using remove(l,-1).
An elegant and concise Ex command solving the issue can be obtained by
combining the :global, :move, and :join commands. Assuming that
the first block of lines starts on the first line of the buffer, and
that the cursor is located on the line immediately preceding the first
line of the second block, the command is as follows.
:1,g/^/''+m.|-j!
For detailed explanation of this technique, see my answer to
an essentially the same question “How to achieve the “paste -d '␣'”
behavior out of the box in Vim?”.
To join blocks of line, you have to do the following steps:
Go to the third line: jj
Enter visual block mode: CTRL-v
Anchor the cursor to the end of the line (important for lines of differing length): $
Go to the end: CTRL-END
Cut the block: x
Go to the end of the first line: kk$
Paste the block here: p
The movement is not the best one (I'm not an expert), but it works like you wanted. Hope there will be a shorter version of it.
Here are the prerequisits so this technique works well:
All lines of the starting block (in the example in the question abc and def) have the same length XOR
the first line of the starting block is the longest, and you don't care about the additional spaces in between) XOR
The first line of the starting block is not the longest, and you additional spaces to the end.
Here's how I'd do it (with the cursor on the first line):
qama:5<CR>y$'a$p:5<CR>dd'ajq3#a
You need to know two things:
The line number on which the first line of the second group starts (5 in my case), and
the number of lines in each group (3 in my example).
Here's what's going on:
qa records everything up to the next q into a "buffer" in a.
ma creates a mark on the current line.
:5<CR> goes to the next group.
y$ yanks the rest of the line.
'a returns to the mark, set earlier.
$p pastes at the end of the line.
:5<CR> returns to the second group's first line.
dd deletes it.
'a returns to the mark.
jq goes down one line, and stops recording.
3#a repeats the action for each line (3 in my case)
As mentioned elsewhere, block selection is the way to go. But you can also use any variant of:
:!tail -n -6 % | paste -d '\0' % - | head -n 5
This method relies on the UNIX command line. The paste utility was created to handle this sort of line merging.
PASTE(1) BSD General Commands Manual PASTE(1)
NAME
paste -- merge corresponding or subsequent lines of files
SYNOPSIS
paste [-s] [-d list] file ...
DESCRIPTION
The paste utility concatenates the corresponding lines of the given input files, replacing all but the last file's newline characters with a single tab character,
and writes the resulting lines to standard output. If end-of-file is reached on an input file while other input files still contain data, the file is treated as if
it were an endless source of empty lines.
Sample data is the same as rampion's.
:1,4s/$/\=getline(line('.')+4)/ | 5,8d
I wouldn't think make it too complicated.
I would just set virtualedit on
(:set virtualedit=all)
Select block 123 and all below.
Put it after the first column:
abc 123
def 45
... ...
and remove the multiple space between to 1 space:
:%s/\s\{2,}/ /g
I would use complex repeats :)
Given this:
aaa
bbb
ccc
AAA
BBB
CCC
With the cursor on the first line, press the following:
qa}jdd''pkJxjq
and then press #a (and you may subsequently use ##) as many times as needed.
You should end up with:
aaaAAA
bbbBBB
cccCCC
(Plus a newline.)
Explaination:
qa starts recording a complex repeat in a
} jumps to the next empty line
jdd deletes the next line
'' goes back to the position before the last jump
p paste the deleted line under the current one
kJ append the current line to the end of the previous one
x delete the space that J adds between the combined lines; you can omit this if you want the space
j go to the next line
q end the complex repeat recording
After that you'd use #a to run the complex repeat stored in a, and then you can use ## to rerun the last ran complex repeat.
There can be many number of ways to accomplish this. I will merge two blocks of text using any of the following two methods.
suppose first block is at line 1 and 2nd block starts from line 10 with the cursor's initial position at line number 1.
(\n means pressing the enter key.)
1. abc
def
ghi
10. 123
456
789
with a macro using the commands: copy,paste and join.
qaqqa:+9y\npkJjq2#a10G3dd
with a macro using the commands move a line at nth line number and join.
qcqqc:10m .\nkJjq2#c
I am trying to delete a range of lines into a register a. Is this the easiest way to achieve this?
:5,10d a
The definition of "easiest" depends on what do you have, and what do you want to do
if you have a start line number and end number, e.g.
:2349,5344d a
is the easiest way.
You don't have to consider the questions like
"where is my cursor?"
"how many lines would be removed?"
...
If you are about to remove a small amount of lines, particularly they are on same screen. (You could use relative-linenumber.) for example: "a5dd but you have to move your cursor to the first line you want to delete. And this could be done by option 1 too: 5:d a<CR> (vim will automatically translate it into .,.+5d a<CR>)
If you just know the 1st line of deletion, and find the last line you want to delete by reading your text, (of course, small amount of lines) you could press V, and press j by reading, when it reaches the deletion ending border, press "ad
If the "range" in your question is the "range" concept in vim, The first option would be better. since it could be 234,540, it could be 1;/foo, /foo/,/bar/... :h range see detail
so back to the first sentence in my answer, There is no absolutely easiest way. It all depends on what do you have, and what do you want to do.
The other way to achieve this would be to highlight the range of lines in visual line mode. (Shift-V)
Then type "ad while in visual line mode. This will put the deleted lines into the a register.
" followed by a register puts the next delete, yank or put into that register.
Below is the documentation for " (quote)
*quote*
"{a-zA-Z0-9.%#:-"} Use register {a-zA-Z0-9.%#:-"} for next delete, yank
or put (use uppercase character to append with
delete and yank) ({.%#:} only work with put).
Another example of deleting multiple lines and putting it in a register. To delete 6 lines and put them in a register you can got to the line and type "a6dd. This puts the 6 deleted lines into register a.
Is there a way to place a character at a specific line in vim, even if the line is short?
For example, I'm contributing to a project which has a comment block style which is 79 columns wide, with a comment character at either end e.g.
!--------------!
! Comment !
! More Comment !
!--------------!
but it's really annoying to space over to it, even with guessing large numbers (35i< SPACE>< ESC>)
Is there a simple command which will do this for me, or a macro or something I could write?
set ve=all
then you could move (h,j,k,l) to anywhere you want. no matter how short your line is.
there are 4 options block, all, insert, onemore for details:
check :h virtualedit
in this way, after you typed short comment, then type <ESC>080l to go to the right place to the tailing !
you can map it too, if it is often used
then it works like this:
Put this in your .vimrc file and restart vim:
inoremap <F1> <C-r>=repeat(' ', 79-virtcol('.'))<CR>!<CR>
With this just press F1 (or whatever key you map) in insert mode after entering comment text to automatically pad with spaces and insert a ! in column 79.
Another simple way is to keep an empty comment box of the correct size somewhere, yank/paste it where needed and just Replace the spaces in it with your comment each time.
If you want to reformat a box that is too short, one way is to start from the comment in your example, make a Visual Block (Ctrl+v) selecting the single column just to the left of its right-hand edge, yank it (y), then repeatedly paste it (p). This will successively move the entire right-hand side of the comment one step, extending the box rightward. Repeat until it has the desired length.
If you already entered the comment text, you can use a macro to add the right-hand ! mark at the correct place. For example, record a macro (qa) that appends more characters than are needed for any line (e.g. 80ASpaceEsc), then use the goto column (|) to go to the correct place (79|) and replace the excess characters from there (C!Esc), then move down one line (j), and stop recording (q). Repeating this macro (#a) then "fixes" each line in turn and moves to the next. In total: qa80A<space><esc>79|C!<esc>jq and then #a whenever needed. Sounds complex but is convenient once you have it.
There are certainly good answers here already, particularly the virtualedit answer. However, I don't see the method which seems most intuitive to me. I would create an empty line for the last row of the comment which is just surrounded by the exclamation points. Then I would yank and paste a new copy of the empty line, go to the old empty line and go to the point at which I want to edit and use overstrike mode (R) to add my text without affecting the placement of the ending exclamation point.
Sometimes the simplest methods, while slightly more clunky, are the easiest to use and remember.
I usually just copy and paste an existing line in the comment block (or copy one from another file) and then modify it. If the text you're replacing is about the same size as what you want to write (e.g., if you're changing the author's name), you probably only need to add or delete a few spaces to make everything line up. It's a lot less painful than spacing out to the desired width.
If you ever have a block that gets too long this way, a neat trick is to place the cursor on the 79th column and press dw. That will clear all spaces up to the ! at the end.
My AlignFromCursor plugin offers commands and mappings that align only the text to the right of the cursor, and keep the text to the left unmodified. So, with the cursor in the whitespace left of the trailing !, you can align it with <Leader>ri.
I’d like to merge two blocks of lines in Vim, i.e., take lines k through l and append them to lines m through n. If you prefer a pseudocode explanation: [line[k+i] + line[m+i] for i in range(min(l-k, n-m)+1)].
For example,
abc
def
...
123
45
...
should become
abc123
def45
Is there a nice way to do this without copying and pasting manually line by line?
You can certainly do all this with a single copy/paste (using block-mode selection), but I'm guessing that's not what you want.
If you want to do this with just Ex commands
:5,8del | let l=split(#") | 1,4s/$/\=remove(l,0)/
will transform
work it
make it
do it
makes us
harder
better
faster
stronger
~
into
work it harder
make it better
do it faster
makes us stronger
~
UPDATE: An answer with this many upvotes deserves a more thorough explanation.
In Vim, you can use the pipe character (|) to chain multiple Ex commands, so the above is equivalent to
:5,8del
:let l=split(#")
:1,4s/$/\=remove(l,0)/
Many Ex commands accept a range of lines as a prefix argument - in the above case the 5,8 before the del and the 1,4 before the s/// specify which lines the commands operate on.
del deletes the given lines. It can take a register argument, but when one is not given, it dumps the lines to the unnamed register, #", just like deleting in normal mode does. let l=split(#") then splits the deleted lines into a list, using the default delimiter: whitespace. To work properly on input that had whitespace in the deleted lines, like:
more than
hour
our
never
ever
after
work is
over
~
we'd need to specify a different delimiter, to prevent "work is" from being split into two list elements: let l=split(#","\n").
Finally, in the substitution s/$/\=remove(l,0)/, we replace the end of each line ($) with the value of the expression remove(l,0). remove(l,0) alters the list l, deleting and returning its first element. This lets us replace the deleted lines in the order in which we read them. We could instead replace the deleted lines in reverse order by using remove(l,-1).
An elegant and concise Ex command solving the issue can be obtained by
combining the :global, :move, and :join commands. Assuming that
the first block of lines starts on the first line of the buffer, and
that the cursor is located on the line immediately preceding the first
line of the second block, the command is as follows.
:1,g/^/''+m.|-j!
For detailed explanation of this technique, see my answer to
an essentially the same question “How to achieve the “paste -d '␣'”
behavior out of the box in Vim?”.
To join blocks of line, you have to do the following steps:
Go to the third line: jj
Enter visual block mode: CTRL-v
Anchor the cursor to the end of the line (important for lines of differing length): $
Go to the end: CTRL-END
Cut the block: x
Go to the end of the first line: kk$
Paste the block here: p
The movement is not the best one (I'm not an expert), but it works like you wanted. Hope there will be a shorter version of it.
Here are the prerequisits so this technique works well:
All lines of the starting block (in the example in the question abc and def) have the same length XOR
the first line of the starting block is the longest, and you don't care about the additional spaces in between) XOR
The first line of the starting block is not the longest, and you additional spaces to the end.
Here's how I'd do it (with the cursor on the first line):
qama:5<CR>y$'a$p:5<CR>dd'ajq3#a
You need to know two things:
The line number on which the first line of the second group starts (5 in my case), and
the number of lines in each group (3 in my example).
Here's what's going on:
qa records everything up to the next q into a "buffer" in a.
ma creates a mark on the current line.
:5<CR> goes to the next group.
y$ yanks the rest of the line.
'a returns to the mark, set earlier.
$p pastes at the end of the line.
:5<CR> returns to the second group's first line.
dd deletes it.
'a returns to the mark.
jq goes down one line, and stops recording.
3#a repeats the action for each line (3 in my case)
As mentioned elsewhere, block selection is the way to go. But you can also use any variant of:
:!tail -n -6 % | paste -d '\0' % - | head -n 5
This method relies on the UNIX command line. The paste utility was created to handle this sort of line merging.
PASTE(1) BSD General Commands Manual PASTE(1)
NAME
paste -- merge corresponding or subsequent lines of files
SYNOPSIS
paste [-s] [-d list] file ...
DESCRIPTION
The paste utility concatenates the corresponding lines of the given input files, replacing all but the last file's newline characters with a single tab character,
and writes the resulting lines to standard output. If end-of-file is reached on an input file while other input files still contain data, the file is treated as if
it were an endless source of empty lines.
Sample data is the same as rampion's.
:1,4s/$/\=getline(line('.')+4)/ | 5,8d
I wouldn't think make it too complicated.
I would just set virtualedit on
(:set virtualedit=all)
Select block 123 and all below.
Put it after the first column:
abc 123
def 45
... ...
and remove the multiple space between to 1 space:
:%s/\s\{2,}/ /g
I would use complex repeats :)
Given this:
aaa
bbb
ccc
AAA
BBB
CCC
With the cursor on the first line, press the following:
qa}jdd''pkJxjq
and then press #a (and you may subsequently use ##) as many times as needed.
You should end up with:
aaaAAA
bbbBBB
cccCCC
(Plus a newline.)
Explaination:
qa starts recording a complex repeat in a
} jumps to the next empty line
jdd deletes the next line
'' goes back to the position before the last jump
p paste the deleted line under the current one
kJ append the current line to the end of the previous one
x delete the space that J adds between the combined lines; you can omit this if you want the space
j go to the next line
q end the complex repeat recording
After that you'd use #a to run the complex repeat stored in a, and then you can use ## to rerun the last ran complex repeat.
There can be many number of ways to accomplish this. I will merge two blocks of text using any of the following two methods.
suppose first block is at line 1 and 2nd block starts from line 10 with the cursor's initial position at line number 1.
(\n means pressing the enter key.)
1. abc
def
ghi
10. 123
456
789
with a macro using the commands: copy,paste and join.
qaqqa:+9y\npkJjq2#a10G3dd
with a macro using the commands move a line at nth line number and join.
qcqqc:10m .\nkJjq2#c
Suppose I have the piece of text below with the cursor staying at the first A currently,
AAAA
BBB
CC
D
How can I add spaces in front of each line to make it like, and it would be great if the number of columns of spaces can be specified on-the-fly, e.g., two here.
AAAA
BBB
CC
D
I would imagine there is a way to do it quickly in visual mode, but any ideas?
Currently I'm copying the first column of text in visual mode twice, and replace the entire two column to spaces, which involves > 5 keystrokes, too cumbersome.
Constraint:
Sorry that I didn't state the question clearly and might create some confusions.
The target is only part of a larger file, so it would be great if the number of rows and columns starting from the first A can be specified.
Edit:
Thank both #DeepYellow and #Johnsyweb, apparently >} and >ap are all great tips that I was not aware of, and they both could be valid answers before I clarified on the specific requirement for the answer to my question, but in any case, #luser droog 's answer stands out as the only viable answer. Thank you everyone!
I'd use :%s/^/ /
You could also specify a range of lines :10,15s/^/ /
Or a relative range :.,+5s/^/ /
Or use regular expressions for the locations :/A/,/D/>.
For copying code to paste on SO, I usually use sed from the terminal sed 's/^/ /' filename
Shortcut
I just learned a new trick for this. You enter visual mode v, select the region (with regular movement commands), then hit : which gives you this:
:'<,'>
ready for you to type just the command part of the above commands, the marks '< and '> being automatically set to the bounds of the visual selection.
To select and indent the current paragraph:
vip>
or
vip:>
followed by enter.
Edit:
As requested in the comments, you can also add spaces to the middle of a line using a regex quantifier \{n} on the any meta-character ..
:%s/^.\{14}/& /
This adds a space 14 chars from the left on each line. Of course % could be replaced by any of the above options for specifying the range of an ex command.
When on the first A, I'd go in block visual mode ctrl-v, select the lines you want to modify, press I (insert mode with capital i), and apply any changes I want for the first line. Leaving visual mode esc will apply all changes on the first line to all lines.
Probably not the most efficient on number of key-strokes, but gives you all the freedom you want before leaving visual mode. I don't like it when I have to specify by hand the line and column range in a regex command.
I'd use >}.
Where...
>: Shifts right and
}: means until the end of the paragraph
Hope this helps.
Ctrl + v (to enter in visual mode)
Use the arrow keys to select the lines
Shift + i (takes you to insert mode)
Hit space keys or whatever you want to type in front of the selected lines.
Save the changes (Use :w) and now you will see the changes in all the selected lines.
I would do like Nigu. Another solution is to use :normal:
<S-v> to enter VISUAL-LINE mode
3j or jjj or /D<CR> to select the lines
:norm I<Space><Space>, the correct range ('<,'>) being inserted automatically
:normal is probably a bit overkill for this specific case but sometimes you may want to perform a bunch of complex operations on a range of lines.
You can select the lines in visual mode, and type >. This assumes that you've set your tabs up to insert spaces, e.g.:
setl expandtab
setl shiftwidth=4
setl tabstop=4
(replace 4 with your preference in indentation)
If the lines form a paragraph, >ap in normal mode will shift the whole paragraph above and below the current position.
Let's assume you want to shift a block of code:
setup the count of spaces used by each shift command, :set shiftwidth=1, default is 8.
press Ctrl+v in appropriate place and move cursor up k or down j to select some area.
press > to shift the block and . to repeat the action until desired position (if cursor is missed, turn back with h or b).
Another thing you could try is a macro. If you do not know already, you start a macro with q and select the register to save the macro... so to save your macro in register a you would type qa in normal mode.
At the bottom there should be something that says recording. Now just do your movement as you would like.
So in this case you wanted 2 spaces in front of every line, so with your cursor already at the beginning of the first line, go into insert mode, and hit space twice. Now hit escape to go to normal mode, then down to the next line, then to the beginning of that line, and press q. This ends and saves the macro
(so that it is all in one place, this is the full list of key combinations you would do, where <esc> is when you press the escape key, and <space> is where you hit the space bar: qai<space><space><esc>j0q This saves the macro in register a )
Now to play the macro back you do # followed by the register you saved it in... so in this example #a. Now the second line will also have 2 spaces in front of them.
Macros can also run multiple times, so if I did 3#a the macro would run 3 times, and you would be done with this.
I like using macros for this like this because it is more intuitive to me, because I can do exactly what I want it to do, and just replay it multiple times.
I was looking for similar solution, and use this variation
VG:norm[N]I
N = numbers of spaces to insert.
V=Crtl-V
*** Notice *** put space immediate after I.