VIM - explain 'normal' and 'global' commands - vim

Can somebody clarify me how global (:h :g) and norm (:h norm) commands are working in VIM? I have file:
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
G
H
I have issued :g/[0-9]/norm 4gg dd hoping that it will work in following maner:
[0-9] = match only lines with numbers
4gg = jump to 4th line
dd = delete current (4th) line
So I was expecting this:
1
2
3
5
6
7
8
9
A
B
C
D
E
F
G
H
But instead of it I get:
1
2
3
4
A
B
C
D
E
F
G
H
Also it does not matter if I use norm or norm!, what is the difference, can you please explain me how this is working or point me to some good references, I have read :h :g and :h :norm but it does not help. Thank you
PS: I can use :4d but I am interested in :g and :norm explanation, the problem was mentioned just as simple example.

:g/pattern/do something
will do do something on each line that matches the pattern. so you got that output.
try:
:g/\d/echo getline('.')
:g/\d/echo line('.')
1st line prints the matched line
2nd prints the matched line number.
so you will see for each matched line, vim does something (echo, in this case)
and for the reason, why 4 is till there, because you have a space between 4gg and dd.
Your line with number has only one char, so space will move cursor to next line. that's why 4 won't be deleted.
remove the space!

:normal
:{range}normal {command}
executes normal mode {command} on every line in {range}. Without {range}, it operates on the current line.
Example:
:5,18normal 0df=
:global
:{range}g/{pattern}/{command}
executes {command} only on lines in {range} that match {pattern}. Without {range}, it operates on the whole buffer.
Examples:
:5,18g/^foo/normal 0df=
:5,18g/^foo/s/^.\{-}=/

It means:
For every line that contains any digit between 0 and 9, go to fourth line and delete it. So in first iteration it deletes the number 4, in the next one the number 5 and so on. When cursor begins with lines that don't contain number, it doesn't match and doesn't execute the normal instruction, so it doesn't delete anything.

To complete your questions (note that it is bad style to ask several questions (unless tightly related), and you should have been able to resolve most of that through the excellent :help):
The difference between :normal and :normal! is that the former considers mappings, whereas the latter always works on the default Vim commands. Therefore, the former is okay for ad-hoc commands (that make use of your mappings), but the latter is recommended for plugins (to be independent of any mappings).

Related

Run vim command on every line in a vim buffer

