ChatGPT解决这个技术问题 Extra ChatGPT

Vim: insert the same characters across multiple lines

vim

Sometimes I want to edit a certain visual block of text across multiple lines.

For example, I would take a text that looks like this:

name
comment
phone
email

And make it look like this

vendor_name
vendor_comment
vendor_phone
vendor_email

Currently the way I would do it now is...

Select all 4 row lines of a block by pressing V and then j four times. Indent with >. Go back one letter with h. Go to block visual mode with Ctrlv. Select down four rows by pressing j four times. At this point you have selected a 4x1 visual blocks of whitespace (four rows and one column). Press C. Notice this pretty much indented to the left by one column. Type out a " vendor_" without the quote. Notice the extra space we had to put back. Press Esc. This is one of the very few times I use Esc to get out of insert mode. Ctrlc would only edit the first line. Repeat step 1. Indent the other way with <.

I don't need to indent if there is at least one column of whitespace before the words. I wouldn't need the whitespace if I didn't have to clear the visual block with c.

But if I have to clear, then is there a way to do what I performed above without creating the needed whitespace with indentation?

Also why does editing multiple lines at once only work by exiting out of insert mode with Esc over Ctrlc?

Here is a more complicated example:

name    = models.CharField( max_length = 135 )
comment = models.TextField( blank = True )
phone   = models.CharField( max_length = 135, blank = True )
email   = models.EmailField( blank = True )

to

name    = models.whatever.CharField( max_length = 135 )
comment = models.whatever.TextField( blank = True )
phone   = models.whatever.CharField( max_length = 135, blank = True )
email   = models.whatever.EmailField( blank = True )

In this example I would perform the vertical visual block over the ., and then reinsert it back during insert mode, i.e., type .whatever.. Hopefully now you can see the drawback to this method. I am limited to only selecting a column of text that are all the same in a vertical position.

Better way: ":%s/^/vendor_/"
Thanks for the response. That works if I only want to append a word to every line. But the method I use can be done at any position. Let me add another my example with a more complicated example.
Then highlight the lines you want to change with shift-V, and type an appropriate search and replace command - in the second example, :s/models\./\0whatever./
Many ways to achieve the above. To fully answer all parts of question then part 1) either regex or visual mode I edit esc works nicely as offered in answers (I prefer visual selection in GVIM). For part 2), macro is perhaps easiest as offered by Brian Neal. The best resource I know of for all these kinds of "how tos" is Practical Vim by Drew Neil. Excellent quick read and light weight reference whenever you forget a formula. Hope this recommendation helps someone, it will be well worth the effort for many vim users.
@Paul: And if you’re counting keystrokes, you could replace \0 with &.

A
Antonio

Move the cursor to the n in name. Enter visual block mode (Ctrlv). Press j three times (or 3j) to jump down by 3 lines; G (capital g) to jump to the last line Press I (capital i). Type in vendor_. Note: It will only update the screen in the first line - until Esc is pressed (6.), at which point all lines will be updated. Press Esc.

https://i.stack.imgur.com/T1WBi.gif

An uppercase I must be used rather than a lowercase i, because the lowercase i is interpreted as the start of a text object, which is rather useful on its own, e.g. for selecting inside a tag block (it):

https://i.stack.imgur.com/nlwsZ.gif


I couldn't get this to work in Windows (since CTRL+V is mapped for clipboard paste). But Vim has also mapped this to Ctrl+Q for the Windows version.
@Ven: Vim’s not actually busy during that time—it’s just waiting for you to press another key, and eventually times out. Two experiments for you: first, try pressing escape and then immediately pressing another key, like j or ^L. You should see that Vim wasn’t busy after all; it was just waiting. Second, try changing 'timeout' to a lower value, like 80 (rather than the default 1000) and observe that it times out more quickly.
@icktoofay It looks like the variable you mean to set is timeoutlen not timeout.
@ANjaNA: If where you want to insert is all in the same column (e.g. if the numbers are all the same length), you can use the same technique except pressing A rather than I, which will insert after the selected block rather than before. If your lines are different lengths, though, that won’t work; I like to use a substitution matching the end of each line for that, e.g. selecting some lines and using :s/$/inserted/.
I had to press down arrow after pressing esc to get this to work
A
Alex Spurling

Another approach is to use the . (dot) command in combination with i.

