All occurrences of text between quotes (like * but for the whole text, not a single word) - vim

When I edit XML-files I sometimes want to jump to the next occurrence of text between quotes. For example, when my cursor is on my.attr in attr="my.attr" I want to jump to the next occurence of my.attr. I want to do it via some key combination (like Shift + * which is for words occurrences). Is is possible?

You can create a visual selection of the attribute value inside double quotes with vi". Then, there are several plugins that implement the * command for visual mode (usually by overloading the * command), i.e. they search for the next occurrence of the selected text. One such plugin is my SearchHighlighting plugin. (The plugin page has links to alternative plugins.)
Related plugins
If you want to change all attribute values (without constructing a :%s/ substitution), my ChangeGlobally plugin provides a gc{motion} and {Visual}gc command that does that.

I would yank the text inside the quotes with yi" (only works if the opening and closing quotes are on the same line) and then /<C-R>". (The <C-R> means CTRL-R, not 5 characters.)
This gives you a chance to modify the pattern before submitting it; as #Kalanidhi pointed out, you may have to escape some special characters. It uses the same i" text object as in #Ingo Karkat's answer.
If your text is short, then you can edit the command line with the arrow keys, but if it is long you may want to edit it in a command-line window with <C-F>. (Alternatively, if you are thinking ahead, use q/ instead of /.)
:help y
:help text-objects
:help c_CTRL-R
:help cmdline-editing
:help cmdline-window

You can use in command mode type /<exact pattern> if any special character then escape the special character like \
For example In command mode /"my\.attr"
So only search the exact pattern. N or n to move forward and backward .

Related

How to change a word in Vim (and all of its other occurrences)

I frequently use the combination c-a-w to change a word in Vim.
Are there any similar means by which one can quickly also change all other occurrences of said word in the specific file?
Use gn option for this purpose, in my case, I have a slightly different version of it
" allows me to use a smarter cgn
nnoremap c* *<c-o>cgn
nnoremap c# #<C-o>cgn
Now when you have to change a word many times, as long as you have not so many of it, because in this case, a classical substitution would be better, just press c* and then press "dot --> ." to change the next occurrencies of it.
If you want to see how awesomeness gn can give us have a look at: Operating on search matches using gn (vimcasts)
You could try:
%s/<CTRL-R><CTRL-W>/NewWord/g
<CTRL-R><CTRL-W> means keep control key pressed and hit R and W.
This copies the word under the cursor to the command line.
See :help c_CTRL-R_CTRL-W.
The main command for replacement of all occurrences is :substitute. Unfortunately, being an Ex command, it doesn't integrate too well with the single-word replacement (e.g. caw) in normal mode: Though you can insert the previously replaced word into the command-line with <C-R>", you still have to enclose it in \<...\> to enforce a whole word match, and also escape any special characters inside the word.
That said, there are plugins that offer help in that area. One of them is my ChangeGlobally plugin, which offers a gc{motion} alternative to c{motion} that then applies the change (or deletion) to other matches in the same line or entire buffer. (The plugin page has links to alternative plugins.)

vim insert mode autocompletion by ctrl-p does not work after dot

In vim insert mode, if there is a word insert, and if I typed ins, then type ctrl-p, vim will auto complete the word to insert.
I remember in my last PC if I type data.ins then type ctrl-p, vim will auto complete the word to data.insert, but since I bought a new PC, vim does not auto complete data.ins, how to fix this?
By the way if I type b on t of the word data.insert, vim will jump back to d, instead of i, I need to jump to i
I suspect that the dot character somehow got to be a part of the iskeyword option. To verify this, you can look at the output of :set iskeyword? (note the final questionmark).
To fix this temporarily, you can do :set iskeyword-=.. To fix this permanently, find out where iskeyword is changed in your .vimrc.
The option iskeyword determines what characters Vim considers to be part of a "word". With a dot inside it, string like data.insert will be considered a single word, meaning you jump over them with a single w/b/e/... motion. Ctrl-p autocompletion looks whether the substring typed until now is part of a "word" in the rest of the document. Since you hadn't typed data.insert before, it doesn't find anything starting with data.ins. When you remove the dot from iskeyword, it will only look if something started with ins (like insert).
After you removed the dot, if you find yourself occasionally wanting to jump over the entire dotted name, you can use Vim's concept of WORDs (see :h WORD). You jump over WORDs using W/B/E/...

Change delimiters for navigating word-wise

When programming/writing I heavily use word-wise commands, for example "move to the left/right by one word", "delete next/last word" by pressing Ctrl (+left,backspace...).
The problem I have is, when the text I am editing contains symbols which will not be recognized as words, therefore ctrl + right will jump over a sequence of symbols AND a regular word after that.
Ideally I want to be able to set the delimiting characters for word-wise operations to space, tab, newline and opening and closing brackets - maybe also arithmetic operators (similar to how Eclipse handles it).
I am using Linux. Do you know any way how to change my settings system-wide or alternatively for xterm and (g)vim individually to achieve this?
Most likely, system-wide won't work. VIM is easy, you can set the characters that define the identifier using the iskeyword setting. In your case, there is too much in it, and you need to remove the ones you do need, or redefine it by adding the ones you do want. eg: :set isk=9,32,50-51
This will set keyword detection to spaces, tabs and parentheses.
However, in VIM you can jump based on word and WORDs, where the first is defined by the abovementioned iskeyword setting, while the latter will jump over all non-blank characters. Maybe, that's the motion you want. You can read more about this in the help (:help w).
Instead of holding down the control key and pressing the left/right cursor keys, why not use Vim's normal mode word motion commands?
w/W - move to start of next word/WORD
e/E - move to end of next word/WORD
b/B - move to beginning of previous word/WORD
ge/gE - move to end of previous word/WORD
You can read up on the difference between a word and a WORD by running :help word.

