How to select the similar text in gvim and modify them? - vim

How I can select all the text start with foo_list starting from line 4 (see. below code) and rename them with list_values or any other preferred name ? Please note, I don't want to change in the first line.
Thanks in advance !
foo_list = [5, 2, 3, 1, 4]
def reverse_list_1():
foo_list=[0,10,20,40]
for i in reversed(foo_list):
print i,
foo_list=[0,10,20,40]
print foo_list[::-1]
for i in reversed(foo_list):
print i,
length = len(foo_list)
for i in range(length):
print foo_list[length-i-1],
Preferable solution: key map in the .vimrc or .gvimrc file, don't want to use any plugin.

That's a job for :substitute. You can specify the range with explicit line numbers (here: 4 to end of buffer $, or maybe next empty line /^$/):
:4,$substitute/\<foo_list\>/list_values/g
You can also first move to the first line and use the .,$ range.
Since that's still a lot of typing, you can pull in the current word (assuming you first position the cursor on the foo_list occurrence in line 4) into the command line via <C-R><C-W>.
Or, for a plugin solution, my ChangeGlobally plugin provides a mapping that avoids the use of :s.

:%s/foo_list/list_values/gc
This command says to replace the word foo_list with list_values in the whole document, asking for confirmation each time. Then for the first occurrence of foo_list on line 1, press n (to indicate NO) , and press y (to indicate YES) for all further occurrences to replace them. This solution works when you have to replace a few words. You can read the command as follows:
In the whole document (%), substitute (s) the word foo_list with list_values and do this globally (g), asking for confirmation (c) each time. For more options in the substitute command type :help :s in vim.
Solution 2 :
When there are thousands of words to replace, you surely don't want to type a y/n confirmation each time (which is enabled by the c flag in the end in the above command).
Take your cursor to line 4 and run
:.,$s/foo_list/list_values/g
Read the above command as from here (.) to the end of file (,$)
replace (s) the word foo_list with list_values
globally (g).

For small changes like this I like to use the gn motion. The gn motion visually selects the current search pattern. This makes for a powerful search/replace method when combining the gn motion with the change, c, operator and the repeat command, ..
Basic steps:
Make foo_list your search pattern. e.g. /foo_list or via *
Use c and gn to change the first foo_list. e.g. cgnbar_list<esc>
Now repeat that change on the next search result via .
Use n to advance to the next search results. (Hit n twice to skip an occurrence)
Keep using n and . until done
There is a nice Vimcasts episode on this topic: Operating on search matches using gn
For more information see:
:h gn

:substitute is the 'correct' way, but if you're only making a few changes, and you are not very experienced with ex commands, sometimes it takes longer to think through the command than to bounce through the list of changes you want to make using motions.
If you start with your cursor on the first instance of foo_list, hit '*' to jump to the next occurrence in the file. Hit 'ce' to delete to the end of the word and enter insert mode. Type in your new variable name and return to normal mode. Now you can jump through the rest of the file using 'n' to jump to the next occurrence (or 'N' to go back), and '.' to repeat your last edit action.

Related

Specifying position for a command in Ex mode

I want to remove percentage marks from the following lines:
oh_test_() ->
[
%{"fold", ?_test(fold(ns()))},
%{"fold nested", ?_test(fold_nested(ns()))},
%{"push arg empty table", ?_test(push_arg_empty_table(ns()))},
%{"push arg table 1", ?_test(push_arg_table1(ns()))},
%{"push arg nested table", ?_test(push_arg_nested_table(ns()))},
%{"multicall 0", ?_test(multicall_0(ns()))},
%{"multicall 1", ?_test(multicall_1(ns()))},
%{"multicall 2", ?_test(multicall_2(ns()))}
].
Cursor is on the line with first %.
:,/%/s/%//
Or:
:,/%/normal ^x
Expected: all percent marks removed. Result: removes only first two percent marks.
Why?
How should I do it
Without using visual mode, and
Not counting line numbers?
Question 1:
Your range: ,/%/ is roughly translated starting from the current line. The end of the range will be the next line that matches /%/ after the current cursor line. This will yield the 2 lines. See :h :, for more information.
Question 2:
There are many ways to do accomplish this. You have already presented a normal and a s/// method. One way to fix your commands is to adjust the range. One of the following will work:
,/\]\./-1 match the ending ]. and then subtract a line
,/^\s*%\(.*\n\s*%\)\#!/ Use a negative look ahead to search for a line that does not start with a %.
All together you could use:
:,/\]\./-1s/%//
:,/^\s*%\(.*\n\s*%\)\#!/s/%//
:,/\]\./-1norm ^x
:,/^\s*%\(.*\n\s*%\)\#!/norm ^x
An alternative to using a macro. The nice thing about using macros in this case is that when an error occurs it stops. Basically you record a macro to search for the % and then delete it then move to the next line. Execute this macro a large number of times. When a % cannot be found the macro will stop.
qq0f%xjq999#q
The macro is my preferred method in this case as I do not need to do any crazy patterns or go looking for the end of the block.
If you allowed the use of visual mode I would suggest vi]k:norm ^x
For more information see:
:h range
:h :,
:h /\#!
:h q
:h #q
:h i]
You first example is basically saying... from my current position until the next % issues the command s/%//...
What you may want to do is something like
:,$ s/%//
which says, for each line from my current position till the end of the file ($), issue the command s/%//
If you didn't want to do it till the end of the file then you could
:set number
Which will show you line numbers, then do something like
:2,8 s/%//
which just issues the command for all lines from 2-8
You seem to be using :,/%/ in a way that should use :g/%/. You could use your command as such: :g/%/s/%// or :g/%/norm f%x
See :help :g for more information on the "global" command. This basically executes a command-mode command on lines matching the pattern. Your version, :,/%/ operates from the current line until the match of "%". This removes the first two because the current line has one and you're searching to the line that has one (the next line). You can read more about this in :help :range. A better way to use this option would be to use a search item that's only on the last line. For example, :,/]/s/%// or :,/]/norm f%x.