Move the cursor where you want to start Press i Type in the prefix you want (e.g. vendor_) Press esc. Press j to go down a line Type . to repeat the last edit, automatically inserting the prefix again Alternate quickly between j and .

I find this technique is often faster than the visual block mode for small numbers of additions and has the added benefit that if you don't need to insert the text on every single line in a range you can easily skip them by pressing extra j's.

Note that for large number of contiguous additions, the block approach or macro will likely be superior.


Nice to see another approach.
I prefer this for only a few lines. Much easier to execute IMO.
After you type in the prefix you want, don't you then need to press escape key?
@iamnotsam, if you are in insert mode, then yes you need to press Esc before moving to the next line. Otherwise pressing "." will simply insert a period.
L
Loukan ElKadi

Select the lines you want to modify using CtrlV. Press: I: Insert before what's selected. A: Append after what's selected. c: Replace what's selected. Type the new text. Press Esc to apply the changes to all selected lines.


Excellent! I'd just highlight the final step Esc for VIM noobs like myself - it took me a while to figure out that the changes get propagated "later"!
Nice, didn't know about "A" and "C" options too.
Why doesn't this work for v? I can do it with Ctrl+V --> A, but doing v to select the text doesn't work -- A only appends to that line. Aren't they both selection? Also, very strange -- A only appends to the end of the line IF I extend the visual block to the end of the line; otherwise it appends wherever the visual block ends for each line. It's like it doesn't recognize a difference between a and A.
I needed to use c instead of C, but it worked perfectly fine. Thank you
P
Peter Mortensen

I would use a macro to record my actions and would then repeat it.

Put your cursor on the first letter in name. Hit qq to start recording into the q buffer. Hit i to go into insert mode, type vector_, and then hit Esc to leave insert mode. Now hit 0 to go back to the beginning of the line. Now hit j to go down. Now hit q again to stop recording.

You now have a nice macro.

Type 3@q to execute your macro three times to do the rest of the lines.


Is "q" special (for "quick macro"?)?
How can the macro be made persistent (working across several sessions)?
@PeterMortensen Vim has a feature called sessions that will persist buffers (and a lot of other things) that you can look into.
From one Peter to another, great answer!
s
srini.venigalla
:%s/^/vendor_/

or am I missing something?


You're missing the fact that it's likely a subtext in a file with many other lines on which the vender_ prefix is unwanted.
@dan If only a subtext is needed, you can limit the search to a set of line numbers, eg 1,4s/^/vendor_/
@BradKoch Interesting. I was not aware of the line number constraints, thanks for that.
it is interesting, but what's more practical is to visually block select with V and type :. It will prefix the ed expression with :'<,'> which make the ed apply only to the selection with :'<,'>s/^/vendor_/
if you highlight matches like I do you may need to run :noh after.
a
arcseldon

Updated January 2016

Whilst the accepted answer is a great solution, this is actually slightly fewer keystrokes, and scales better - based in principle on the accepted answer.

Move the cursor to the n in name. Enter visual block mode (ctrlv). Press 3j Press I. Type in vendor_. Press esc.

https://i.stack.imgur.com/ce8e1.gif

Note, this has fewer keystrokes than the accepted answer provided (compare Step 3). We just count the number of j actions to perform.

If you have line numbers enabled (as illustrated above), and know the line number you wish to move to, then step 3 can be changed to #G where # is the wanted line number.

In our example above, this would be 4G. However when dealing with just a few line numbers an explicit count works well.


A
Aubrey Lavigne

An alternative that can be more flexible:

Example: To enter the text XYZ at the beginning of the line

:%norm IXYZ

What's happening here?

% == Execute on every line

norm == Execute the following keys in normal mode

I == Insert at beginning of line

XYZ == The text you want to enter

Then you hit Enter, and it executes.

Specific to your request:

:%norm Ivendor_

You can also choose a particular range:

:2,4norm Ivendor_

Or execute over a selected visual range:

:'<,'>norm Ivendor_

Or execute for each line that matches a 'target' regex:

:%g/target/norm Ivendor_

