vim: replace block - vim

Let's say I have this text:
something "something else"
something here "just another quoted block"
I want to substitute "something else" with "just another quoted block", so I do:
/quot<enter> (to jump to second quoted block searching for the string "quot")
yi" (to yank inner text for current quoted block)
?else<enter> (to jump back to the first quoted block wich contains "else")
vi" (to visually select the quoted block)
p (to paste yanked text)
This works, but I would like to know if the two last steps can be replaced by a single one, to avoid visual mode. I know it's not a huge gain keystroke-wise, but I think that the Vim philosophy would encourage what I'm trying to do, and every time I do this my mind keeps asking for this command. :-P
What I tried so far:
r (replace) replaces just one character
c (change) throws me into Insert mode and does not let me paste the text.

"_di"P
Delete inside quotes to the blackhole register; paste last yanked before cursor.
Or
ci"<Ctrl-R>0<ESC>
Change inside quotes to retrieve last yank; leave insert mode.

With my ReplaceWithRegister plugin, the last two steps would be gri". It also offers grr (replace current / [count] lines); though it only saves a little typing, I find this indispensable.

Key stroke wise, j$yi"k then vi"p is actually probably the fastest. However, if you absolutely must go into insert mode you can j$yi"k then "_ci"<C-r>" or ci"<C-r>0. The :help i_CTRL-R operator allows you to put the contents of a register into insert mode.

I usually try to keep it simple, using what I feel is more intuitive with every day commands:
j
yi"
k
ci"
<ESC>
p

Related

vim - surround text with function call

