Is it possible to interactively delete matching search pattern in Vim? - vim

There is a phrase that I want to look for in Vim. When found, I want to delete that occurrence of the phrase. What is the easiest way to cycle through all the occurrences (via n), and delete a match one by one (I do not want to delete all of them at once).
Note: I know I can delete a certain number of characters or a number of words, but I want to specifically remove the match of my search. Is this possible?

http://vim.wikia.com/wiki/Search_and_replace
Try this search and replace:
:%s/foo/bar/gc
Change each 'foo' to 'bar', but ask for confirmation first.
Press y or n to change or keep your text.

There are 3 ways I can think of:
The way that is easiest to explain is
:%s/phrase to delete//gc
but you can also (personally I use this second one more often) do a regular search for the phrase to delete
/phrase to delete
Vim will take you to the beginning of the next occurrence of the phrase.
Go into insert mode (hit i) and use the Delete key to remove the phrase.
Hit escape when you have deleted all of the phrase.
Now that you have done this one time, you can hit n to go to the next occurrence of the phrase and then hit the dot/period "." key to perform the delete action you just performed
Continue hitting n and dot until you are done.
Lastly you can do a search for the phrase to delete (like in second method) but this time, instead of going into insert mode, you
Count the number of characters you want to delete
Type that number in (with number keys)
Hit the x key - characters should get deleted
Continue through with n and dot like in the second method.
PS - And if you didn't know already you can do a capital n to move backwards through the search matches.

