Complex replacement in gVim - vim

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.

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.

Deleting specific patterns without deleting the whole lines

Say I want to remove all comment blocks in my source code without deleting the whole lines they are on.
It's possible to achieve this using the
:%s/\/\*.*\*\//
command. I was wondering, is there a specific delete command for this, or is replacing the matched pattern the best approach? The difference most likely wouldn't be much, I'm just curious.
Replacing with nothing really is the idiomatic 'delete this pattern' operation.
:%s/pattern//g
If you want to blank all lines that contain a pattern, like in your example, the obvious solution is to add wildcard matches around the pattern.
:%s/.*pattern.*//
An alternative is to use :global with a normal mode or Ex command. These two achieve the same thing:
:g/pattern/normal! S
:g/pattern/delete|put! _
By the way, while I don't recommend using abbreviated command names in scripts or in code that other people might see, I think it's fine to use them interactively. Thus I tend to abbreviate such commands as :g/pattern/norm! S and :g/pattern/d|pu!_.

Is there a way to elegantly comment specific lines in vim search history, similar to " in command-line history?

I am using vim to edit structured text files.
Sometimes I use search-and-replace feature, and sometimes I am better off with search, followed with a macro, in which case I have several macros at hand, and the choice of one depends upon the particular search result.
In both cases, though I have to spend some effort to arrive at an acceptable regex to satisfy my editing needs. As the regexs are often very long and sophisticated, I end up with both command-line history and search history full of my trial-and-error by-products. The correct regex is not always the last one in a series of attempts, so if I want to reuse the hard-earned regex in a similar editing situation, I have to dig through the pile again.
In search-and-replace scenario I have quickly fixed this with comments that I now put in place at the end of a would-be reusable search-and-replace command string, for example:
:%s/very_long_and_sophisticated_regex/another_long_and_sophisticated_regex/gc "comments on what this search and replace command does and how it might be reused
This way I can easily ignore the piles of stuff in my command line history and quickly find relevant re-use candidates, they are shown in different color. The commands are reusable right away, comments are ignored.
Not so with the search history, though.
Having rtfmed and searched the web, I have not found anything similar. At the moment I put quasi-comments using XXX at the end of reusable search strings, for example:
/search_string_containing_very_long_and_sophisticated_regex XXX comments on what it finds and how it might be re-used
This way I can at least find the right string for re-use, but I have to first delete 'XXX' and the comments.
I wonder if there is a more elegant way of commenting the search strings in search history, similar to command-line history.
You used the word "elegant" in your title, and that I don't have on offer. If instead you can also accept a quirky workaround that relies on Vim internals, here's one.
To restate your problem, it is possible to add comments after Ex :commands,
:AComplicatedExCommand -42 -quux " this fizzes the brobble
:HardToRememberCommand test.txt " use this to brew the framble
but the same is not possible for complicated search /queries (or ?queries).
I've just discovered that you can trick Vim by terminating your search query with a literal null byte:
/[Complicated]*regexp/^# this regexp finds all scrobbles
/another\+Rege\x*p/^# use this to search foo bars
The ^# here is a literal NUL. You can enter it by pressing CtrlV and then 000.
Vim will ignore everything after the null byte, but it'll still show the whole line in the search history, including the "comment".
You can add a regexp branch that never matches, e.g. /\%$indicator\|search string
\%$ is a special Vim atom matching the end of the file. Since that will never match when followed by the indicator text, the first branch (up to \|) will never match and therefore can represent your indicator.
I've created the TaggedSearchPattern plugin to make adding the tag and recalling it even easier.

What is the use case of marks?

Both Sublime Text 2 and VIM have a feature called marks. However, I've not been able to find a use case for it. It feels like everything you can do with it can also be done with other things, often even better.
So the question is: what is the use case of marks?
If you mean marking text lines as in vim, I use it quite a bit.
For example, if you want to quickly go look at something else, you can use ma to mark the current line as a, then go check out something else in the file, then return to where you were with a simple 'a.
Similarly, if you want to delete an unknown number of lines between your current position and somewhere else, use ma, go to that "somewhere else, and just use d'a.
There are many more things you can do with them (such as changing text between your current position and a mark), those two are just the most common ones I use (and I use them a lot).

Is there a way to get a snippet to work immediately after a word?

Whenever I try to use a snippet (using snipMate) after a word, without a space, it does not work. So I have to hit space, type my snippet, hit tab, and then eliminate the space. Is there a better way of doing this? Is there a way to get the snipppets to work even immediately after a word? Here is what I mean:
let us say my snippet is this:
snippet test
<some code>${1}</code>${2}
typical use:
hello test[TAB]
turns into this:
hello <some code>|</code>
but if I try this:
hellotest[TAB]
it turns into this:
hellotest_____
the _ being white space. Is there a way to fix this?
Vim abbreviations can be of three types (full-id, end-id, and non-id, cp. :help abbreviations), which help solve this problem. snipMate, however, allows all non-whitespace characters for snippet names, and therefore has to rely on whitespace for separation.
You have to modify the parsing of the snippet name, in plugin/snipMate.vim, it's in the function TriggerSnippet():
let word = matchstr(getline('.'), '\S\+\%'.col('.').'c')
There's no setting to that effect if that's what you ask. You will have to look at the source and do the change there yourself, I'm afraid.
Also, it can probably seen as a limitation but it's definetely not a bug so what you are after is an improvement, not a "fix". My advice, though, is to use it as it was designed: having triggers work even if they are part of another word makes no sense at all. Spaces are the most natural way of separating ideas and words.

Resources