3 ms·
Suppose a range of lines contains function calls in some programming language: i = foo(a, 42, 1) j = bar(b, c, 100, 2) # this is a comment (well, duh)
by rav 11y ago
Suppose a range of lines contains function calls in some programming language:
i = foo(a, 42, 1)
j = bar(b, c, 100, 2) # this is a comment (well, duh)
bazbar(etc, 3)
You want to edit the last parameter in each function call -- change it to 'hello'. I have two ways of approaching this: macros (interactive) or :norm (less interactive).
1. Put your cursor on the first byte in the first line, type qq to record a macro of your change, q to finish. Select the rest of the lines in visual line mode and type :'<,'>norm @q to run the macro on each of the remaining lines.
2. Select the lines in visual line mode and type, for instance,
:'<,'>norm %F,ws'hello'
This is the "non-interactive" version of the above since the macro keystrokes are given directly to :normal. Pro: ability to undo keystrokes unlike when recording a macro. Con: cannot actually see the effect of the keystrokes (but with practice, this is not a problem).
(Note that colon in visual mode automatically inserts the :'<,'> so you only have to type :norm ...)
I find the declarative nature of regexes/:s to be too restrictive -- I much prefer the operational nature of macros/:normal, since that lets me make the change I want directly, without me having to phrase the change as a regular expression.
I could also use CTRL-A in normal mode to increment the last argument in each line:
:'<,'>norm %b^A
(where ^A is the literal, typed CTRL-V CTRL-A)
I feel like a wizard whenever I use :normal in a non-trivial manner.
- solarexplorer 11y agoIsn't :%s/.)/hello)/ simpler? Maybe that's because I know nothing about macros. Thanks for the explanation.
- rav 11y agoPardon, it might have been a trivial example. I managed to find a real-world example I encountered in February this year. The PAPI library has a utility program papi_avail which prints a table of supported performance counters. The lines may look like this: PAPI_VEC_SP 0x80000069 Yes Single precision vector/SIMD instructions PAPI_VEC_DP 0x8000006a Yes Double precision vector/SIMD instructions PAPI_REF_CYC 0x8000006b No Reference clock cycles For a course project, I wanted to turn this into a C-array like this: {PAPI_VEC_SP, "Single precision vector/SIMD instructions"}, {PAPI_VEC_DP, "Double precision vector/SIMD instructions"}, {PAPI_REF_CYC, "Reference clock cycles"}, Using :norm, this transformation can be achieved in the following way: :'<,'>norm I{^[eldedecw, "^[A"}, (where ^[ is a literal escape, typed CTRL-V ESC.) Anecdotally, it is faster for me to type up such a line than an equivalent regular expression, since I use vi normal mode commands much more than regular expressions.
- solarexplorer 11y agoI would have piped this through awk, but this is probably better done with macros. Thanks for taking the time to elaborate. I will definitely give macros a try.
- pestaa 11y agoI just spent minutes to parse that instruction. Mind blown. Thank you for this enlightenment.
- rav 11y agoYou need to know how dw, de, cw, ce relate to each other, when the cursor is on a token character vs. a whitespace character, and so on, in order for this to be truly useful -- but luckily, ordinary practice with those commands in Vim can lead to an efficient internal idea of how it works. "You get used to it, though. Your brain does the translating. I don't even see the code. All I see is blonde, brunette, redhead."
- foolinaround 11y agothis is awesome, can you please suggest some resources for me, a long-time basic user of vim, ( know a lot of commands for actions, but not the underlying relationships?
- jedmeyers 11y ago/^\(\S*\)\s*\S*\s*\S*\s*\(\p*\) :%s//{\1, "\2"}, "Now they have two problems."
- rylee 11y agoI would have almost simply started recording a macro, convert the first one using as many idempotent normal mode commands in place of insert mode commands as possible, and simply replayed it. Thanks for the idea. As a side note, I love how Vim is basically a functional programming language for text editing.
- chatmasta 11y ago
- linschn 11y agoI guess that would change the comment : "duh)" would become "hello)", whereas the macro does not.
- sharmajai 11y agoNo, not without a 'g' at the end.
- aidos 11y agoLord, that's so useful. I normally include a move to next line part in my macro and then guess at how many times to run it (20@q, repeat until I get it right). It's actually the main reason I often don't bother using macros. This is such a great tip. Thanks!
- rav 11y agoYou can combine regexes with macros if you only wish to run your macro on a particular set of lines: :'<,'>g/foobar/norm @q will run the macro only on the subset of selected lines that match the regex "foobar". :g/.../ will match the regex against all lines in the file.
- weaksauce 11y agoI love the g command. Very useful to quickly cull out lines of stuff that you don't want in your file. g/foobar/d
- marcoperaza 11y ago@@ applies the previously applied macro, so after applying the macro (including the move to next line, but see below too) you can you just hold down @ and quickly go through as many lines as you need. If you overshoot, you can just press u a few times. Another tip: when you forget to add the move to next line to your macro, you don't have to start over. You can append to a macro, just use the upper-case register name instead. So to append a down and move to beginning of line to macro 'a', you'd type qAj0
- aidos 11y agoBoth useful tips. I knew the macro is really just replaying whatever is in the register but it's good to connect the append dots to the equation.
- pyvpx 11y agocare to suggest any resources that helped you reach wizard-like levels of usage? I very much wish to work towards that kind of ability in vi/vim.
- rav 11y agoI am sorry, but I don't know any resources... I have collected a few things on the following page: http://users-cs.au.dk/rav/vim/ http://users-cs.au.dk/rav/vim/ Basically, I achieved my wizard-level C++, Vim and Git knowledge during my three years as a part-time student programmer in the basic research center MADALGO. I took the time to study the documentation (respectively the C++11 draft, :help and the git man pages) whenever I was curious. For Vim in particular, I made sure to eliminate all repeated keysmashing in my daily workflow, which "unfortunately" required me to learn about macro wizardry. My only advice is to keep practicing, to keep trying to spot inefficiencies in your own workflows, and to actively eliminate these inefficiencies by studying the Vim help pages.
- bch 11y agoOver the years, I've got a lot of mileage out of "Learning the vi and vim Editors" from O'Reilly, and web pages like http://www.lagmonster.org/docs/vi.html http://www.lagmonster.org/docs/vi.html. Practicing and testing compositions based on what you learn from these will go a _long_ way. Try new ways to move (by screens, by sentences, by blocks), test using your buffers, experiment w/ transforms. Then, one day, you realize you're pretty good with vi.
- mkehrt 11y agoI like http://learnvimscriptthehardway.stevelosh.com/ http://learnvimscriptthehardway.stevelosh.com/ , which covers a different set of features.