vim change one occurrence alone in the line - vim

I had a text like this
pid_t child;
long orig_eax;
child = fork();
if(child == 0) {
printf("the child is happy %d", child);
printf("the child");
I wanted to replace the word 'child' selectively using vim
so I used
%s/child/pid/c
so it asked me before replacing each match
but when it came to line 5 where there are two occurrences of 'child' , where I wanted to replace second one alone , so when it prompted to change first occurrence I gave 'n' , then instead asking the next occurrence in the same line it skipped the entire line and went to the next line.
Is this the expected behavior ?
If so how to ignore the first occurrence in the line but replace the second in the same line using the above search command ?

Add g ('global') modifier after the second / (along with the c (which stands for 'confirm')) : :%s/child/pid/cg
For more informations on flags, have a look at :help s_flags.
For instance, for the g flag :
[g] Replace all occurrences in the line. Without this argument,
replacement occurs only for the first occurrence in each line. If
the 'edcompatible' option is on, Vim remembers this flag and toggles
it each time you use it, but resets it when you give a new search
pattern. If the 'gdefault' option is on, this flag is on by default
and the [g] argument switches it off.

Related

Delete till end of sentence in vim

So I'm playing vim adventures and I got stuck. I need a Vim command that will delete the keys in red. I thought dd would do it, but that only deletes the current line.
Use das or dis to delete a sentence. Use dap or dip to delete a paragraph. See :help text-objects for details. Unrelated to your question, see this wiki page for plugins that provide other, highly useful text objects.
) jumps to the beginning of next sentence, so d) will delete (from the cursor) till the beginning of the next sentence. Vim detects sentences using ., meaning period + space. This does mean that d) will have some problems if your cursor is on either the period or space delimiting two sentences, and will only delete until the first character of the next sentence (meaning it deletes either a space or the period and space, which is almost never what is desired). das will work as you probably expect, deleting the sentence and the delimiter (period + space).
If you specifically want to move (and delete to) the last character in a sentence it is more complicated according to this vi.SE answer:
The solution was either dk which deletes the line and the line above it or dj which deletes the line and the line below it.
My original question was actually not the right question (there are multiple sentences).
To delete to the end of the sentence, from where your cursor is, use the letters, use "d)". the "d" is the delete command object, followed by a motion object ")" which advances the cursor (and the deletion process) to the end of the sentence.
To delete "around" a sentence, including all the extra whitespace, use "das" (delete around sentence). Or to delete inside the sentence, and not all the whitespace, then use "dis" (delete inside sentence).
Once you understand the VIM language, then you can easily memorize a plethora of operations. Use this table to understand VIM's vocabulary:
COUNT NUMERAL + TEXT OBJECT COMMAND + MOTION (or OPERATORS)
"3das" will perform "delete around sentence 3 times"
So, if practical, you could place a numeral followed by...
a command:
d=delete
y=yank (into memory buffer to "put" later)
c=change (delete then insert new text)
and then a motion:
) = move cursor to end of sentence
( = move cursor to beginning of prior sentence
} = move cursor to the next paragraph
{ = move cursor to the beginning of the prior paragraph
w = move cursor to next word
b = move cursor back a word
$ = move cursor to the end of the logical line
0 = (zero) move cursor to the beginning of the logical line
G = move cursor to the end of the file
gg = move cursor to the beginning of the file
h, j, k, or l (you might have to look those up)
OR instead of a Motion, define a field of area using:
a = around
i = inside
followed by the name of the area around the cursor:
s = sentence
p = paragraph
w = word
t = xml-tag <tag example> lots of text between tags </tag example>
< or > = inside or around a tag, frequently found in xml documents
{ [ ( ) ] } = inside or around any type of bracket ...
... {a large area [some more (a little stuff) things] of a great many things }
I actually find this table from the help file the best overview for block commands:
"dl" delete character (alias: "x")
"diw" delete inner word
"daw" delete a word
"diW" delete inner WORD (see |WORD|)
"daW" delete a WORD (see |WORD|)
"dgn" delete the next search pattern match
"dd" delete one line
"dis" delete inner sentence
"das" delete a sentence
"dib" delete inner '(' ')' block
"dab" delete a '(' ')' block
"dip" delete inner paragraph
"dap" delete a paragraph
"diB" delete inner '{' '}' block
"daB" delete a '{' '}' block
So deleting a sentence is das or deleting a paragraph is dap.
If you want to delete from J up to and including the . start at J and use df.
If you want to delete both lines then 2dd
Another option (not sure if it works in the game) is to delete up to and including the period:
d/\./e
You have to escape the period when using a search pattern like this after the delete command.
If you were limited to a single line, it is much simpler:
df.
You can use the command: d2d, but I do not know whether it works in the game.
Vim grammar is [Nubmer] [Operator/ Command] [Motion or Text Object]
So in this case, you can use: 2dd

how to understand below vim script entries?

Question 1:
I only know the bash script like this let var = value, but how to understand the mean of the below grammar under vim?
let g:counter += 1
return g:counter . '. '
Question 2:
What’s the means by '<C-\>^>', what is the key sequence in vim?
map '<C-\>^>'
I want to append my question, please forgive me,
the vim key map is like this
map <C-\>^] :GtagsCursor<CR>
I press key like
Ctrl-\ Shift-. and press ]
this doesn't work, what's the matter?
Question 1:
the two lines should be in a function. otherwise the return doesn't make any sense.
also the global variable g:counter should be already defined.
then the first line, just does as same as:
let g:counter = g:counter+1
so increment the variable g:counter by 1.
The 2nd line:
return g:counter . '. '
for example, after increment, the variable value is 10, then the line returns a string 10. (space)
the first dot concatenates two strings. first string is the variable value, which is converted into string type automatically. and the second string is '. '
Question 2:
map <C-\>^>
Note that I took the single quote from your map command away.
The key sequence is:
Ctrl-\Shift-6Shift-.
shift-6 is ^
Shift-. is >
Regarding the first question, you should probably type :help eval.txt or :help usr_41.txt inside Vim and read a good chunk of it.