1. In my opinion, the most convenient way is to search for one
occurrence first, and then invoke the following :substitute command:
:%s///gc
Since the pattern is empty, this :substitute command will look for
the occurrences of the last-used search pattern, and will then replace
them with the empty string, each time asking for user confirmation,
realizing exactly the desired behavior.
2. If it is a common pattern in one’s editing habits, one can
further define a couple of text-object selection mappings to operate
specifically on the match of the last search pattern under the cursor.
The following two mappings can be used in both Visual and
Operator-pending modes to select the text of the preceding match
of the last search pattern.
vnoremap <silent> i/ :<c-u>call SelectMatch()<cr>
onoremap <silent> i/ :call SelectMatch()<cr>
function! SelectMatch()
if search(#/, 'bcW')
norm! v
call search(#/, 'ceW')
else
norm! gv
endif
endfunction
Using these mappings one can delete the match under the cursor with
di/, or apply any other operator or visually select it with vi/.

The best way is probably to use:
:%s/phrase//gc
c asks for confirmation before each deletion. g allows multiple replacements to occur on the same line.
You can also just search using /phrase, select the next match with gn, and delete it with d.

Related

vim: command like f{char} but for series of chars instead of single char

In vim I can navigate to char in current line using f{char} -- To [count]'th occurrence of {char} to the right. The cursor is placed on {char} (inclusive).
Lets look on next line:
from fmodule import futility
-- there are three words starting from f letter and assume that I want to jump to futils. To do it (with cursor at the beginning of line) I will execute 2ff, but instead I would really like to do something like f{fut} (providing first chars of word not single one).
What are the ways to accomplish this task?
You can use the / search as a motion, also in visual mode and in combination with a command like d. You need to conclude the search with <Enter>, as usual. In contrast to f, this will also find matches in following lines. Some consider this a feature (and change f accordingly via plugins), others don't like this. If you're in the latter camp, the following mapping will restrict the pattern to the current line automatically:
noremap <expr> <Leader>/ '/\%' . line('.') . 'l'
You might also want to define <Leader>? for the opposite direction.

VIM: Change current highlighted search term matched with /search

Is there any command equivalent to "delete until the end of the current highlighted search match and enter insert mode"?
For example, I search for a term with:
/Element
It finds the string ExampleElementExample, places the cursor on the E in Element, and highlights Element.
I would like a generic command that applies to all searches that is equivalent to c7l or ctE in this particular case. However, I also want to be able to easily repeat this command to the next match by pressing n, ..
c//e basically does what I want, but falls short because it replaces the current search buffer, so n no longer takes me to the next match. Right now I'm using ctE or visual mode, but I feel like there must be a better option.
What is the fastest and most efficient way to execute this command?
If your Vim is recent enough (7.3 with a patch-level above 6xx), you can use gn:
barbazfoobazbar
/foo<CR>
barbaz[foo]bazbar
cgnvim<CR>
barbazvimbazbar
You can hit . to jump to the next foo and change it to vim in one go.
See :help gn.
I think the best option would be to use search and replace with the confirm flag.
:%s//replace/gc
If you leave the search string empty, it will automatically use the current search string. By the c flag, it asks you for permission to replace and upon decision, it will move to the next match. The g flag will find all matches, not just the first on a line, which I hope is what you are looking for.
You can use the following custom text object taken from Copy or change search hit on the Vim Tips Wiki:
" Make a simple "search" text object.
vnoremap <silent> s //e<C-r>=&selection=='exclusive'?'+1':''<CR><CR>
\:<C-u>call histdel('search',-1)<Bar>let #/=histget('search',-1)<CR>gv
omap s :normal vs<CR>

How to move through words in camel-cased identifiers in Vim?

How to move the cursor before or after the first uppercase letter of a word in Vim?
My motivation is removing or selecting the first word of a camel-case identifier in code. For example, if the cursor is on the m character in the word camelCase, I can use the FcdtC sequence of Normal-mode commands to delete the camel prefix.
Is there a general way to jump to the next occurrence of an uppercase letter in an identifier?
In situations where approaches using only built-in Vim instruments are
preferred, the following search commands can be used.
For jumping to the next uppercase character:
/\u
For moving the cursor one character to the right of the next uppercase
character:
/\u/s+
or
/\u\zs
If one expects to use a movement like that often, one can always
define a key mapping for it as a shorthand, e.g.:
:nnoremap <leader>u /\u/s+<cr>
I don't think there is anything built-in.
As #ib. indicates, you can use a regular expression motion, but it’s not particularly easy to type. However, there is camelcasemotion plugin that adds the necessary motions, for this, as well as underscore seperated identifiers.
Updated Answer (using #ib.'s contribution)
"select from first char up to First uppercase letter ( after first char )
map ,b bv/[A-Z]<cr>h
Original Answer
Regarding jumping before and after the first uppercase letter—
You can map it if you want to.
"Before next uppercase letter
map ,A /[A-Z]<cr>l
"After next uppercase letter
map ,B /[A-Z]<cr>h
:D. Hope this helps. I'm reading your second question now.
Ok, read it. Now you can do this
bv,A
:D
I think I thought maybe "the vim way" to do it :
Vim allow us to define our own operator !
" movement mapping {
" Delete yank or change until next UpperCase
" o waits for you to enter a movement command : http://learnvimscriptthehardway.stevelosh.com/chapters/15.html
" M is for Maj (as in french)
" :<c-u>execute -> special way to run multiple normal commande in a map : learnvimscriptthehardway.stevelosh.com/chapters/16.html
onoremap M :<c-u>execute "normal! /[A-Z]\r:nohlsearch\r"<cr>
That way giving
DailyAverage.new(FooBarBaz)
If my cursor is on a (from DailyMesure) and I press dM It delete to A and give
Average.new(FooBarBaz)
It works with all command waiting for a movement (c y ........)
This snippet need to be improved because of bad highlight.

Vim whole word search - but faster

I know that to search for a whole word in vim you need to type:
/\<word\><CR>
Now, what I would like to do is to map this behaviour to ? (as I never search backwards, and if needed I could search forward and then NN). I.e. I'd like to type:
?word<CR>
and have the same result as above (vim searches the whole word). I've been fiddling around with vim commands and mappings for some weeks now, but I'm not sure about how to accomplish this one. Thank you for any help.
Update: (insead of ? I use \ now).
I tend to use * and # (as suggested by Brian Agnew), but if you want a method that involves typing
?word<CR>
you could do something like this:
function! SearchWord(word)
let #/ = '\<' . a:word . '\>'
normal n
endfunction
command! -nargs=1 SearchWord call SearchWord(<f-args>)
nmap ? :SearchWord
Note there is a space after SearchWord on the last line.
Explanation:
The mapping will make ? open up a command prompt and type SearchWord (including the space). The command makes SearchWord myword do the equivalent of call SearchWord('myword') (i.e. it puts the quotes round the argument in order to make it into a string). The function sets the search register #/ equal to your word surrounded by \< and \> and then does a normal-mode n to find the next instance of the contents of the search register.
Of course you lose the benefits of incremental searching if you do this, but hopefully it's useful anyway.
You can search for words under the cursor using * and # (forwards and back). g* and g# will do the same but finding words containing what's under your cursor initially.
Obviously (!) you need to have found the first instance already for this to work, but it's very effective for successive searches.
Al's solution is very nice, but wouldn't it be simpler to just enter the \<\> pattern, then move the cursor back twice? This works for me:
nmap ? /\<\><Left><Left>
This way you still get incremental search (kinda).

How to quickly change variable names in Vim?

I am using Vim to read through a lot of C and Perl code containing many single letter variable names.
It would be nice to have some command to change the name of a variable to something more meaningful while I’m in the process of reading the code, so that I could read the rest of it faster.
Is there some command in Vim which could let me do this quickly?
I don’t think regexes would work because:
the same single letter name might have different purposes in different scoping blocks; and
the same combination of letters could be part of another longer variable name, a string literal, or a comment.
Are there any known solutions?
The following is how to rename a variable which is defined in the current scope {}.
Move your cursor to the variable usage. Press gd. Which means - move cursor to the definition.
Now Press [{ - this will bring you to the scope begin.
Press V - will turn on Visual Line selection.
Press % - will jump to the opposite } thus will select the whole scope.
Press :s/ - start of the substitute command.
<C-R>/ - will insert pattern that match variable name (that name you were on before pressing gd).
/newname/gc<CR> - will initiate search and replace with confirmation on every match.
Now you have to record a macros or even better - map a key.
Here are the final mappings:
" For local replace
nnoremap gr gd[{V%::s/<C-R>///gc<left><left><left>
" For global replace
nnoremap gR gD:%s/<C-R>///gc<left><left><left>
Put this to your .vimrc or just execute.
After this pressing gr on the local variable will bring you to :s command where you simply should enter new_variable_name and press Enter.
I know it's an old question, and #mykola-golubyev's way obviously IS the best answer for the particular case in the OP question (which, I assume is going through obfuscated code where you're likely to have multiple blocks with same var names); but with the question name like that many people coming here from google searches probably look for less situation-specific ways to rename variables in VIM -- and those can be more concise
I'm surprised no one suggested this way:
* :s// NEWNAME /gc
The * is the same as gn - search the next occurrence of the word under the cursor AND make it the last searched pattern; you can then omit the search pattern in the substitute command and VIM will assume that last one is the pattern to search for.
For small amounts of var copies, here's an even quicker one:
* cw NEWNAME <esc> then repeat n. for other occurrences
* is search for occurrences, cw is change word, n goes to the next occurrence of the last searched term and . repeats the last command (which is now change word to NEWNAME)
(Credits for me knowing all this go to #doomedbunnies on Reddit)
Another cool trick: (credits to #nobe4)
* cgn NEWNAME <esc> then repeat . for other occurrences
cgn is "change whatever is the result of (find next occurrence)". Now that this is the last command, you don't need the n to go to the next occurrence, so fewer strokes again, and, more importantly, no need to alternate n and .. But, obviously, this one has the drawback of not having a way to skip an occurrence.
Here are some benefits of these over other similar approaches, or language-specific plugins with refactoring support:
no command mapping, no fiddling with .vimrc(or init.vim), so you can use it in any VIM copy you come across (e.g. a quick task on some VPS or your friend's machine where configuring VIM your way would defeat the purpose of 'quick')
using * or gn for word selection is very quick -- just one keystroke (well, let's say 1.5)
using * or gn makes sure you don't get any matches inside other words, just as :%s/<C-R>//gc does. Beats typing the :%s/\<OLDNAME\>/NEWNAME/gc by hand: I personally tend to forget to use the \< things to limit matches to whole words only.
Not using a scope will only result in a few extra strokes of n to skip unwanted matches -- probably even fewer than the extra strokes needed to limit the scope to a certain code block. Under normal circumstances, your variables are most likely somewhat localised to a certain code block anyway.
AFAIK, there is no actual refactoring support in VIM. When doing a rename with the intent of a refactor I usually take the following precautions:
Limit the scope of the change my using marks.
When entering the regex, bracket the name with \< and >. This will make it match an entire word which reduces the types of incorrect renames that will occur.
Don't do a multiline replace to reduce chances of a bad replace
Look through the code diff carefully if it's anything other than a small change.
My end change looks something like this
:'a,'bs/\<foo\>/bar
I would love to be wrong about there not being a refactoring tool for VIM but I haven't seen it.
Put this in your .vimrc
" Function to rename the variable under the cursor
function! Rnvar()
let word_to_replace = expand("<cword>")
let replacement = input("new name: ")
execute '%s/\(\W\)' . word_to_replace . '\(\W\)/\1' . replacement . '\2/gc'
endfunction
Call it with :call Rnvar()
expand("<cword>") gets the word under the cursor. The search string uses % for file-scope, and the \(\W\) patterns look for non-word characters at the boundary of the word to replace, and save them in variables \1 and \2 so as to be re-inserted in the replacement pattern.
You could use the 'c' modifier in the global search and replace that would ask you for confirmation for each replace. It would take longer but it might work for a non-humongous code file:
%s/\$var/\$foo/gc
The c stands for confirm.
In c, you may be able to make some progress using cscope. It makes an attempt at understanding syntax, so would have a chance of knowing when the letter was a variable.
If this is across multiple files, you may consider taking a look at sed. Use find to grab your files and xargs plus sed for a replace. Say you want to replace a with a_better_name in all files matching *.c, you could do
find . -name "*.c" | xargs sed -i -e 's/a/a_better_name/g'
Bear in mind that this will replace ALL occurrences of a, so you may want a more robust regex.

Resources