How can I quickly add something to a few lines in vim? - vim

I'm trying to get away from my arrow use but there is one thing I've yet to solve without using the arrow keys. Take this example:
var1 = "1"
var2 = "2"
var3 = "3"
var4 = "4"
Now I want this to be:
var_1 = "1"
var_2 = "2"
var_3 = "3"
var_4 = "4"
Using arrows I would just goto the var1, insert and add the underscore and then arrow down and do the same thing. The problem with using hjkl is I can't be in insert mode so I have to esc out, move down, insert...rinse repeat which required more work. Is there another way to accomplish this?

You can also use a visual block insert:
go to the "1" in "var1"
press CTRL+V
go down with j to select all the rows you wish to affect
I (that's capital i)
_
<ESC>
The underscore should now be inserted at the correct place in all the rows selected (for some reason it takes a second for it to happen on my machine)

There are many ways to do this. Using movement commands for example:
1G0 → Go to the start of the first line
f1 → go to the first occurence of "1"
i_<ESC> → insert "_" and go back to normal mode
j. → go down a line and repeat the insert command
j. → go down a line and repeat the insert command
...
Or, better yet, use an "ex" command:
:%s/var/var_/
Or even with the visual block command, as johusman notes.

Assuming you're at line 1, character 1...
Using a macro:
qqfra_<Esc>+q3#q
q Record macro
q Into register q
f find
r 'r'
a append
_ underscore
Esc Normal mode
+ Start of next line
3 Three times
# Play macro
q from register q
Par 11.
Or (better) using substitute:
:%s!r!&_<CR>
Par 9!
[Sorry... too much VimGolf!]

I tend to prefer :substitute over the visual block mode.
%s/var\zs\ze\d/_/

I always have line numbers turned on, so I'd do e.g.
1,4 s/var/var_/
This is similar to the
% s/var/var_/
answer, but it only functions on the named lines. You can use visual mode to mark the lines, if you don't like typing the range (the 1,4 prefix) in your command.

Related

Quickest way to switch order of comma-sparated list in Vim

Supose I have a function such as
myfunc(arg1 = whatever, arg2 = different)
I would like to transform it to
myfunc(arg2 = different, arg1 = whatever)
What is the quickest command sequence to achieve this? suppose the cursor is on the first "m". My best attempt is fadt,lpldt)%p.
There is a vim plugin: vim-exchange
visual select arg1 = whatever
press Shiftx
visual select arg2 = different
press Shiftx
I would recommend you change it a bit so it will work from wherever the cursor is and so that it will work on any arguments:
0f(ldt,lpldt)%p
All I changed from your method was I added 0 to move the cursor to the beginning and I changed fa to f(l so that it will work regardless of argument name.
Now you can either put this into a macro, or, if you use it a lot, you can make it a mapping:
nnoremap <C-k> 0f(ldt,lpldt)%p
I arbitrarily chose Ctrl-k here put you can use whatever you like.
I wrote a plugin for manipulating function arguments called Argumentative. With it you just execute >, and the argument your cursor is on will shift to the right. It also provides argument text object in the form of i, and a,.
With pure vim, with your cursor at the start of the line:
%3dB%pldt,lp
This is the quickest I could think of on the spot (12 strokes).
This should work for all names as long as there is always a space around the equal signs.
% " Jump to closing brace
3dB " Delete to the beginning of 3 WORDS, backwards
% " Jump to the beginning brace
p " Paste the deleted text from the default register
l " Move right one character
dt, " Delete until the next comma
l " Move right one character
p " paste the deleted text from the default register
You could also turn this into a Macro to use at any time.

How to quickly edit determinate part of code inside different similar lines

I have this problem I'm adjusting a code I've made I have a structure like this:
Apple1 = Fruit("ss","ss",[0.1,0.4],'w')
PineApple = Fruit("ss","ss",[0.315,0.4],'w')
Banana = Fruit("ss","ss",[0.315,0.280],'w')
...
...
Instead of "ss"I would like to type further information like "Golden Delicious". For the moment I'm simply deleting "ss"clicking over it and then replacing it with the information I want to insert. I'm sure there is a faster way to do it, I've tried something with VIM macros but I can't figure out how to "Raw input" my data.
I've try simply to substitute it with Spyder, but is slow because I have to click substitute every time, with VIM for what I've try is the same.
Then I wonder how insert something else after 'w'...
This is an example of an final output only to understand better the question :
Apple1 = Fruit("Golden Delicous","red",[0.1,0.4],'w')
PineApple = Fruit("Ananas comosus","green",[0.315,0.4],'w')
Banana = Fruit(" Cavendish banana","yellow",[0.315,0.280],'w')
...
...
I reformulate the question: which is the faster way to change "ss", for the moment I'm clicking over "ss" delate "ss" and write e.g "Golden Delicous" but is very slow. What I would like is that for every single ss the editor ask me to insert something to replace the single ss.
e.g. first ssin the fist line: I want to replace it typing something else e.g. "Golden Delicous" second ssin the first line I want to replace it typing somethingelse e.g. red. First ssin the second line I want to replace it with s.e. e.g. Ananas comosussecond ssin the second line I want to replace with s.e. e.g. green and so on.
I'm sure there is an answer for this somewhere but I can't find it!
Please if you down vote explain me why so I can improve it!
As far as I understand, the data that you want to substitute for "ss" does not have regular structure, so you will need to enter it by hand.
In Vim you would do it like this:
Place the cursor over the first "ss", then press * and then N.
Press ce, enter the new data (e.g. "Golden Delicious"), then leave Insert mode by pressing Escape.
Press n to jump to the next instance of "ss".
Repeat steps 2 and 3 ad libitum.
Look up :h * and :h n for more information.
I would do it like that:
:%s/ss/\=input('Replacement: ')/gc
This queries you for each occurrence. With the /c flag, the display is even updated during the loop (at the cost of having to additionally answer y for each occurrence); without the flag, you would need to keep track of where you are yourself.
You can use a function that searches the whole file substituting all "ss" strings with values from arrays populated with the replacement data:
function! ChangeSS()
let ss1 = ['Golden Delicous', 'Ananas comosus', 'Cavendish banana']
let ss2 = ['red', 'green', 'yellow']
call cursor(1, 1)
let l = "ss2"
while search('"ss"', 'W') > 0
if l == "ss1"
let l = "ss2"
else
let l = "ss1"
endif
execute 'normal ci"' . remove({l}, 0)
endwhile
endfunction
It uses a reference variable (l) that exchanges which array you want to extract data from. ss1 is for first appearance of "ss" in the line and ss2 for the second one.
Run it like:
:call ChangeSS()
That (in my test) yields:
Apple1 = Fruit("Golden Delicous","red",[0.1,0.4],'w')
PineApple = Fruit("Ananas comosus","green",[0.315,0.4],'w')
Banana = Fruit("Cavendish banana","yellow",[0.315,0.280],'w')

How can I make vim to format matrix side by side

I am using vim to log a lot of my day-to-day work. I usually have a lot of results with matrix. When I paste those at the end of the day I have pages of (sometimes) 0ne or 2 columns matrix
My question is how can I ask vim to programatically format
this:
R) DT = data.frame(x=rnorm(6),y=rnorm(6))
R) DT
x y
1 -0.0007499 0.7661
2 1.5559552 -0.6664
3 0.2082094 -0.1598
4 -0.1684766 -0.0536
5 3.1014233 -0.7439
6 0.1985104 2.0415
R) DT2 = data.frame(x=rnorm(7),y=rnorm(7))
R) DT2
x y
1 -0.005116 -0.4388
2 2.317381 0.6597
3 0.359883 0.4770
4 -1.426220 0.4911
5 0.468820 -0.3260
6 0.626147 -0.6254
7 -1.086660 2.1973
to this: side by side
R) DT = data.frame(x=rnorm(6),y=rnorm(6)) R) DT2 = data.frame(x=rnorm(7),y=rnorm(7))
R) DT R) DT2
x y x y
1 -0.0007499 0.7661 1 -0.005116 -0.4388
2 1.5559552 -0.6664 2 2.317381 0.6597
3 0.2082094 -0.1598 3 0.359883 0.4770
4 -0.1684766 -0.0536 4 -1.426220 0.4911
5 3.1014233 -0.7439 5 0.468820 -0.3260
6 0.1985104 2.0415 6 0.626147 -0.6254
7 -1.086660 2.1973
EDIT:
Thanks everybody, Kent solution worked, strangely before set ve=all my C-Q did not allow to select a block like
############
###############
#########
#########
#########
I couldn't reach the last column of the second line (using gvim on win XP).
Now works very well
I'll also use Ingo Karkat plugin"
try following steps:
:set ve=all
move cursor to beginning of line R) DT2 = data.frame(x=rnorm(7),y=rnorm(7))
press C-V, then using motion magic to select the 2nd block
press d
move cursor to the first line, the position you want to paste the 2nd block. type p
if your text is always like that format, you could try this mapping:
:nnoremap <leader>mt :let &ve='all'<cr>gg/^R)<CR>n<c-v>G$dgg$3lp  
 