vim repeat find next character 'x'

I often navigate in vim by f x to find next occurrence of character 'x',
but overlook that there is a word (or more words) containing 'x' in between the word I want to edit and the beginning cursor position.
So i have to f x again, which is kind of annoying since there is this nice button ., which does repeat the last command. So is there a way to repeat f x with a single button press.
The command to repeat an f is ; (semicolon); , (comma) reverses the direction of the search.
Time has passed since I asked this question - nowadays I use vim-easymotion, which makes the need for ; almost unnecessary.
This plugin allows to jump to a certain letter directly - triggering the plugin makes all letters grey except for all 'x' on the screen - and those are replaced by red letters which you can press to jump directly to it.
To add to #Jeremiah Willcock answer, We can add count to f command to go to the nth occurrence [count]f{char}. For e.g.
2fx => goes to the second occurrence of x [if available]
similarly we can use the same counter to ; and ,. For e.g.
2; => goes to the second occurrence of last search [if available]
2, => goes to the second occurrence of last search in reverse [if available]
This is very useful when using it with c{motion}(change) or d{motion}(delete). For e.g. If we want to change or delete to 3rd occurrence of a char we can do
c3fx => change to 3rd occurrence of character x (included)
d3fx => delete to 3rd occurrence of character x (included)

Move lines matched by :g to the top of the file

I have a large text file with several calls to a specific function method_name.
I've matched them using :g/method_name.
How would I move them to the top of the file (with the first match being on the top)?
I tried :g/method_name/normal ddggP but that reverses the order. Is there a better way to directly cut and paste all the matching lines, in order?
Example input file:
method_name 1
foo
method_name 2
bar
method_name 3
baz
Example output file:
method_name 1
method_name 2
method_name 3
foo
bar
baz
How about trying it the other way around: moving the un-matched lines to the bottom:
:v/method_name/normal ddGp
This seems to achieve what you want.
I think you can achieve the desired result by first creating a variable assigned
to 0:
:let i=0
And then executing this command:
:g/method_name/exec "m ".i | let i+= 1
It basically calls :m passing as address the value of i, and then increments
that value by one so it can be used in the next match. Seems to work.
Of course, you can delete the variable when you don't need it anymore:
:unlet i
If the file is really large, count of matching entries is small, and you don't want to move around the entire file with solution v/<pattern>/ m$, you may do this:
Pick any mark you don't care about, say 'k. Now the following key sequence does what you want:
ggmk:g/method_name/ m 'k-1
ggmk marks first line with 'k.
m 'k-1 moves matching line to 1 line before the 'k mark (and mark moves down with the line it is attached to).
This will only move a few matching lines, not the entire file.
Note: this somehow works even if the first line contains the pattern -- and I don't have an explanation for that.
For scripts:
normal ggmk
g/method_name/ m 'k-1

How to add a word at the beginning of multiple lines in vim?

In Vim,
How do i add a word at the beginning of all lines?
Also how do i add it at end?
Eg..
If i have
A
B
C
D
I want to make it to
int A =
int B =
etc..
use visual block mode (Ctrl-v) to select the column you want, and then hit I, type the characters you want, and then hit Esc
So in this case, you'd put your cursor on A, hit Ctrl-v, go down to D, hit I and type int (it'll only appear on the first line while you type it), and then hit Esc at which point it'll apply that insert to all visually selected portions.
This works for anywhere in the document, beginning of line or end of line.
:he v_b_I for more info on Visual Block Insert
You can do this:
:%s/^/at the beginning/
:%s/$/at the end/
:%s/.\+/int & =
+ won't match on empty lines
If you need to copy just the first word, then do:
:%s/^\w\+/int & =/g
If you want to preserve indentation, then do:
:%s/^\(\s*\)\(\w\+\)/\1int \2 =/g
A global substitute should do i:
:%s/.\+/int & =/
This is how it works: in the second part of the substitution (ie in the int & =) the ampersand is replaced with what machted in the first part (the .*). Since .* matches the entire line, each line is subsituted as wanted.
If you have empty lines (in which you don't want to have any replacements), you could go with a
:%s/^\S\+$/int & =/

Resources