I want to JJ on every line in the current vim buffer. As I have very huge file, it is not possible to manually run on every line. How can I tell vim to do this for me?
Basically I have a file which has data in single column. I want to convert it to three columns
a
b
c
to:
a b c
And another one:
:%norm JJ
See :help :normal.
Use Macro and Normal mode command.
qqJJq
Recoding JJ commands to q
uu
Define q macro. undo all.
:%norm! #q
apply q to entire document.
PS : I'm not good at english
:g/^/join
joins consecutive lines (1+2, 3+4, and so on...) in the entire buffer. You can also supply a [range] to the :global command, which here is only used for its intelligent line handling; the ^ regular expression pattern matches any line.
To join three consecutive lines, use either
:g/^/.,.+2join
or
:g/^/join|join
(The former may give an error if the total amount of lines isn't divisible by 3; the latter avoids that.)

Search and replace in vim in specific lines

I can use
:5,12s/foo/bar/g
to search for foo and replace it by bar between lines 5 and 12. How can I do that only in line 5 and 12 (and not in the lines in between)?
Vim has special regular expression atoms that match in certain lines, columns, etc.; you can use them (possibly in addition to the range) to limit the matches:
:5,12s/\(\%5l\|\%12l\)foo/bar/g
See :help /\%l
You can do the substitution on line 5 and repeat it with minimal effort on line 12:
:5s/foo/bar
:12&
As pointed out by Ingo, :& forgets your flags. Since you are using /g, the correct command would be :&&:
:5s/foo/bar/g
:12&&
See :help :& and friends.
You could always add a c to the end. This will ask for confirmation for each and every match.
:5,12s/foo/bar/gc
Interesting question. Seems like there's only range selection and no multiple line selection:
http://vim.wikia.com/wiki/Ranges
However, if you have something special on line 5 and 12, you could use the :g operator. If your file looks like this (numbers only for reference):
1 line one
2 line one
3 line one
4 line one
5 enil one
6 line one
7 line one
8 line one
9 line one
10 line one
11 line one
12 enil one
And you want to replace one by eno on the lines where there's enil instead of line:
:g/enil/s/one/eno/
You could use ed - a line oriented text editor with similar commands to vi and vim. It probably predates vi and vim.
In a script (using a here document which processes input till the EndCommand marker) it would look like:
ed file <<EndCommands
5
s/foo/bar/g
7
s/foo/bar/g
wq
EndCommands
Obviously, the ed commands can be used on the command line also.

How to efficiently concatenate one set of lines with another set of lines in Vim?

Say, I have 10 consecutive lines followed by another 10 lines, e.g.:
1
2
⋮
10
a
b
⋮
j
I want to append the lines from the second range (a…j) to the lines in the first range (1…10), so that the above 20 lines turn into the following 10 lines, instead:
1a
2b
⋮
10j
Which Vim commands can I use to achieve this?
I would start going to line with a, then CTRL-V, 10j$d to blockwise delete everything.
Then :set virtualedit=all, goto first line, move cursor right by 10 characters for example, and press p. Now remove first sequence of spaces in your ten lines.
There is a second way, which is basically the same:
10dd
:call setreg('"', #", '^V') where ^V is typed with CTRL-V CTRL-V
(this will turn the register blockwise)
P
:,+10s/ //g
You can also do that programatically: enter Ex mode with Q, and type this
let i = 1
while i <= 10
call setline(i, getline(i) . getline(11))
11d
let i = i + 1
endwhile
vi
If you intend to reuse it put this into your vimrc :
function PasteLines(startline,numlines)
let i = 0
while i < a:numlines
call setline(a:startline+i, getline(a:startline+i) . getline(a:startline+a:numlines))
exec '' . (a:startline+a:numlines) . 'd'
let i = i + 1
endwhile
endfunction
And call it with :
:call PasteLines(1, 10)
where 1 is the first line, and 10 the number of lines. You need therefore 20 lines.
This would be my way:
qaG"aDdd9-$"apq
9#a
Explanation:
q # Begin recording typed characters...
a # to register 'a'
G # Set cursor in last line.
"aD # Delete the content from the beginning of line till the end and save it in register 'a'.
dd # Previous command deleted the content but left the line in blank, delete the complete line.
9- # Go back 9 lines.
$ # Set cursor at the end of current line (last number in your example).
"ap # Paste content of register 'a' (at end of line without newline character).
q # Stop recording.
---------------
9 # Run nine times.
#a # Commands of register 'a' (all previous commmands).
Register 'a' where I record commands is a different register of where I save content of each line, although they are named the same (letter 'a').
1. Assuming that the cursor is located on the first line of the
twenty-line block, let us consider the following short Ex command:
:,+9g/^/''+10m.|-j!
This is the :global command running on lines that belong to the
range of the next ten lines (starting from the current one). On every
of these lines, two Ex commands, ''+10m. and -j!, are sequentially
executed. The first command takes the tenth line under the line at
which the cursor has been positioned and inserts it just below the
line where the cursor is currently located, using the :move command.
The :join command, -j!, appends the just moved line to the one
just above it (without inserting or deleting whitespace in between,
due to the ! modifier).
There are two considerations that is necessary to take into account in
order to get the idea of that line movement. First, before the command
specified in a :global is executed on yet another line, the cursor
is positioned at the first column of that line. This way, the address
referenced in the aforementioned :move command as ., corresponds
to the latest line on which the command is currently being run.
Second, the number of the line that was the current one just before
a :global command was sent to execution, is added to the jump list.
Therefore, its address can be obtained in ranges through the
' pseudo-mark (see :help :range).
See also my answer to the question “Vim paste -d ' ' behaviour
out of the box?”.
2. The same effect can be achieved by means of Normal mode commands:
qqdd9+PgJ9-q9#q
This sequence of commands implements the same moving scheme, using a
macros to repeat a single-line transferring operation. The commands to
concatenate the first pair of lines, dd9+PgJ9-, are recorded in the
"q register using the q command. Similarly to the Ex command
proposed above, the macros deletes the current line (dd), moves the
cursor nine lines downward (9+), inserts the just cut line above the
new cursor position (P), joins that two lines without adding or
removing any spaces between them (gJ), and moves the cursor nine
lines upward (9-). Finally, these actions are automatically iterated
nine times using the # command to join the remaining nine pairs of
corresponding lines.

How to delete line(s) below current line in vim?

Is there a command to delete a line (or several lines) that is immediately below current line?
Currently I'm doing it as:
jdd and then . to repeat as needed.
Is there a command that would combine all these?
UPDATE: The reason I would like to have such command is that I don't like to move away from current position, yet be able to delete lines below.
The delete ex command will work nicely.
:+,$d
This will delete all the lines from current +1 till the end ($)
To delete the next 2 lines the follow range would work, +1,+2 or shorthand +,+2
:+,+2d
As #ib mentioned the :delete or :d command will move the cursor to the start of the line next to the deleted text. (Even with nostartofline set). To overcome this we can issue the `` normal mode command. `` will jump back to the exact position before the last jump, in this case the :d command. Our command is now
:+,+2denter``
Or as one ex command
:+,+2d|norm! ``
To make this easier we wrap this all up in a command:
command! -count=1 -register D :+,+<count>d <reg><bar>norm! ``
Now to delete the next following 3 lines:
:3D
This command can also take a {reg} like :delete and :yank do. So deleting the next 4 lines into register a would be:
:4D a
For more information
:h :d
:h :command
:h :command-register
:h :command-count
:h ``
dG should work.
This means delete all rows until end of file from current cursor.
This will delete ALL lines below the current one:
jdG
Unfortunately that will move the cursor to the beginning of current line after the deletion is made.
well, to do it simply you could use the xxdd command. Most of the time I know (at least have an idea) the size of the script I am editing. So, the command as below is usually more than enough :
99dd
999dd to remove 999lines starting at the cursor position.
9999dd
99999dd for very long script ;)
The other solutions are informative, but I feel it'd be simpler to use a macro for this:
qq (begins recording)
jddk (go down, delete the line, and go back up - i.e. the thing you want to do)
q (end recording)
Now you can do #q to perform this action, maintaining the cursor at the current position. You could also do something like 5#q to delete 5 lines below the cursor.
And finally, if you're repeating the action more than once, you could just type ## after the first time you run #q (this repeats the last used macro - in this case q)
This is a job for marks!
Try maj20dd`a
ma sets the file-specific mark 'a', j20dd does the deletion you want (20 lines in this case), and `a restores you to the mark's position (line and column).
Obviously this pattern can be extended to do anything you want before returning to the mark. If you use mA (or any other capital letter) the mark will actually be unique across files, so you can even edit elsewhere before returning. If you have a very frequent usage you could make it a macro as suggested above.
You could enter the number of lines to delete: j 20 dd k.
Just for the fun of it, you can define a little function that does
exactly what you described: deletes the next n lines below the
current line and restores the initial cursor position.
function! DeleteNextLines(n, reg)
let l = line('.')
let m = min([a:n, line('$')-l])
if m > 0
let c = col('.')
exe '+,+'.m 'd' a:reg
call cursor(l, c)
endif
endfunction
Also, you can define a command that accepts the number of lines
to delete (one, if omitted) and the register name to use as an
optional argument (just like the :delete command).
:command! -range=1 -register -bar D call DeleteNextLines(<count>, <q-reg>)
Additionally, you can define a mapping for triggering the above
:D command, if it is necessary.

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