How to insert in visual block on different columns - vim

Imagine I have this lines:
one_view = Column(String(5))
two_view = Column(String(5))
three_view = Column(String(5))
four_view = Column(String(5))
five_view = Column(String(5))
six_view = Column(String(5))
seven_view = Column(String(5))
eight_view = Column(String(5))
nine_view = Column(String(5))
I need to append _f after each view.
I'm entering visual block and doing 8j, after this I want to find the first occurrence of = in each line and put the cursor here, after this I want to enter insert mode.
Is it possible with vanilla vim?
Edit: I know I can do it with macros or with :s/view/view_f/g but I'm just interested is it possible this way

No, visual block mode can't be used that way.
Generally, visual block mode creates a rectangle, which implies columns and vertical alignment. The only case where visual block mode is not restricted to vertically aligned text is when expanding the block to the end of the line with $ and, even then, it's only the end of the lines that is concerned.
:[range]s/view/&_f is really the best approach, here.

That is not possible. Not answering the actual question, but for that kind on things I would use one of those strategies:
use a substitution, like s/_view/_view_f/ in the right scope
align all the spaces (with easyalign for instance) and then use visual mode and I to insert _f on a rectangle.

As others have said, it wouldn't work as you've described it with vanilla vim (There are some align plugins which might actually make it possible, but I really don't recommend that for many reasons) I'd recommend using macros over regex. The regex is only going to work for this specific case. If 'view' wasn't there, it wouldn't work (Maybe you could then regex off of =, but you're not really setting yourself up well long term. This type of thing comes up all the time, and I prefer macros. These let you copy a number of commands and replay them. So you'll create a macro that does the first one, then you will replay the macro 8 times to do the other 9. So I would:
gg to get to the top of this nine line file
qq start a macro bound to q
e to get to the end of the first word
a_f to append _f to the first word
Esc to exit insert mode
j to go to the next line
0 to go to the beginning of the line
q to end your macro
8#q to play q the macro 8 times.
Now your file should look how you'd like.

Related

Vim : How to insert a / after certain length in multiple line

Here is following piece of text (a c++ code) which I am trying to edit in vim,
#define MACRO(X) /
{ /
if(x)
{
"some action performed here"
}
}
I want to complete this macro syntax by introducing / at each line. For aesthetic reasons I want the / to be aligned at same line length like how it is done for first two lines. How to achieve this in a single or few Vim commands. Assume that macro is very big in line count and I cant manually introduce space and / at every line
First of all, I am confused that the "macro" you meant in your question is a vim macro or your function named "MACRO(X)"?
To solve the problem you need set ve=all read :h 've' for detail.
If you meant the "macro" is a vim one, that is, you want to extend an existing vim macro, it is hard to tell how to do that. That's because we cannot see the existing macro, what does it do.
I list here two ways to do it, one is using a vim macro, you can put it into your existing one and test if it is required. The other one is using :normal command.
Assume that you've set ve=all
Assume that you want to add a / on column 50
vim macro
First record a macro a:
qa050lr/jq
Then you can replay it x times, e.g. 99#a
normal command
%norm! 50lr\
Two more ways to do the same thing.
If set ve=all or set ve=block using blockwise-visual mode.
$<C-V>6jr/
That is, go to an existing "/" at top line. Then enter blockwise-visual mode. Then extend selection downwards. Then replace everything with "/"
Using just :s
1,7s/$/\=repeat(' ', 49 - strlen(getline('.')))..nr2char(47)
That is, substitute "end of lines" 1 through 7 with an expression (variable number of spaces followed by slash).

Selecting visual block in the middle of a sentece accross multiple lines in Vim

So, let's imagine I have this code:
print $this_one = "1";
print $this_tu = "2";
print $this_three = "3";
and I want to select the middle part using the visual block mode:
$this_one
$this_tu
$this_three
and perhaps append something etc. but that's not important now.
The problem I am facing is that I don't know how to select that.
If it were something like:
print $this_one;
print $this_tu;
print $this_three;
I would just press Ctrl + v then j j and $ and it would be done.
But what if it is in the middle and the words end up on a different columns?
The blockwise selection with a jagged right edge indeed only works at the end of lines. In the "middle", you're stuck with a rectangular block selection that then includes trailing whitespace.
Unless you switch to a completely different approach (the comments already mention vim-multiple-cursors, which lets you select multiple places and then you can interactively edit all of those in parallel), you have to live with that.
Depending on the command that is applied to the blockwise selection, the trailing whitespace (or even any other characters you inadvertently capture) doesn't necessarily harm.
To append a character (say, $) to all middle words in your example, I would use the vis.vim plugin's :B command to work on the selection only, moving to the end of the word with the E motion, then appending the character with a$:
:'<,'>B normal! Ea$
In this, the whitespace is kept, and everything to the right of the selection moves one character right.

VIM Select Entire Line

How do you select a single line in VIM, when your cursor as at some random point along that line?
I know you can do (v, $) to get to the end of the line, or (v, ^) to get to the start, but when you do (v,$,^) it logically doesn't select the whole line, it selects from cursor, until end, then switches it to cursor until beginning... So this approach fails of course.
Capital V selects the current line in one key stroke; two, if you include the "shift" in shift+v.
V would be direct answer. However, I rarely need to do this because "selecting the current line" is generally part of a larger task. Example of such tasks includes copying the line and deleting the line. There's generally a better way to accomplish the task as a whole. The following are some of the tasks I can think of:
copy the line: yy
delete the line: dd
indent the line: >> or <<
select the current paragraph: vap or vip
delete from the current line to the end of the file 0dG
highlight the current line to see where my cursor is: use :set cursorline in .vimrc file
One case in which I do use V is to select multiple lines that are not a paragraph or some other text object. In this case, there's a tip that might be useful for you: once in the selection mode, you can use o to jump the cursor between the start and the end of the selection.
While this might be more keystrokes.
If you are already in visual mode you can use o to go to the other end of the visual selection.
So you can type
v0o$
To select the whole line. Take a look at :h visual-change
However from the comments it seems you just want to copy the whole line.
Which would just be yy
Just change your order of operations. You almost have it.
^,v,$
Or as suggested by #Kent: because ^ goes to the first non-empty char, if the line has leading spaces:
0,v,$
I know this thread is super old, but I just had the same question. This thread came up first, but I found a different answer than any found here. Use 'V' to select whole lines. That easy. One character to select the whole current line.

Programming in Vim: What specific mechanism do *you* use to 'copy-paste' variables?

NOTE
This was flagged as a potentially subjective question, but it is not subjective. It is requested to learn the various specific ways that people use Vim so that a person coming from a "mouse-and-keyboard" oriented text editor might learn more of the Vim way of editing.
This is not a subjective question about personal preferences or which editor or editing style is best.
This is a specific question about the mechanical steps one would take to obtain an outcome in the Vim editor, using alternative editors as a baseline for cross-reference.
PROBLEM
Suppose you have the following code in your Vim and you want to get from before to after where before looks like this:
// Before //
$mynames = Array();
$mynames['alice'] = 'alpha';
... and after looks like this ...
// After //
$mynames = Array();
$mynames['alice'] = 'alpha';
$mynames['betty'] = 'bravo';
$mynames['cindy'] = 'charlie';
$mynames['deana'] = 'delta';
HOW NON-VIM EDITORS WOULD DO IT
Using a non-vim editor, programmer A would simply copy the first line for alice, paste it multiple times into the editor and then re-edit the values so that alice and alpha are replaced with the appropriate values, editing one line at a time.
Using a non-vim editor, programmer B would create a rectangular selection that spans four lines, and just start typing the common text $mynames[''] = ''; and then go back and fill in the appropriate values, editing one line at a time.
HOW ABOUT VIM?
Given that Vim is a significantly different approach from "mouse-and-keyboard" style editors of the day, this is a request for insight on the specific steps one takes in editing with Vim. Obviously, it is possible to just type each line individually, but it is assumed that there is a time-saving way to do this in Vim in a way that compares to what programmer A and programmer B did above.
1) How would a vim programmer go about doing this edit operation, using a time-saving method like those above?
2) If someone were to search the Internet for more examples of specific 'step-by-step' comparisons of Vim editing sessions vs "mouse-and-keyboard" style editing, what would one search for?
I use the same, first i copy a line. then pasting it any times what i need.
Then you can create a macro to edit a keys. When cursor is on first line where i need to work. (a frist pasted line)
qq f[ci'<C>-<o>q "recordes a macro to find a [block] and
change inner quotes ' and stays in insert mode
Then you can play your macro any time by #q . (I have a map Q = #q for fast macro start by Shift+q)
The same way you can use for values:
qq f=f'ci'<C>-<o>q
Macro for find a value block and go to insert mode.
And the answer for comparsion i will save time to move my hand from keyboard to mouse times = number of edit lines. Selecting a block for changing. Vim is more productive no doubt.
If I know ahead of time what the different values are going to be, I'll to the roundabout approach. I'll start with this:
$mynames = Array();
alice alpha
betty bravo
cindy charlie
deana delta
Then I will place my cursor in front of alice, hit Ctrl+V, move down to deana, then hit Shift+I to go into insert mode and type $mynames[' followed by Esc. This inserts the text in all selected lines. Then I repeat that for '] = ', followed finally by ';'
Not the most efficient way, but usually the first that comes to mind.
I like AlexRus's solution (I love Vim macros).
But I think that a more realistic situation would be to paste the key/value pairs from some other application/document:
betty bravo
cindy charlie
deana delta
and perform a bunch of transformations on each line.
SOLUTION 1
We could select all three lines with <S-v>jj or some other way and apply a series of search/replace on the selection:
:'<,'>s/^/$mynames['
gv to reselect
:'<,'>s/ /'] = '
gv to reselect
:'<,'>s/$/';
The whole editing sequence looks like this:
<S-v>jj:s/^/$mynames['<CR>gv:s/ /'] = '<CR>gv:s/$/';<CR>
SOLUTION 2
We could apply a single search/replace
:'<,'>s/^\(.*\) \(.*\)$/$myname['\1'] = '\2';
where the search part isolates the beginning of the line (^), the space between words () and the end of the line ($) by actually matching the text between them and the replace part replaces the whole line with $myname[' + the first match (\1) + '] = ' + the second match (\2) + ';.
I'm bad at regex so I had to check my notes to put it together but I have no doubt many Vim users are able to type that kind of command in one go. I will, someday.
The whole editing sequence looks like this:
<S-v>jj:s/^\(.*\) \(.*\)$/$myname['\1'] = '\2';<CR>
SOLUTION 3
With the same setup, we could enter VISUAL-BLOCK mode at the beginning of the first line with <C-v>, go as far down as necessary and type I$myaccess['<Esc> to obtain:
$mynames['betty bravo
$mynames['cindy charlie
$mynames['deana delta
move the cursor to the space between words with f<Space>, hit <C-v> again, expand the selection to the bottom and type c'] = '<Esc> to obtain:
$mynames['betty'] = 'bravo
$mynames['cindy'] = 'charlie
$mynames['deana'] = 'delta
then move to the end of the line with $, hit <C-v> again, select what you want again and type A';<Esc> for the last touch.
The whole editing sequence looks like this:
<C-v>jjI$myaccess['<Esc>f <C-v>jjc'] = '<Esc>$<C-v>jjA';<Esc>

Swap text around equal sign

Is there an easy way to flip code around an equal sign in vi/vim?
Eg: I want to turn this:
value._1 = return_val.delta_clear_flags;
value._2._1 = return_val.delta_inactive_time_ts.tv_sec;
value._2._2 = return_val.delta_inactive_time_ts.tv_nsec;
value._3 = return_val.delta_inactive_distance_km;
(...)
into this:
return_val.delta_clear_flags = value._1;
return_val.delta_inactive_time_ts.tv_sec = value._2._1;
return_val.delta_inactive_time_ts.tv_nsec = value._2._2;
return_val.delta_inactive_distance_km = value._3;
(...)
on A LOT of lines in a file.
I know this seems a little trivial, but I've been running into lots of cases when coding where I've needed to do this in the past, and I've never had a good idea/way to do it that didn't require a lot of typing in vim, or writing a awk script. I would think this would be possible via a one liner in vi.
Explanations of the one-liners is very welcome and will be looked upon highly when I select my accepted answer. :)
Something like this:
:%s/\([^=]*\)\s\+=\s\+\([^;]*\)/\2 = \1
You might have to fiddle with it a bit if you have more complex code than what you have shown in the example.
EDIT: Explanation
We use the s/find/replace comand. The find part gets us this:
longest possible string consisting of anything-but-equal-signs, expressed by [^=]* ...
... followed by one or more spaces, \s\+ (the extra \ in front of + is a vim oddity)
... followed by = and again any number of spaces, =\s\+
... followed by the longest possible string of non-semicolon characters, [^;]*
Then we throw in a couple of capturing parentheses to save the stuff we'll need to construct the replacement string, that's the \(stuff\) syntax
And finally, we use the captured strings in the replace part of the s/find/replace command: that's \1 and \2.
For interest's sake, here's how I did it as a recorded macro:
qq0"+df=xA<BACKSPACE> = <ESC>"+pxi;<ESC>jq
Peforming that on the first line sets the "q" macro to do what's required. Then on each subsequent line you can execute the macro by typing:
#q
or, say you want to apply the macro to the next 10 lines:
10#q
I always find macros easier for a quick switch like this than figuring out the regex, because they're essentially an extension of how I would do it by hand.
Edit: Dan Olson points out in his comment that if you want to then apply the macro to a range of lines, for instance lines 6-100, you can enter the following. I don't know if there's a more concise syntax that doesn't require the ".*" pattern match.
:6,100g/.*/normal #q
Explanation of the macro
qq
start recording in register q
0
go to beginning of line
"+df=
delete up to the '=' and put the text into the '+' register
x
delete extra space
A
go to end of line and enter insert mode
<BACKSPACE> = <ESC>
Delete the semicolon, insert an equals sign and a space
"+p
insert the test copied earlier into register '+'
xi;<ESC>
reinsert the trailing semicolon
j
move down to the next line, ready to reapply the macro
q
stop recording
:%s/^\s*\(.\{-}\)\s*=\s*\(.\{-}\)\s*;\s*$/\2 = \1;/
should work nicely.
:%s/\([^ =]*\)\s*=\s*\([^;]*\);/\2 = \1;/

Resources