I am searching for an easy way to do search and replace things in vim as a "workaround" for refactoring.
On some other stackoverflow-question I found this snippet of code:
nnoremap gR gD:%s/<C-R>///gc<left><left><left>
I thought gD selects the current word under the cursor in the whole document and %s then search and replaces the matches after I typed the replace pattern.
gc stands for globally with confirmation?!
However: This does not work as expected. For example in some python class of mine I can easy rename occurencies of self in the whole file but it does not work on method identifieres or field identifieres with a length of one.
def __init__(self):
self.test = []
self.A = []
...
So self could be changed using this snippet, but doing gR on the field A simply does not work.
How can I get this work to do an easy search and replace on one file?
Any tips on intelligent refactoring would be also appreciated. After hours of searching I just found plugins and workarounds which work mostly with C files, but I would also need at least Java, Python and PHP compatibility.
Thanks for every answer :)
UPDATE: I recently found out it just works if the initial selected pattern is on the beginning of the line. If the pattern is somewhere in the middle of the line it does not work...any ideas?
gD is "Go to global declaration", see :help gD.
The mapping:
jumps to the 1st occurrence of the word under the cursor in the buffer with gD,
populates the command-line with %s/, meaning "substitute in the whole buffer",
followed by the search pattern used by gD, inserted with <C-r>/,
an empty pair of slashes, //, for the replacement,
the flags gc that mean "do your magic on every match on the line and ask for confirmation",
and goes <left><left><left> to place the cursor between the //, ready for you to type the replacement.
That mapping does exactly what it claims to do, here, no matter how long the word under the cursor is.
Vim is not an IDE, don't expect anything "intelligent".
Related
When I type /foo and then enter, is there a way to mark occurrence for all highlighted words? Right now, the /search seems pretty useless compared to the regular atom search, since it only highlights but doesn't let you replace.
The key / is used for searching, whereas :s for substitutions (i.e. replacements). So to replace foo with bar you can do:
:%s/foo/bar/gc
Here % means look for replacements in the entire file, and the last gc are replacement flags. The Vim documentation provides a great explanation of the topic and it can be accessed by typing :help subs. To learn more about replacement flags: :h flags.
Some more suggestions for a good workflow (at least in Vim itself):
After using /foo to locate a match, and you only want to replace that one: As the cursor is at the start of the match, you can use ce, cE or more generally cgn (gn selects the current / next match; it's a recent addition in version 8.0).
If you want to replace all matches, you don't need to repeat the search pattern in the :substitute command; an empty {pattern} there will recall the search pattern. So, you can briefly write :%s//bar/g (+ c to interactively influence replacements).
It seems I can't mark occurrence if I press enter. However, I can do some things if I haven't pressed enter.
cmd-o marks all search occurrences
ctr-cmd-c waits for you to specify a range, and then changes all search occurrences
This has been bugging me for a while: I'm writing code that uses verilog-auto which means I'm editing in a verilog file with perl snippets injected into comment sections. One very useful thing that I like to do in Vim is to search for the whole word under the cursor with * and #. However, with perl syntax that contains variable names such as ${w} and $w, these shortcuts don't work.
I don't want to add $, { and } to my "keywords" list as there are many instances where I don't want these to count as part of a whole word. For instance, in verilog concatenation: {sig1,sig2[1:0]}, I wouldn't want {sig1 to be searched for as a whole word.
Is there a way to get "whole word" to recognize sequences via a regex or something? So only ${[a-z]+} or $[a-z]+ gets recognized as "keywords".
Either that or a separate keyboard shortcut that can let me search for the pattern under the cursor.
Here's a really ugly hack, but it works:
nnoremap * viW:s/\%V\$*{*\a*}*/\=setreg('a', submatch(0))/n<cr>/<C-r>a<cr>n
nnoremap # viW:s/\%V\$*{*\a*}*/\=setreg('a', submatch(0))/n<cr>/<C-r>a<cr>N
The only downside is that this will overwrite your last visual selection, so if you use gv a lot, this isn't the best solution. It also overwrites the a register, although you could pick a different one if you want.
This question already has answers here:
Vim - Delete til last occurrence of character in line
(5 answers)
Closed 8 years ago.
This is a sentence
If the cursor is on s of This, I want to move the cursor on n of sentence
I can do $Fn
But this can't be used combining with other command like delete
e.g If the cursor is on s of This, and delete all between cursor and n of sentence
d$Fn doesn't work
Anyone knows how to do this?
Assume that you have trouble with deleting words between s and the second n in "sentence". You can do it by
d2fn
And as #kev mentioned, easymotion is a good choice, with easymotion you can do it in a more intuitive way like
d<Leader><Leader>fn
the above command will highlight n in the line and let you choose.
My JumpToLastOccurrence plugin extends the built-in f/F/t/T motions with counterparts that move to the last occurrence of {char} in the line. Your example would be d,fn.
Vim plugin easymotion can help you.
As others have said, you can use the search command / in combination with the d command to delete up to a pattern match.
But, you can also make use of search offsets to place the cursor anywhere you want in relation to that search. See :help search-offset for details, but in your case:
d/senten/e will delete up to and including the second 'n' in "sentence".
You could also use d/sentence/e-2 to do the same thing but limit the match even more.
This is very powerful in combination with incremental search and search highlighting, because then you can see exactly what you're acting on before you hit <Enter> to finish the command, or <Esc> or <C-C> to cancel the whole thing.
You could use visual mode: v$Fnd
My Vim plugin ft_improved can also help. You simply keep on typing until the match is unique.
I don’t know which “n” in “sentence” is referred to here, but you can indeed use d to do this. Simply combine it with search (/):
d/n
Or, if you want to delete up to the second “n” in “sentence”, you could make the search pattern one character more specific:
d/nc
I've to replace all occurrences of a specific macro inside some(only some amongst dozens) C functions. Since the file is thousands of lines long, with several instances of the macro in all the functions, I'd like to replace all occurrences within the particular function the cursor is currently placed.
I know VIM provides navigation commands (like [[ to go to the beginning of the current function, and then % to find its matching closing brace) , but I can't figure out how to use them to come up with the required search-replace command.
Can anyone help ?
Place your cursor on the first opening brace. Then type v% and you will see the function body get highlighted. Then type the replacement command :s/find/replace/g and hit enter. This will replace within the selected function.
Note: You will see you command prompt change to: :'<,'>:s/find/replace/g.
Although I would also recommend dogbane's solution, I thought I'd also mention the NrrwRgn plug-in. It's quite useful for working on a continuous subset of a buffer.
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.