I want to wrap some code :
myObj.text;
with a function call where the code is passed as an argument.
console.log(myObj.text);
I've thought about using surround.vim to do that but didn't manage to do it.
Any idea if it's possible ? I
With Surround in normal mode:
ysiwfconsole.log<CR>
With Surround in visual mode:
Sfconsole.log<CR>
Without Surround in normal mode:
ciwconsole.log(<C-r>")<Esc>
Without Surround in visual mode:
cconsole.log(<C-r>")<Esc>
But that's not very scalable. A mapping would certainly be more useful since you will almost certainly need to do it often:
xnoremap <key> cconsole.log(<C-r>")<Esc>
nnoremap <key> ciwconsole.log(<C-r>")<Esc>
which brings us back to Surround, which already does that—and more—very elegantly.
I know and use two different ways to accomplish this:
Variant 1:
Select the text you want to wrap in visual mode (hit v followed by whatever movements are appropriate).
Replace that text by hitting c, then type your function call console.log(). (The old text is not gone, it's just moved into a register, from where it will be promptly retrieved in step 3.) Hit <esc> while you are behind the closing parenthese, that should leave you on the ) character.
Paste the replaced text into the parentheses by hitting P (this inserts before the character you are currently on, so right between the ( and the )).
The entire sequence is v<movement>c<functionName>()<esc>P.
Variant 2:
Alternatively to leaving insert mode and pasting from normal mode, you can just as well paste directly from insertion mode by hitting <ctrl>R followed by ".
The entire sequence is v<movement>c<functionName>(<ctrl>R")<esc>.
You can use substitution instruction combined with visual mode
To change bar to foo(bar):
press v and select text you want (plus one more character) to surround with function call (^v$ will select whole text on current line including the newline character at the end)
type :s/\%V.*\%V/foo\(&\)/<CR>
Explanation:
s/a/b/g means 'substitute first match of a with b on current line'
\%V.*\%V matches visual selection without last character
& means 'matched text' (bar in this case)
foo\(&\) gives 'matched text surrounded with foo(...) '
<CR> means 'press enter'
Notes
For this to work you have to visually select also next character after bar (^v$ selects also the newline character at the end, so it's fine)
might be some problems with multiline selections, haven't checked it yet
when I press : in visual mode, it puts '<,'> in command line, but that doesn't interfere with rest of the command (it even prevents substitution, when selected text appears also somewhere earlier on current line) - :'<,'>s/... still works

Pasting inside delimiters without using visual selection

In Vim, let's say I want to replace the contents of one String with the content of another.
Original input
var1 = "January"
var2 = "February"
Desired output
var1 = "January"
var2 = "January"
What I would usually do is:
Move cursor to line 1
y i " (yank inner quotes)
Move cursor to the destination quote in line 2
v i " p (visual select inner quotes, paste)
While this works well, I generally try to avoid visual mode when possible, so I am not completely satisfied with my step 4 (v i " p).
Is there any way to specify a "destination paste area" without using Visual mode? I suspect it might be something chained to g, but I can't think of anything.
There are many ways of doing this however using visual mode is the easiest.
Use the black hole register to delete the content then paste. e.g. "_di"P
Do ci"<c-r>0. <c-r> inserts the contents of a register
Simply paste and then move over a character and delete the old text. e.g pldt"
However visual mode still has my vote. I find that the concerns most people have is that using visual mode + paste is that the default register is swap with the selected text and it doesn't repeat well. Good news everybody! The 0 register always stores the last yank. The bad news is visual mode still doesn't repeat well. Take a look at this vimcast episode, Pasting from Visual mode, for more information. It mentions a few plugin that help with this.
I need this so often, I wrote a plugin to simplify and allow maximum speed: ReplaceWithRegister.
This plugin offers a two-in-one gr command that replaces text covered by a {motion} / text object, entire line(s) or the current selection with the contents of a register; the old text is deleted into the black-hole register, i.e. it's gone. It transparently handles many corner cases and allows for a quick repeat via the standard . command. Should you not like it, its page has links to alternatives.
It's not particularly pretty, but here goes:
Go to line one and yi"
Move to line two
Type "_di"hp
That deletes what's in the quotes, but sends the deleted text to a black hole register. Then it moves the cursor back one, and pastes what you yanked from line one.
All in all, you can start on the first line and type yi"j"_di"hp. Why is it that people find vim intimidating? ;)
Alternatively, yank the first line as normal, then drop to line two and type ci"<Ctrl+p> and select the previously yanked text from the menu.
Excerpt from my .vimrc:
" Delete to 'black hole' register
nnoremap <leader>d "_d
vnoremap <leader>d "_d
So, you just need to \di"P as your last step (assuming you use \ as a <leader>).
There is a plugin that addresses this problem precisely. It was presumably born out of the same feeling you're feeling, namely that Visual mode often feels less than ideal to advanced Vim users.
operator-replace – Operator to replace text with register content
With operator-replace installed the replacing goes like this.
Yank the word inside the quotes.
yi"
Move to the target line
j
Replace inside the quotes with the yanked text. (I've set up gr as the replace operator: :map gr <Plug>(operator-replace). Pick your own mapping.)
gri"
Check it out! This is part of the truly excellent textobj/operator frameworks. I couldn't work without them.

Command to surround a character with spaces in vim

I am trying to use vim properly - to aid me I've mapped my arrow keys to "" so that I am forced to use {hjlk} to move around.
This is causing me a problem when I want to just surround a character with spaces, eg:
"2+3" is better formatted "2 + 3"
Previously I would have put my cursor over the + and typed:
i[space][arrow-right][space][Esc]
That's 5 presses.
To do this without the arrow I seem to need to put the cursor over the + and go:
i[space][Esc]lli[space][Esc]
That's 8 presses.
I can convert the "li" into an "a" which reduces it to 7 presses:
i[space][Esc]la[space][Esc]
Short of writing this into a macro is there a better way of doing it? Is there some magic vim command which will allow me to do it in less than even 5 presses - and some way to generalise it so that I can do it to entire words or symbols, eg if I want to convert 3==4 to 3 == 4?
Personally, I think it makes most sense to destroy what you want to surround, and then repaste it.
c w "" ESC P
Obviously, you can replace both the object and the quotes with whatever you like. To change just one character + to be [space]+[space], you would do
s [space] [space] ESC P
on the +
The first thing that jumps to mind after reading just the title is surround.vim which is an excellent script to do all kinds of useful things along the lines of what you've described.
To solve your specific problem, I would probably position the cursor on the + and:
s[space]+[space][esc]
To change 3==4 into 3 == 4, I might position the cursor on the first =, and:
i[space][esc]ww.
i have been wondering about this as well. i tried with surround.vim, but the naive approach
S<space>
(after making a visual selection) does not work since the space is already taken up as a modifier for adding space to other surrounding character pairs. S<space><cr> adds a ^M in the output. Ss almost works but inserts a space only before.
after asking at tpope/surround.vim on github:
S<space><space>
in visual mode works. alternatively, from normal mode, ysl<space><space> works for a single character
Hah! I've been trying to figure out how to surround a block in spaces for quite a while and I finally found the right combination.
Using surround.vim you say surround selector space space.
So for this specific case I would use visual mode (a good trick for operating on single characters under the cursor BTW) thus: "vs " <- four key presses!
I also have a habit of typing things like argument lists without spaces. With this technique you can just navigate to the second argument using w and say "vws " to visually select a word and surround with spaces.
I prefer visual select mode generally. Also the alternate surround syntax "ysw " excludes the word final comma that is caught by "vw".
You could create a macro with one of the described actions and call it everytime you need it (Like amphetamachine proposed while I was writing) or you could simply search & replace:
:%s/\(\d\)\(+\|-\)\(\d\)/\1 \2 \3/g
You probably have to execute this command two times because it will only find every second occurence of +/-.
EDIT:
This will replace everything without the need to be called twice:
:%s/\d\#<=+\|-\d\#=/ \0 /g
Try positioning your cursor over the '+' and typing this:
q1i[space][right arrow][space][left arrow][esc]q
This will record a quick macro in slot 1 that you can re-use whenever you feel like it, that will surround the character under the cursor with spaces. You can re-call it with #1.
There is also the more versatile one:
q1ea[space][esc]bi[space][right arrow][esc]q
Which will surround the word under the cursor ("==" counts as a word) with spaces when you hit #1.
You could set up a mapping like this (press enter in visual mode to wrap spaces):
:vnoremap <CR> <ESC>`<i<SPACE><ESC>`>la<SPACE><ESC>h
This method allows you to use . to repeat the command at the next +.
Put your cursor over the + and type:
s[SPACE][CTRL-R]"[SPACE][ESC]
I know this is and old thread, but this might be useful to someone. I've found that the map (map it to anything else you want!)
noremap <leader>ss diwi<SPACE><C-R>"<SPACE><ESC>B
works ok both for turning 'a+b' into 'a + b' (when used over the '+' char) and for turning 'a==b' into 'a == b' (when used over either the first or the second '=' sign).
I hope it's useful to someone.

In vim, is there a plugin to use % to match the corresponding double quote (")?

The % key is one of the best features of vim: it lets you jump from { to }, [ to ], and so on.
However, it does not work by default with quotes: Either " or ', probably because the opening and closing quote are the same character, making implementation more difficult.
Thinking a bit more about the problem, I'm convinced that it should be implemented, by counting if the number of preceding quotes is odd or even and jumping to the previous or next quote, accordingly.
Before I try to implement it myself, I'd just like to know if someone already has?
Depending on your reason for needing this, there may be a better way to accomplish what you're looking for. For example, if you have the following code:
foo(bar, "baz quux")
^
and your cursor happens to be at the ^, and you want to replace everything inside the quotes with something else, use ci". This uses the Vim "text objects" to change (c) everything inside (i) the quotes (") and puts you in insert mode like this:
foo(bar, "")
^
Then you can start typing the replacement text. There are many other text objects that are really useful for this kind of shortcut. Learn (and use) one new Vim command per week, and you'll be an expert in no time!
Greg's answer was very useful but i also like the 'f' and 'F' commands that move the cursor forward and backward to the character you press after the command.
So press f" to move to the next " character and F" to move to the previous one.
I have found this technique very useful for going to the start/end of a very long quoted string.
when cursor is inside the string, visually select the whole string using vi" or vi'
go to start/end of the string by pressing o
press escape to exit visual select mode
this actually takes the cursor next to the start/end quote character, but still feels pretty helpful.
Edit
Adding Stefan's excellent comment here which is a better option for anyone who may miss the comment.
If you use va" (and va') then it will actually visually select the quotes itself as well.
– Stefan van den Akker
I'd like to expand on Greg's answer, and introduce the surround.vim plugin.
Suppose that rather than editing the contents of your quotes, you want to modify the " characters themselves. Lets say you want to change from double-quotes to single-quotes.
foo(bar, "baz quux")
^
The surround plugin allows you to change this to
foo(bar, 'baz quux')
^
just by executing the following: cs"' (which reads: "change the surrounding double-quotes to single-quotes").
You could also delete the quote marks simply by running: ds" (which reads: "delete the surrounding double-quotes).
There is a good introduction to the surround plugin here.
I know this question is old but here is a plugin to use % to match the corresponding double quote:
https://github.com/airblade/vim-matchquote

How can I insert text in the middle of the line to multiple lines in Vim?

Say I have ten lines and I want to prepend text to some word that occurs in those lines? It does not have to be at the beginning of the line.
From:
sdfsd foo sdfsd
sfsd foo fsdf
sdfsdf foo sdfsdf
to:
sdfsd bar(foo sdfsd
sfsd bar(foo fsdf
sdfsdf bar(foo sdfsdf
Is it also possible to not only prepend the bar( but actually surround foo with bar(foo)?
I would also like a quick way to append // comments to multiple lines (C-style comments).
I use Vim/GVim 7.2.
Go to the first foo, press Ctrl-v to enter visual block mode and press down until all the lines with foo are marked. Then press Shift-i to insert at the beginning (of the block). When you are finished and press Esc, the inserted characters will be added to each line at the left of the marked block.
To insert at the end, press again Ctrl-v, move up/down to mark all affected lines and then press End or $ to extend the selection until the end of the lines. Now you can press Shift-a to append at the end of all the lines, just like previously with Shift-i.
The visual selection can also be done with normal movement commands. So to comment a whole block in C you could move to the opening brace and type Ctrl-v % Shift-i // Esc.
To answer your first question, the below
:%s/foo/bar(&)/g
will look for foo, and surround the matched pattern with bar(). The /g will do this multiple times in one line.
Since you're just matching foo, you could do a simple :s/foo/bar(foo)/g. The above will work, however, if you decide to match on a regular expression rather than a simple word (e.g. f[a-z][a-z]). The '&' in the above represents what you've matched.
To prefix a set of lines I use one of two different approaches:
One approach is the block select (mentioned by sth). In general, you can select a rectangular region with ctrl-V followed by cursor-movement. Once you've highlighted a rectangle, pressing shift-I will insert characters on the left side of the rectangle, or shift-A will append them on the right side of the rectangle. So you can use this technique to make a rectangle that includes the left-most column of the lines you want to prefix, hit shift-I, type the prefix, and then hit escape.
The other approach is to use a substitution (as mentioned by Brian Agnew). Brian's substitution will affect the entire file (the % in the command means "all lines"). To affect just a few lines the easiest approach is to hit shift-V (which enables visual-line mode) while on the first/last line, and then move to the last/first line. Then type:
:s/^/YOUR PREFIX/
The ^ is a regex (in this case, the beginning of the line). By typing this in visual line mode you'll see '<,'> inserted before the s automatically. This means the range of the substitution will be the visual selection.
Extra tip: if your prefix contains slashes, you can either escape them with backslash, or you can use a different punctuation character as the separator in the command. For example, to add C++ line comments, I usually write:
:s:^:// :
For adding a suffix the substitution approach is generally easier unless all of your lines are exactly the same length. Just use $ for the pattern instead of ^ and your string will be appended instead of pre-pended.
If you want to add a prefix and a suffix simultaneously, you can do something like this:
:s/.*/PREFIX & SUFFIX/
The .* matches the whole line. The & in the replacement puts the matched text (the whole line) back, but now it'll have your prefix and suffix added.
BTW: when commenting out code you'll probably want to uncomment it later. You can use visual-block (ctrl-V) to select the slashes and then hit d to delete them, or you can use a substitution (probably with a visual line selection, made with shift-V) to remove the leading slashes like this:
:s:// ::
:normal to the rescue!
:%norm Wibar(
:%norm WEa)
:norm(al) replays the commands as if you had typed them:
W - goes to the next word
i - starts insertion mode
bar( - types the sequence 'bar('
Or in one line:
:%norm Wibar(ctrlvESCEa)
If you're running Windows then type ctrlq instead of ctrlv.
Yet another possibility (probably not-so-useful in your test case, but handy in other situations) is to cordon off the area you want to change with marks.
Put the cursor anywhere in the top line and press 'a
Put the cursor anywhere in the last line and press 'b
Issue the command :'a,'b s/foo/bar(&)/
I usually like visual block mode if everything is visible on the screen, and I usually prefer marks if the start and stop are separated by many screens.
Another simple regular expression is:
%s/^/<text you want to prepend>/
For the C-style comments, use the regexp answer by Brian, and match on line ending $, and insert away.

Resources