then you could in normal mode type <leader>mt to do the transformation.
NOTE
I have no experience of vim on windows... so you may have to change the mapping for windows blockwise selection. <C-Q> ? not sure.
I assume the first line of the file is R)...
this will paste the 2nd block to the position: 3 spaces after the end of 1st line, change the number 3 in mapping if you want to adjust it
The key to this is blockwise visual mode. Go to the beginning of the second block (what should become the right column next to the first block), press Ctrl+V (on Windows, this is often remapped to Ctrl+Q), create the selection with $ and jjj. . ., then delete with d. Then go to the first line of the first block, $ to go to the end of line, (optionally append padding whitespace), then paste with p . The second block should be pasted to the right of your cursor. Finally, you can delete the empty lines left where the second block was.
My UnconditionalPaste plugin simplifies this task: You can then simply delete the second block with dd or Vjjj. . .d, and force a paste in blockwise mode with the plugin's gdp mapping.
If you find a way to determine the size of the blocks (the } key, which jumps to the next empty line, may come handy here), you can then put all of the steps into a custom mapping.

Vim Copy and paste text on the same line

I have an input text as follows -
(command (and (A B C) ))
(command (and (D E F) ))
(command (and (G H I) ))
...
...
I would like to copy and paste part of text on the same line as
(command (and (A B C) (A B C)))
(command (and (D E F) (D E F)))
(command (and (G H I) (G H I)))
...
...
Will it be possible to do it using VI Editor automatically?
Update :
I think I missed one important point that the values A,B,C ... I... can have variable length. I just used them as symbols.
Thanks !
If all the lines are the same length and format as in your example:
With cursor anywhere on or inside of parens (A B C):
va(Ctrl+v
Now you have (A B C) selected and are in block select mode. Use any mechanism to block select downward. If it is a few lines, you can just move downward. If it is many you can add a count, or use a search (/) or end of file Shift+g.
Once you have selected all:
y/)Enterp
This will yank (y) the whole block, move to the close paren, and paste the block after it (p).
If the lines vary in length or otherwise cannot be reasonably selected as a block
You can use a pattern replacement. This is specific to your example, where we are looking for the pattern (A B C) where A, B and C are capital letters contained in parentheses and separated by spaces. We take a match of that pattern plus the following space, and replace it with the match of that pattern, a space, and the pattern match again.
:%s/\(([A-Z] [A-Z] [A-Z])\) /\1 \1/
Yes, several ways to do this in vim (as with most things). I would probably opt for a quick macro: go to the first line and hit qa from normal mode to start recording a macro named "a". Now do the edit on that line manually. Of course you'll want the operations to be generic, so don't just type in the values, use yank and put to copy it. Once the edit is done, escape to normal mode and press j to move down to the next line (this will set you up to run the macro on the next line). Hit q again to stop recording, then type #a to execute the macro on the next line, then hit it again to run it on the next line, etc. Or, once you do #a once, you can do ## to run the same macro again. You can also supply a count to ## to do is several times.
Alternatively, you can do a regex with the :s command, but it depends on what your lines actually look like and how good you are with regex.
(these work for me in vim)
using block select:
14l<C-v>jj6ly7lp
using macro (if lengths are varied):
record the macro using:
qqf(;vf)y;pj0q
and then repeat as neccessary:
100#q
works for a file with 100 lines
I combine the techniques given by bmearns and Kev.
So what I did is as follows
start recording the macro by q.
/( to find the opening bracket, so it goes to the second one.
n to goto the third one.
v to mark the visual block
/) to search for the end of the bracket
y to copy the visual block
n to goto next ) bracket
One time arrow key to go next to the closing bracket
p to paste the visual block
Down Arrow key to goto next line.
Home Key to goto first location of the next line.
q to stop recording the macro
#a to do the same operation for all the lines.
And it worked just completely fine !
Thanks a lot guys !

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