vim search for exact phrase - search

After a long day of yak shaving, getting stuck on something super simple and probably being dumb. Vim n00b('ish) to boot. I'm trying to search for an exact phrase, which works for the first result but moving to any different result (n or * - forward, # - back) permutes the result to the first word.
/__webpack_require__)
matches correctly for the first result, and then proceeds to match only __webpack_require__ going forward or backward.
I am using yadr, so there are a bunch of vim plugins I don't understand (I know, that's a problem, but one for another day). Any help would be appreciated. Googling is a mess on this topic.
** update **
I did try \) but found that actually is not an escape. I also noticed, that searching for function(modules, export, __webpack_require__) also permutes after the first result to function so something I don't understand is happening here that is probably totally normal and useful, but not when you don't understand it.

You should use n to move to the next search result (and N for backwards). * searches for the current word under the cursor which will cause the change to what you are searching for that you are experiencing.

Related

Is there a better method for find and replace in Vim?

Edit: I moved this over to the Vi and Vim site: https://vi.stackexchange.com/questions/13689/how-to-find-and-replace-in-vim-without-having-to-type-the-original-word
I'd like to optimize my "find and replace" workflow in Vim. It's something I do often, as I'm sure most of you do too. Usually something along the lines of -- copy a block and change the name of a variable in a few places. I know, I know, that probably triggers your "why are you copying and pasting code" reflex, but let's not go down that road... There are plenty of valid use cases :)
I'm well aware of the search and replace commands: :s or :%s but I don't like them. It forces me to type out both the full variable name I'm searching for and what I'm changing it to. Maybe there is a better way fix the the amount of typing with :%s? I often use long descriptive variable names, so that is really a deal breaker for me. I also don't like how typing out a variable name from scratch is typo prone and can consume time and brainpower hunting down typos. I much prefer typing it once, and then copying and pasting to just avoid this entirely if possible.
My current workflow uses some combination of movement/yank/select/search/put to move around the file and replace one by one. It is not great but has the benefit of avoiding typing out full variable names. I might just need to type the first few letters with / or use another movement command (i.e. fx) depending on what's around and then hit ve to select the whole word. I also don't mind that I have to repeat for every instance. I never do a full find replace without confirming each change. But it would be much preferable if I could repeat the replacement action with a single keystroke (which I can't do with this method). each replacement is usually something like n then ve then p (or even worse "0p)
Is there a faster way?
My own workflow is similar to yours:
To start, get the cursor on one instance, possibly with / or by navigation.
Hit * to find the next instance of that word.
Change one instance with cw and then the new variable name.
Then it's fast: n/N to get to the next/previous instance, and . to repeat the last edit.
This workflow gives me the same advantage as yours, in that I can review each case before applying the change, but it's just two keystrokes for each additional change.
Hope this helps.
I like the "visual highlight then edit" approach.
shift + v to highlight the region that you want to modify.
then :s/old/new/r where old is what word you want to replace with new.
r changes the first instance of that word old.
Note* There are options other than r which modify its behavior how you want to replace the word.

In Vim, how do I get the total number of matches after doing a search?

I'm wondering if there exists an event or option in vim that detects if there are currently words being highlighted as the result of user doing searching (for example, with :/).
Basically, my Vimscript wants to do something like:
if (search highlight is turned on) and (there is at least one match)
find out the total number of matches
find out the index of current match
Any idea? Thanks.
P.S. The reason why I want this is because whenever I do a search, I have to pay attention to the line number change on the side to be able to tell if the search has reached the bottom of the file. I'd like some sort of indication, maybe on the status bar, that the current occurrence (highlighted word) is, for example, 5/20 out of all occurrences in the file.
There's already a plugin that does this: IndexedSearch: shows 'Nth match out of M' at every search (index of match+total # matches).
Also, have a look at my SearchPosition plugin; it has to be triggered via a mapping, but then shows a lot of information about the (current and overall) matches.
:h v:hlsearch
That variable tells you whether search highlighting is on.
if v:hlsearch && search(pattern, 'cn')
// do stuff
endif
Edit: Updating answer
In order to get the number of matches, one crude way of doing it would be :
redir => num_matches
:%s/pattern//n
redir END
Now the variable num_matches holds the output of :%s/pattern//gn, you can parse it.
Another probably more reliable way to get it would be to actually use search(pattern, 'c') and cycle through all the matches within a loop until you come back to the first, which would give you your desired data.
I like your idea and have coded a solution for it. It has to do a fair bit of work in Vimscript, but it actually runs reasonably well on a 8000-line file.
Suggestions if you want to try this yourself:
It triggers a function call on CursorHold. My function checks to see if we are currently on a match line:
let this_line = getline('.')
if match(this_line, #/) >= 0
...
If we are, then I loop through all the lines in the file, using match() to count the number of matching lines, and find the index of the current occurrence. The only other function I had to use was line().
I will push my script up soon, but this might be enough for you to work with. Thanks for the idea!
Update: Although searching the whole file is quite a lot of work, it seems to perform quite well on a modern machine. In the current version, I only trigger the search when the cursor is on the start of a match, and only if the number of lines in the buffer is below a threshold (default 10,000).
Update: My script is at show_search_occurrence.vim

Complex replacement in gVim

I have been a terrible person as of late when it comes to Minecraft. I have over-modded it to the point that I need to completely re-write the IDs of them all.
The only problem is that... It'll take about a couple of hours jut to re-write them ONCE, not to mention if any of them collide with the original game. So, in order to save time, I figured I'd use Vim, but after reading through several of the helpful posts on here, I still only know a minimal amount about the replacement feature/command. Here's what I'm trying to do:
Replace this
I:exampleModnamePath.id=16389
I:exampleModnamePat2.id=19657
Etc.
With this
I:exampleModnamePath.id=20000
I:exampleModnamePath.id=20001
Etc.
This continues for a while, and to those who answer, could you please inform me of how it works, so I don't have to ask these questions all the time?
For your perusal:
:let g:num = 1
:g/\.id=\d\+$/exec 's!\.id=\d\+$!.id='.g:num.'! | let g:num=g:num+1'
This is slightly simplified version of my code for (re)numbering chapters in the ebooks.
Idea in a nutshell: use :g to run something over affected lines; use :exec to generate/run new substitution command AND increment the counter. Tried it once and was surprised to find that the trick worked. Was inspired by my previous toying with :g//s/// combo.
I'm not sure what is the rule you are using to choose which number to use for replacement but if all you need
is just a new number that doesn't collide with previous ones you could try just replacing the first digit
with something in a range not used. Something like replacing 16389 with 76389
To do that you could use this :s/Path.id=.\(.*\)/Path.id=7\1
That would search for the string Path.id= followed by a single character and then a group of more characters.
I will replace it with the string Path.id=7 and the group previously selected.
You could make it more selectiv adding letters before Path.id to match only certain types of paths.

Vim: delete to next character, when next character is not on same line

I'm sure that I'm going to get ridiculed for asking a duplicate question; someone must have asked the question before! But in an hour of searching I haven't found it. I must be searching for the wrong thing.
In Vi (or Vim) I am able to delete all characters up to the } character through the key sequence dt} (or df} if I want to remove the bracket as well).
However, this only works if the } character is on the current line. What I want to do is to delete everything up to the next } even if it's first occurrence is on a subsequent line.
I'm thinking something like d/} (where the slash /}<enter> in any other context, would take me to the next occurrence of }). For obvious reasons, this doesn't work, but I hope the intention is clear.
== EDIT ==
Okay okay okay... sorry. You're all right, it does work (on my clean-install machine). might be some messed-up mapping in a config file, but it's not working on my other one.
Hang head in shame
d/}<cr> works. It's the canonical way to delete until the next } that's not on the same line. By the way, d?{<cr> does the same but in the opposite direction.
This plugin should save you some keystrokes. It extends the functionality of fFtT,; so they work across lines.
If the character is } or { placed at the beginning of the line, one way could be using Text object motions, so a command like d]] could be useful too.

Find the next occurrence of a variable in vim

I would like to know if/how I can make vim look for the next occurrence of a variable. Let's say the variable's name is simply 'n', then /n would give me all occurrences of that letter, which isn't always terribly helpful. I guess I could create a regex to solve the problem, but I wondered whether there was some command/keystroke I simply don't yet know about; and as all my googling has been to no avail I decided to put a question on here.
Thanks a lot for your help!
If you have the cursor over the variable in question, you can press * and it will search for the next occurrence or # will search for the previous one.
This is equivalent to typing:
/\<n\>
(\< matches on the start of a word and \> matches on the end of word). The only difference (for reasons I'm not sure of) is that * and # don't pay attention to the 'smartcase' option.
See:
:help *
:help /\<
If you press n in command mode it will give you the next match of your search.
More detail:
/ will start forward search
? will start backward search
n will give you the next result in the direction you are searching
N will give you the previous result wrt the direction you are searching in

Resources