Append general buffer to the end of every line in VI

I'm trying to add the contents of the general buffer to the end of every line. I'm sure this is fairly simple, however, an hour of google searches have lead me nowhere.
This is what my file looks like
::Things to bring camping
--matches
--tent
--sleeping bags
--inflatable bed
--firewood
--camping stove
--skillet
I want to add "::Things to bring camping" to the end of every line.
This is i have figured out so far.
/:: -> brings me to the line in question
Y -> yanks the entire line to the general buffer
I tried :%s/$/\p -> this added a "p" to the end of every line.
My problem is with step 3. How do I tell the "search and replace command" to used the "p" (the contents of the general buffer) instead of the "p" the character
Thank you so much for your help.
Just a suggestion: If you try doing it with a macro, you will be able to use 'p' to add the contents of the general buffer.
Sorry, I had to go into vim and find out.
The way to copy your entire line while in command mode, is:
^r "
(that's CTRL and r, then " )
That should paste the entire line you yanked into your search and replace command
For step three, instead of \p, you should use ctrl-R-a. Hold down the control key and type an uppercase "R", continue holding control, and type a lowercase "a".
For a line with multiple words, use ctrl-R-" instead.
I agree with using a macro - they're very powerful.
In this case I took your list example and positioned it at the first colon.
I used y$ to grab the remainder of the line in the buffer.
Then I recorded the macro - I chose 1.
q1
j$pq
Then you can call it for any number of rows in your list. E.g. 10#1
Learned something figuring this one out ...
:%s/$/\=getreg()/
The \= says that what follows is an expression to be evaluated, and the getreg() call gets the contents of the register, by default the "general buffer" as it used to be called by vi.

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.

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

VIM substitution: Using the current line as the search string

Assuming the following text file, which is actually a data dump of funds and price statistics:
PBCPDF
05/01/2006
0.0000
0.0000
PBCPDF
0.0000
06/01/2006
0.0000
0.0000
PBCPDF
0.0082
[… lines repeat …]
What I wanted to achieve is to delete all instances of PBCPDF except for the first one, which I could write the substitution command as :.+1,$s/PBCPDF\n//g.
However, since I wanted to program a macro to process multiple fund names, I need a means to use some sort of pattern that would retrieve the current line as the search pattern without me doing it by hand.
Is there a way to do that?
ggyy:+1,$s/<Ctrl-R>"<BS>//g
Let's see what that does, exactly.
Go to the first line
gg
Yank the entire liine
yy
Start the substitution
:+1,$s/
Get the current line from the register to which you yanked it to:
<Ctrl-R>"
Note: Don't type the ", you have to actually hold Control and press R, followed by a double quote.
Delete the end of line character:
<BS>
Note: press Backspace.
Replace with nothing.
//g
You can record this in a macro by wrapping it with a qq/q, or whatever.
If you're doing this in a macro (using the q command) it's smart enough to catch when you do some of the more esoteric keystroke commands - the one I'm specifically thinking about is CTRL-R, CTRL-W, which will insert the word under the cursor into the command line. So, for example, if you did
ESC
qw
/[CTRL-R, CTRL-W] (you should see the word under the cursor enter the command line)
[enter]
q
then you just created a macro that searches for the next word in the buffer that's the same as this one, get it? It will dynamically yank the word under the cursor into the command as part of the macro. There might be something like CTRL-W in the command above that does this for the whole line, but I don't know it offhand.
Having studied sykora's and Matt's answers, I came up with a slightly better improvement which works on a line-wise basis rather than a word-wise basis (as per Matt's solution).
This command is to be executed after the cursor is positioned on the line of which the deletion is to occur:
:.+1,$s/<CTRL-R>=getline(".")<CR>\n//g
Explanation for VIM beginners:
:.+1,$s/
Start substitution from the line after the current line (.+1) and the end-of-file ($)
<CTRL-R>=getline(".")<CR>\n
<CTRL-R> refers to the actual pressing of the CTRL and R keys, which allows you to enter special expressions. In this case, =getline(".") which retrieves the text of the current line.
<CR> refers to the pressing of the enter key, which completes the <CTRL-R> expression. I also specify the newline character (\n) at the end of the search pattern as I need to remove it.
//g
And then replace with nothing.

Resources