How do I repeatedly search & replace a long string of text in vim?

I'm aware of the vim replace command, which is of the form, eg:
:%s/old/new/gc
But what if either of these strings is long? How can I use something like visual selection mode, the clipboard or vim registers instead of having to type the old/new text in?
You can use q: to bring up a command-line window. This lets you use all the vim editing commands to edit the vim command line, including p to paste. So, you could copy the text into a register, paste it into the command line window, and execute it that way.
I recently discovered this feature via vimcasts.
According to the manual, you can use Ctrl+R to insert the contents of a register into the current position in the command line. The manual also claims that Ctrl+Y inserts the text highlighted with the mouse into the command line. Remember that in X11 and some other systems, you can also paste text into a program from the system clipboard using the middle mouse button or a menu command in your terminal emulator.
I think to avoid have your command line be huge you can use this to solve your issue
:%s/foo/\=#a/g
That replaces "foo" with whatever is in register a.
If you're trying to do a substitute with a long complicated search pattern, here's a good way of going about it:
Try out the search pattern using some test cases and refine it until you have the pattern you want. I find incsearch really helps, especially with complicated regular expressions.
You can then use :%s//new to replace all instances of the last searched for pattern.
If you've entered a pattern and want to copy it out of the search history, you can use q/ to bring up a command line window containing recent search patterns very similar to the q: one that contains recent command history.
On the other hand, if you're asking about how to copy and paste text into the substitute command:
I'd write the pattern out in insert mode and yank the search and replacement into two distinct registers using, say, "ay and "by and then use :%s/<C-R>a/<C-R>b/gc to do the substitute. There are lots of variations of the yank command, but this one should also work automatically when using a visual selection.
If you're copying in text from the clipboard, you can use <C-R>* to paste it's contents in insert mode.
I have the following mapping in my .vimrc
vnoremap <leader>r "ry:%s/^Rr/
So I visually select the thing I want to replace, and hit ,r, type the replacement and hit return. If I want to paste the replacement, I yank it before selecting the text to replace, and then use <C-r>" to paste it as the replacement before hitting return.
Note: to insert ^R in your .vimrc, you actually type <C-v><C-r>.

How do I specify "the word under the cursor" on VIM's commandline?

I want to write a command that specifies "the word under the cursor" in VIM. For instance, let's say I have the cursor on a word and I make it appear twice. For instance, if the word is "abc" and I want "abcabc" then I could type:
:s/\(abc\)/\1\1/
But then I'd like to be able to move the cursor to "def" and use the same command to change it to "defdef":
:s/\(def\)/\1\1/
How can I write the command in the commandline so that it does this?
:s/\(*whatever is under the commandline*\)/\1\1
While in command-line mode, CTRL+R CTRL+W will insert the word under the cursor.
See the help for c_CTRL-R for a listing of all the other special registers:
:help c_CTRL-R
<cword> is the word under the cursor (:help <cword>).
You can nmap a command to it, or this series of keystrokes for the lazy will work:
b #go to beginning of current word
yw #yank to register
Then, when you are typing in your pattern you can hit <control-r>0<enter> which will paste in your command the contents of the 0-th register.
You can also make a command for this like:
:nmap <leader>w :s/\(<c-r>=expand("<cword>")<cr>\)/
Which will map hitting '' and 'w' at the same time to replace your command line with
:s/\(<currentword>\)/
yiwP
yiw: Yank inner word (the word under the cursor). This command also moves the cursor to the beginning of the word.
P: Paste before the cursor.
You can then map the e.g.: < ALT > - D to this command:
:nmap < ALT >-D yiwP
Another easy way to do this is to use the * command.
In regular mode, when over a word, type
*:s//\0\0<Enter>
* makes the search pattern the current word (e.g. \<abc\>).
:s// does a substitution using the current search pattern, and \0 in the replacement
section is the matched string.
You can then repeat this behaviour, say over word "def", by either typing the same again, or by typing
*#:
#: just repeats the last ex command, without a need for an <Enter>, in this case the substitution.
You can also record a quick macro to do this using the q command
qd*:s//\0\0<Enter>q
Then repeat it to your hearts content by typing
#d
when over a word you want to double. As this is only one character less than the prior solution, it may not be worth it to you - unless you will be doing other ex-commands between the word-doubling, which would change the behaviour of #:
You need to escape the backslashes within the mapping. You can also include the substitution string within the mapping.
:nmap <leader>w :s/\\(<c-r>=expand("<cword>")<cr>\\)/\\1\\1<cr>
ywPx
will do what you describe.
ywPxw
will also advance the cursor to the next word.
#user11211 has the most straightforward way to duplicate the word under cursor:
yiwP
yank inner word (moves cursor to start of word), paste (before cursor).
eg. straigh[t]forward ----> straightforwar[d]straightforward
[] is cursor
To elaborate...
You probably want to have the cursor following your duplicated word:
yiwPea
straigh[t]forward ----> straightforwardstraightforward[]
NOTE:
yiw
is yank inner word (without whitespace)
yaw
is yank all word (including trailing whitespace).
yawPea
is therefore duplicate word including whitespace, and position cursor.
straigh[t]forward ----> straightforward straightforward[]
" count word (case sensitive)
nmap <F4> :%s/\(<c-r>=expand("<cword>")<cr>\)//gn<cr>

Resources