7 ms·
The article mentions ”gn” in passing, but it doesn’t give it enough credit: this is an enormously useful motion, almost more useful on its own than the rest of
by OskarS 6y ago
The article mentions ”gn” in passing, but it doesn’t give it enough credit: this is an enormously useful motion, almost more useful on its own than the rest of the article.
The thing that makes it golden is that it is a motion, and thus combined with a command, it is repeatable! So, like:
1. Search for something (either using / or *).
2. Type ”cgn” in Normal mode (i.e. change next search match) and replace what you searched for with whatever
3. Hammer on ”.” (i.e. repeat last command) to replace other matches.
This replaces, like, 97% of uses of :s and is a much more convenient way to do search/replace, especially if you use * to search for the word under the cursor. It’s the bee’s knees!
- throwoutttt 6y agoAs someone who uses this regularly, it's still not as convenient as multi cursors that most modern ides give you. There's a vim extension for multiple cursors but it's a little buggy.
- OskarS 6y agoI dunno, I’ve also used both, and I keep coming back to the Vim/gn way of doing it, I just like it more. I see how people can feel otherwise, though.
- boogies 6y agoYeah, not everyone is the same, but there are definitely people interested in multi-cursor modal editors, enough to build their own, eg. vis⁰ — a light, fast, and simple text editor with a pretty standard vim normal mode but sam’s structural regex command language¹ for creating and procedurally editing selections in command mode², and kakoune³ — known for switching vi’s word order from verb noun to noun verb, so typical normal mode commands work by first creating one or more selections with motions (no need to press v), and only then operating on them. And of course Emacs has multi-selection modes and AFAIK they’re compatible with evil. ⁰https://sr.ht/~martanne/vis/ https://sr.ht/~martanne/vis/ ¹http://doc.cat-v.org/bell_labs/structural_regexps/ http://doc.cat-v.org/bell_labs/structural_regexps/ ²http://doc.cat-v.org/bell_labs/sam_lang_tutorial/ http://doc.cat-v.org/bell_labs/sam_lang_tutorial/ ³http://kakoune.org/ http://kakoune.org/
- lucb1e 6y agoAs someone who never used a multi-cursor IDE (I've seen other use it but not in a convincing way): what's something that you use this for that you don't think vim can do? The main purpose I've seen is basically block mode (like ctrl+v) or (iirc) repeating things on multiple hits (like n. or indeed cgn).
- usmannk 6y agoWhy is this preferable to :%s?
- RMPR 6y agoI find it more intuitive, and for a small number of iterations it's definitely faster.
- simias 6y agoIt composes better if you were searching for something and then want to replace it IMO. You basically just have to remember the search syntax and then you can reuse it for replacing. It's also better if you don't actually want to replace in the whole file and there's no convenient shorthand for the range. I very rarely use :s myself, I'm always too worry that I'm going to clobber something I didn't mean to, I prefer to search and manually repeat a substitution. s can do it with with the "c" modifier but I find that using normal edit commands is both more flexible and easier to remember.
- kadonoishi 6y agoIt allows you to use a full Turing machine rather than restricting yourself to a Finite State Machine.
- asicsp 6y agoOoh, sounds interesting. I'll have to look up the details. I currently do this after a search with / and regex (if it is a bit complicated) :%s//replace/gc
- stjohnswarts 6y agoThis is what I do, I use regex's so often it's easier for me to read this even if it's a little bit more typing
- RMPR 6y agoAwesome, that's definitely something I'll add to my bag of tricks. But > This replaces, like, 97% of uses of :s and is a much more convenient way to do search/replace, especially if you use * to search for the word under the cursor. It’s the bee’s knees! I'm not really sure about that. I can definitely see it replacing :s for a small number of repetitions, but for a large number. I think using :s with a range is quicker. Edit: typos, punctuation
- thesteamboat 6y agoI too wish to add this to my repertoire. I don't think it will replace :s, but occasionally I find myself copying a line to use as a template. When I go to change each line I'm changing a particular part to different things. Assuming I remember, this trick seems like a good approach.
- nightcracker 6y agoThis has one huge shortcoming: when the next match is off-screen, pressing . jumps immediately to the next match and replaces it, before you had the opportunity to review whether you want that. To solve this I wrote a little plugin (that I finished as a plugin yesterday and uploaded just now): https://github.com/orlp/vim-quick-replace https://github.com/orlp/vim-quick-replace It requires vim-repeat (and a patched one because the current one has an issue): https://github.com/orlp/vim-repeat https://github.com/orlp/vim-repeat The nice thing is that it always jumps to the next match before replacing, and if you choose to replace the current match it immediately jumps to the next one, so that you can evaluate whether you want to replace it. You can start in two quick ways: using the current word under the cursor or the current visual selection, so it's very flexible. For me replacing a variable name is often just putting my cursor on it, pressing space + r, typing the replacement name and then a couple .'s, n's and if I mess up some u's. To see it in action: https://i.imgur.com/wEX6O1w.mp4 https://i.imgur.com/wEX6O1w.mp4
- tasty_freeze 6y agoI'm not sure exactly what your plugin does, but are you aware of the "c" flag to substitute, eg :%s/debug/dbg/c vim will show the text which is about to be modified, and you have a prompt to confirm, skip, or quit (and some others).
- nightcracker 6y agoYes, I am aware, but it's not nearly as flexible and quick. It doesn't allow me to in the meantime move my cursor around, switch buffers, undo, open/close a fold, etc. It takes complete control of your workflow to temporarily put you in some special 'search/replace mode' in a very non-Vimlike manner. My plugin has a simple operation (if cursor is on a match, replace, regardless jump to next match) that gets repeated with ., combined with nN and u and you have complete control while also rapidly doing search/replace. And you would still need some nice mappings to substitute the word/selection underneath the cursor with :%s///gc.
- chrismorgan 6y ago
- deleted 6y ago[deleted]
- mushishi 6y agoJust tried this. Note for others: between 2. and 3. you need to get back to normal mode (which is kinda obvious but...) Thank you for the tip.
- thanato0s 6y agoYeah I know the trick and I explain it a bit more in another article on my blog. Most of the time it's more keystrokes than using :s though, so I'm not a big fan of it. But I see the appeal :)
- typon 6y agoI'm paranoid and I like seeing exactly what I'm replacing. In that case I still use :s but I always end it with :s/foo/bar/gc. Although I do see the appeal of cgn for simple replacements.
- thanato0s 6y agoIf you use Neovim, you can set the option inccommand: set inccommand=nosplit It will display the substitute directly in the buffer.
- simias 6y agoOh man, I knew there had to be a way to do that but I couldn't find it, so I always resorted to counting the number of characters in the match and then use cl<num> to replace it if there was no convenient motion like some kind of barbarian.
- bobbyi_settv 6y agoThe non-barbarian way to avoid counting characters when there's no convenient motion is visual mode. Hit v, then hit l until you've highlighted the part you want to change, then hit c to start changing it.
- simias 6y agoOh I never thought about that either. Thank you.
- bobbyi_settv 6y agoI rarely actually do it because f and t motions, possibly with a number, can usually handle these cases. For example, c3tA to change up to but not including the third capital A after the current position
- tasuki 6y agoIf it's more than one 'A' I'd use visual mode. I'm always impressed people can accurately count up to like three ;)
- gnubison 6y agoc<num>l is equivalent to <num>s (unless you've installed a plugin that binds s to something else).
- erostrate 6y agoThank you so much! I've been using Vim for 5 years and I always thought :s was one of the major pain points.
- aaimtts 6y agoThis is very useful, thank you! How would you go about pasting the "replace" part though? I could only think of this rather awkward sequence: 1. Yank to named register 2. Search 3. "cgn" 4. Ctrl-R to paste from named register 5. Repeat This is actually the biggest gripe I have with vim, even after almost 10 years of constant use. Vim always seems to overwrite the default register when I don't want it to. This makes replacing multiple bits of text with one pasted value awkward. I feel like I'm missing some essential shortcut or configuration that everybody else knows. It can't just be named registers, right?
- tvrg 6y agoYou can slightly simplify your workflow using the yank register 0. 1. Yank using y without specifying a register ... 4. CTRL-R 0 Deletes and changes don't touch the 0-register. It always contains your last (unnamed) yank.
- petepete 6y agoSo I've been using vim for nearly twenty years and didn't know this. I also never touch visual mode make any advanced use of buffers or marks. I feel like some kind of caveman now.
- trigoman 6y agoI was looking on how do this exact thing! Thank you! In IntelliJ I press Alt+j to add to selection then I can edit all matches. You just described how to do the same effect in Vim
- johncoltrane 6y agoMaybe you will like these little gems I came up with back when the gn patch was merged: nnoremap <key> *``cgn nnoremap <key> #``cgN Hit <key> to change the current word and ... to repeat on the next occurrences.
- lucb1e 6y agoI used to do n.n.n.n. to do the same (i.e. /search something, then do the replacing with something like cw or 3s or ct' or whatever you want, and then hit n for next result and . to repeat the change). Using cgn is less flexible and you need to learn another thing (you know about n and . already by the time you get to cgn), and maybe it's just me but hitting n. repeatedly is practically equally fast as just hitting the dot. It also has the downside that it doesn't match what is being shown: when I hit * on "overview" it highlights both "overview" and "Overview" (I have highlight search enabled), but cgn replaces only one of them. When the cursor is on Overview and I run "*cgnexample<esc>..." it will skip all the "Overview"s and only replace "overview". But perhaps it's a bug in Vim since it works when I run * on the lowercase variant.
- Skunkleton 6y agoThis might be the right audience for this little vimrc tidbit: "Press space to highlight current word nnoremap <silent><space> \ :let @/='\<<C-R>=expand("<cword>")<CR>\>'<CR>:set hls<CR> This works just like *, except that it leaves your cursor where it is. You can then use n/p/whatever as normal.
- lucb1e 6y ago> like * but leaves your cursor where it is Ooooh that is great! I use *# every time and am then annoyed when the n key goes backwards instead of forwards and then I try to remember to do #* instead and pff... ^^ This will solve those issues!
- revscat 6y agoThis is useful enough that I wonder why you chose not to just map it to *. Is there a reason you did not?
- Skunkleton 6y agoBecause <space> is even easier to hit :) Edit: also because I try and keep my keybinds as close to default as I can, and <space> is oddly underused.
- hpfr 6y agoThe author does mention this in an in-depth article on search: https://thevaluable.dev/vim-search-find-replace/ https://thevaluable.dev/vim-search-find-replace/ It's pretty comprehensive. Personally I'd just install Doom Emacs though :)
- sanderjd 6y agoThat does sound useful, but I do this with `:s/foo/bar/gc`, then I press `y` each time, which is pretty similar to pressing `.` each time in your example. I do like that the `cgn` approach works better for something you searched for without knowing a priori that you were going to do a replacement on it.
- u801e 6y agoI've done this by setting the / register with * as you mentioned, but I still use the :s command, type / and then use the ctrl-r / key combination to paste the contents of the / register, then type the second / and then the replacement. The g and z set of commands are pretty useful in vim.
- edanm 6y agoYes, and here's my favorite vim trick I ever invented - you can do use this after changing a word. What I mean is: if I'm on a (say) a variable name, and I change it with "cw", then realize I actually need to change it in a few more places, I can use a little shortcut to change it in those places, without even thinking of it beforehand. The shortcut is: " Make <leader>. repeat the last "change word" command. nnoremap <leader>. :let @/=@"<cr>/<cr>cgn<c-r>.<esc> After any change command, just hit <leader>. to repeat it. You can thereafter hit "." to repeat again.
- nandkeypull 6y agoNice, it works in evil-mode on emacs as well! Although for emacs I would just use query-replace, which does the same thing with y/n confirmation, and it can also be run on just a selected region if desired.