is it possible to send key sequences like while in insert mode (norm Iabc) in order to do more interesting stuff?
@batbrat I just figured this out! You can hit ctrl-v ctrl-[ to insert an "escaped Esc", which pulls you back to "normal mode" for the purpose of your normal command. I just tested this with '<,'>norm Iaa^[ysiw", where ^[ is the escaped Esc.
The :%mode approach is really valuable to know. I'm glad I stumbled upon this answer!
c
computingfreak

I wanted to comment out a lot of lines in some config file on a server that only had vi (no nano), so visual method was cumbersome as well Here's how i did that.

Open file vi file Display line numbers :set number! or :set number Then use the line numbers to replace start-of-line with "#", how?

:35,77s/^/#/

Note: the numbers are inclusive, lines from 35 to 77, both included will be modified.

To uncomment/undo that, simply use :35,77s/^#//

If you want to add a text word as a comment after every line of code, you can also use:

:35,77s/$/#test/ (for languages like Python)

:35,77s/;$/;\/\/test/ (for languages like Java)

credits/references:

https://unix.stackexchange.com/questions/84929/uncommenting-multiple-lines-of-code-specified-by-line-numbers-using-vi-or-vim https://unix.stackexchange.com/questions/120615/how-to-comment-multiple-lines-at-once


This was the perfect solution for me as I'm often only using vim-tiny.
P
Peter Mortensen

You might also have a use case where you want to delete a block of text and replace it.

Like this

Hello World

Hello World

To

Hello Cool

Hello Cool

You can just visual block select "World" in both lines.

Type c for change - now you will be in insert mode.

Insert the stuff you want and hit escape.

Both get reflected vertically. It works just like 'I', except that it replaces the block with the new text instead of inserting it.


P
Peter Mortensen

Suppose you have this file:

something

name
comment
phone
email

something else
and more ...

You want to add "vendor_" in front of "name", "comment", "phone", and "email", regardless of where they appear in the file.

:%s/\<\(name\|comment\|phone\|email\)\>/vendor_\1/gc

The c flag will prompt you for confirmation. You can drop that if you don't want the prompt.


A
Arpan Saini
Use Ctrl+V to enter visual block mode
Move Up/Down to select the columns of text in the lines you want to comment.
Then hit Shift+i and type the text you want to insert.
Then hit Esc, wait 1 second and the inserted text will appear on every line

does this method work for all versions of vim or require any vim plugins? the reason why i ask is b/c it sometimes works on some machines, but sometimes does not. i can't figure out the difference. vim that comes with git on windows - i can't get it working. on some ubuntu and centos linux machines, i can't get it working. i have had success in a few rare cases, but i could not reproduce the success. it's a mystery. nothing seems to happen after i hit ESC.
oddly, it DOES work for me now. nothing has changed, except maybe the stars :) while looking for solution to my issue, i did find something at this page though that mentions something to look for in vim vim.wikia.com/wiki/Inserting_text_in_multiple_lines In Vim, check that you have the blockwise-operators feature (I, A, and more) by entering the :version command. The output should include +visualextra.
I meant to add a comment in general, not to your answer. Most of these answers say the same thing but using different words. Mine had something different to offer and included a link.
P
Peter Mortensen

Ctrl + v to go to visual block mode Select the lines using the up and down arrow Enter lowercase 3i (press lowercase I three times) I (press capital I. That will take you into insert mode.) Write the text you want to add Esc Press the down arrow


V
Victor

I came here to paste in many lines an already copied string. When copy with y we can paste, in the INSERT MODE, pressing Ctrl+r and right after press ''. This will have the same result as being in NORMAL MODE and press p. This is called paste from registry.

Suppose the following text in the buffer:

vendor_something

text
to_receive
the_paste
pattern

Then we can put the cursor pointing to v in vendor_ and press v, move to right using l until select the underscore symbol we want to paste in the text bellow. After that, we can point the cursor at the beginning of "text" (two lines bellow vendor_something) and press Ctrl+v. Then I to go into INSERT MODE where we press 3j Ctrl+r '' Esc. The result of this sequence will be:

vendor_something

vendor_text
vendor_to_receive
vendor_the_paste
vendor_pattern

M
Mike P.

:.,+3s/^/vendor_/

Another example, I needed to just add two spaces to a block of 125 lines, so I used (with cursor positioned at the beginning of the first line of the block):

:.,+125s/^/ /

Worked great.


k
kjohri

If the change is required in the entire file,

:1,$s/^/vendor_/

If the change is required for only a few lines,

Go to the first line where change is required, and either give the command

:.,ns/^/vendor_/

Substitute n with the line number of the last line in the block.

Or,

:.,+ns/^/vendor_/

Substitute n with number of lines minus 1 in which the change is required.