How to modify a line after every 6 lines in vim - vim

I have a file with these lines:
aaa
aaa
aaa
aaa
aaa
aaa
bbb
bbb
bbb
bbb
bbb
bbb
ccc
ccc
ccc
ccc
ccc
ccc
ddd
ddd
ddd
ddd
ddd
ddd
i want to convert this into:
aaa;100;
aaa
aaa
aaa
aaa
aaa
bbb;100;
bbb
bbb
bbb
bbb
bbb
ccc;100;
ccc
ccc
ccc
ccc
ccc
ddd;100;
ddd
ddd
ddd
ddd
ddd
Is this possible in vim in one command ?

Yet another one
:g/^/ if !((line('.')-1)%6)|s/$/;100;
Breakdown
g/^/ Global command to apply next expression on each line
if !((line('.')-1)%6) If the modulus of the current line equals 0
s/$/;100; Replace the line ending with ;100;

That depends on what you mean by "one command", but you can do without manually repeating it for each item by using a macro:
Position your cursor on the first line
Start recording a macro named z: qz
Enter insert mode at the end of the line: <shift-A>
Enter the text you want: ;100;
Exit insert mode: <esc>
Jump down six lines: 6j
Stop recording the macro: q
Repeat the macro the right number more times: 3#z
Because the jumping down 6 lines is part of the macro, it will line up properly and loop through the file.
The relevant commands here are q# to start recording a macro, q to end the recording, and ## to play a recording back.
More information can be found in various places, such as the vim wiki: http://vim.wikia.com/wiki/Macros

If the lines are all the same until the change, this is a pretty nasty Vim solution:
/\v(.*)\n\zs\1#!
:%g//norm A;100;
Traditionally in Vim you craft a search first, then use :%s//replace to replace your last search with "replace". In one line it would be:
:%g/\v(.*)\n\zs\1#!/norm A;100;
I'm so sorry. This is what happens after years of Vim use. It's not pretty.
Explanation:
Essentially we're finding lines that AREN'T duplicated on the next line, and performing an action on them, in this case, adding some text.
:%g/ Perform an action on a pattern (same syntax as %s)
\v Very magic. Makes all special characters in Vim regexes special.
(.*)\n any text followed by a line break. Capture the text.
\zs Start highlighting the match here. This will put the cursor on the next line after the match, where we will perform the action.
\1 The capture group from above (.*), so a new line with the same text...
#! But negate it! So the cursor will go to any line that is NOT duplicated by the previous line.
/norm A;100; Peform the normal mode command A;100; which will execute keystrokes on each line as if you were in normal mode. Regular Vim here, just append (A) text.

:%s/\v(.*)(\n.*)(\n.*)(\n.*)(\n.*)(\n.*\n)/\1;100;\2\3\4\5\6/

Related

how to insert text at specific lines in vim?

I want to put cursor at specific lines that is:
AAA
BBB
CCC
I know how to edit those three lines using CTRL_V and then SHIFT_I, but my question is how do i edit the first and the last line and leave out the second line that is:
test_AAA
BBB
test_CCC
thanks in advance.
Vim doesn't have a built-in "multiple cursors" feature. If you want to do it the vanilla way, you can use :help .:
" cursor is on first A
> AAA
BBB
CCC
" do itest_<Esc>
> test_AAA
BBB
CCC
" move the cursor to CCC
test_AAA
BBB
> CCC
" press .
test_AAA
BBB
> test_CCC
or the almighty :help :global, which is the de-facto way to operate on non-contiguous line:
:g/^AA|^CC/s/^/test_
And there are many other ways.
Or you can ask your favourite engine to help you find the couple of plugins that replicate that feature: "vim multiple cursors".
You could use a reverse global command:
:v/^BBB/norm Itest_
Explanation:
The normal global command uses "g" instead of "v" which inverts the search, so, for each line that does not start with BBB use the normal command "I" (insert)

How to put/insert multiple yanked/deleted lines in vim

A simple problem that I do not have the right terminology to google to.
I am in visual mode when I delete some lines:
aaa
eee
fff
bbb
ccc
ddd
ggg
hhh
from first whitespace in 'b' row I press $ to select to end of line and then down to 'd' line but when I put them in the slot after 'aaa' I get this:
aaa
bbb
ccc eee
ddd fff
ggg
hhh
I want 'e' and 'f' lines to push down, not out. I can do it by copy/paste using the mouse in insert mode but the mouse is not my friend so I would like to know another way of doing it.
It looks like you are using "visual-block mode" (<C-v>, or <C-q> if you source mswin.vim, which you shouldn't) instead of the correct "visual-line mode" (V).

In Vim, how to cut in block mode but paste in normal mode, inserting as new lines?

Every now and then I run into this type of editing problem in Vim.
I have text formatting in a table that I want to turn into a list.
Before:
AAA BBB
AAA BBB
AAA BBB
CCC DDD
CCC DDD
CCC DDD
After:
AAA
AAA
AAA
BBB
BBB
BBB
CCC
CCC
CCC
DDD
DDD
DDD
Of course not as trivial as this example. The blocks can have hairier contents, larger and inconsistent numbers of lines, etc.
The way I do it now seems to be a bit of a hack:
Select a block from the right column in block mode:
CTRL-q in the Windows version to select the top-left corner.
d to cut the block.
Note how many lines were in the block, then manually add that many blank lines.
Go to the top-left of the new blank area I created. SHIFT+p to paste the block into this area.
Step is the rough part.
Doing a normal non-block cut or copy will always paste into "new" lines. A kind of "insert" or "append" operation. Doing a block cut or copy will normally paste in a kind of "overwrite" mode.
Is there a better way to copy or cut in "block mode" but paste in "insert / append mode"?
The ex command :put will always paste a register line wise.
Cut the block of text with visual block mode like you have before then execute :put instead of p.
If you want to "cast" pastes in more ways then use #Ingo Karkat's plugin.
For more information see:
:h pu
you can block wise select the BBB part as how you did, and after cut by d for example, you run this command:
call setreg('"',#",'V')
then you can paste to target line, it will turn your block-wise "yank" into line-wise.
You can create a mapping if you do need to do this often.
My UnconditionalPaste plugin has a glp (go linewise paste) command that will paste the register contents as new lines, regardless of how they were yanked (e.g. in blockwise mode).
It also has several other helpful commands that affect the way the register is pasted.

How to select a jagged block in Vim?

For example, there are some text like this:
001 aaaaa
002 bbbbbbbb
003 ccc
I want to select
aaaaa
bbbbbbbb
ccc
and yank it. What should I do?
The following sequence should do the trick
ggw<C-v>G$
where
gg -- Goes to top of file
w -- skips one word
<C-v> -- starts visual block select
G -- selects until end of file
$ -- selects to end of each line
Switch to Visual Mode in Vim by pressing v in prompt
place the cursor in the column to select
Use ctrl+v to select a block to copy
Then the column alone will be selected and copy needed text alone and can yank it:)
Please refer the link here

How to delete every other row, plus paste deleted results after selection?

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.

Resources