Switch cursor position in visual block insert mode - vim

Is there a keystroke, similar to v_o, to switch cursor position in visual block insert mode?
Example: | cursor position
|line1
line2
line3
Hit Ctrl+v and go down to line 3
line1
line2
|line3
Hit I
|line1
line2
line3
Now the cursor is back at line 1.
I want to stay the cursor in line 3.

So, based on your comment:
The column insertion is done in a single step. Do your selection (c-v), go down, go in insert mode (I), add your x and leave the insert mode with either escape or ctrl-[. As you quit the insert mode, the inserted text will be added on all the lines.
In any case, your cursor will go back at the beginning. If you want to bring it at the end of what has been selected, you can do it by pressing: '> which marks the end of the last visual selection.
EDIT: After further discussion about the need, the point is to execute a column insert on a long range.
I would do 3 splits (with :sp), I would resize (by dragging the statusbar of a window) the 2 top ones to show each one line (the beginning of the selection for one, and the end for the other), they will be used as reference.
Then, use the third one to do the actual manipulation, and as you will type/indent (at the beginning of the selection), you will see it change in one of your small splits and you can compare with the other one to indent to where you want.
Here is a screenshot to illustrate it (I wanted to indent from line 1 to 43 and I use my first split as a reference to indent everything on where "blandit" is, line 44), I use the first split to see the beginning, the second to see the end and the 3rd to actually do the whole manipulation:

Related

In vim, how do I paste a column of text to the end of irregular length lines?

I would like to paste a column of text at the end of irregular-length lines.
For example, I would like to paste the following:
SRR447882.fastq.gz
SRR447883.fastq.gz
SRR447944.fastq.gz
at the end of these lines:
TIL01_
TIL01_
TIL04-TIP285_
Many times in the past, I simply create enough space on the first line that pasting will not come before the end of the existing text in the longest line. But then I need to go back and remove whitespace.
I have tried googling "vim column paste irregular length rows" and similar queries.
You could try to do the following four steps:
block-wise select the first 3 lines (you want to paste later), and press y
line-wise select (V) the 3 lines ending with _, press :right
then move cursor to the end of the first line($), paste the yanked text
gv re-select the lines, press :left
It looks like this:
You can do it like this:
Start on the first line of the second block
qq, start recording the q macro
4k, go up four lines
d$, delete till the end of line
4j, go back to the previous line
$p, paste the line at the end of the line
q, stop recording the macro
jVG, go down one line and select the remaining lines
:norm! #q, apply the macro to the selection
It does however leave space where the previous text was. #Kent one's is still easier.
My UnconditionalPaste plugin has (among others) gBp / gBP mappings that paste register contents as a minimal fitting (not rectangular) block with a jagged right edge.
demo
Step 1 - goto to the start of the SPP... lines, then start Visual mode linewise with V (capital V), press j two times to get the desired lines selected then press y.
Step 2 - goto the start of the TIL0... lines, then start Visual mode linewise with V (capital V), press j two times to get the desired lines selected then type...
:s;$;\=' ' . split(#")[line('.')-line("'<")];g`
and press Enter.
Here's another way to do it with a different feel to it:
set ve=all to permit insert/paste at arbitrary columns past eol. Block-copy your source text, then at your first target line paste it with 100|P (100 being any column number longer than your target lines), then :'[,']s, *\%100c,,
If you do p instead of P you'll get a space separator.

Vim: insert the same characters across multiple lines

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.
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.
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):
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.
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.
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.
:%s/^/vendor_/
or am I missing something?
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.
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.
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 (short for normal)
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_
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
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.
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.
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
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
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
:.,+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.
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.

Cut and paste in Vim without moving next line up

When I cut and paste in VIM by pressing v, and go to the end of the line using $, and press d, the next line gets moved up to the same line I'm cutting.
How do I stop this?
It moves up because you have removed all the characters including line return/feed.
There are multiple solutions as usual with Vim. There is no "one true way" but you can try the following commands.
You can use D (capital) in normal mode which will erase everything until the end of line.
See :help D
Using another motion
What you could do instead of using $ to move to the end of the line, use g_. It will move to the last non blank character of the line and won't select line return.
See :help g_
So vg_d should work as you want.
Using Replace
Alternatively, what you could do instead of cutting, you could replace the erased character by a blank using the space character.
So v$rSPACE should work to erase but it will not save the replaced characters in register (for pasting later for example).
To cut everything from current cursor position until the end, use C.
:he C will help you:
Delete from the cursor position to the end of the
line and [count]-1 more lines [into register x], and
start insert. Synonym for c$ (not |linewise|).
Doing so will cause the current line (assuming you are on the start of the line when hitting C) to become empty and the content is (by default) yanked into register "
Edit:
As Xavier notes in his comment (and his answer), the same could be achieved with D. It also cuts everything from current cursor position until the end of the line but doesn't go in insert mode after doing it.
If you use these keystroke sequence then next line would not move up.
v $ h d
It is moving up because EOL character $ is also getting deleted without moving cursor 1 character back.
Just skip the visual mode and swap the other two commands, ie. press d $.
This is shorter than your starting one and doesn't break your tradition introducing other keystrokes you may not be familiar with.

Why does Vim position the caret one character off with $ (end of line)?

Observe a line in a Vim instance:
Now I hit $:
Why does my cursor not go all the way to the end? Once I try inserting, the text gets inserted before the last character! Even if I try to move right again while still in normal mode I get the bell. Oddly, when in edit mode I can move to the actual end of line with the right arrow key!
Does anyone know why Vim does this? On 7.3 by the way. Thanks for the help.
Pressing $ while in command mode causes the cursor to move to the end of the line, effectively highlighting the last character. Hit i here to insert before the last character, or a to append to the line. It is slightly ambiguous here, because you're using a pipe character as a cursor rather than a rectangular block cursor. Have a look at ":help termcap-cursor-shape" if you want to change that.
If the goal is to append to the end of the line, A will jump to the end of the line and enter insert mode with a single keypress.
Use a to append a character after the current.
Or, to go to the end of the line and append in 1 step, use capital A. I.e. shiftA.
Similarly shift-I to insert at the beginning of the line without first having to press ^.
The cursor can't be between two characters, it is always on a character.
If you press $ then x, you will correctly delete the last printable character of the current line.
What you are observing is the fact that using i, you are always inserting your text before the selected character. If you want to insert after the selected character, you have to use a or better A as it has already been mentioned.
In other words:
i means "insert before character under cursor".
a means "insert after character under cursor".
mnemonic for a : a for "append".

confused by capital I in vim

I follow these step whenever I want to comment a block of code:
1) Enter Blockwise Visual mode by hitting CTRL-V.
2) Mark the block you wish to comment.
3) Hit I (capital I) and enter your comment string at the beginning of the line. (// for C++)
4) Hit ESC and all lines selected will have
However, I am not quite sure what I does there. And why ESC causes the insert on each line in the block.
In block select mode I tells VIM to switch to insert mode with the cursor before the first character in the first line of the block.
All of the characters that you type on that first line will be inserted in front of all of the lines in the selection, right before the selected block.
You can do the same with A, except that you will add it after the block.
from :help I
Insert text before the first non-blank in the line
[count] times.
When the 'H' flag is present in 'cpoptions' and the
line only contains blanks, insert start just before
the last blank.
inserts before each selected line
I can only make the assumption that "ESC" is used because it's not a printable character as ENTER is.
When using I , A or c in visual-mode, you are using actually the so called blockwise-operators. Yes, they behave very different in visual-mode than on insert.
For more help, help :blockwise-operators

Resources