News for hackers. Stuff that matters.
Re:Intermediate Vim by jnurmine on Wednesday May 01, 2019 @04:33AM (#19795448)
Maybe you can cover macros since they are conceptually very simple and very powerful.

They may seem a bit complex but are quite simple. Basically you just record your editing movements and play it back.

How macros work: press q x to record and q to end. Then repeat with @ x, where x is the name of the macro you want to use (you can have several macros). Anything you do will be played back. That's it... Conceptually simple.

A nice trick is to record a macro for a single line and place the cursor on the start of the next line at the end of the recording. This way it's possible to operate upon large blocks of text in a similar way by just repeating the macro. The key then is to use generic movements like "go to the beginning of line" (^), "go to the end of line" ($), "skip word" (w), etc.

As a silly toy example, if you have a list of strings in a text file, you can turn it into a list of quotes with (from the top of my head):

  qx<Home>i"<Esc>$i<Right>",<Down><Home><Esc>q
(Record macro, go to beginning of line, insert mode, write a quote, exit insert mode, go to end of line, insert mode, move right, write a quote and a comma, move down to next line, move to the beginning of line, exit insert mode, end macro recording)

Then to process 100 lines, you'd do:

100@x

That turns these:

  alpha
  bravo
  charlie
  delta
  ...
into

  "alpha",
  "bravo",
  "charlie",
  "delta",
  ...
If you have hundreds of lines of that you'll start to appreciate the easy automation.

I use macros to do drive-by mass-edits without resorting to sed, scripting, regular expressions etc. since the cognitive load of those is higher for me.

Edit: formatting

Re:Intermediate Vim by n8henrie on Wednesday May 01, 2019 @10:02AM (#19797038)
My favorite newish-to-me macro trick is to use "recursive macros" -- macros that call themselves at the end, eg `qa[do something]@aq`. The idea (at least for me so far) is to record a line-wise action that goes to the next line before calling itself and will fail on the first non-matching line. For example, if you need to put some text after the first `0`, using commands like `t` or `f` to get there will fail if there is no `0`, but `/` will go to the next `0` on any line.

A macro like this will just keep calling itself until it fails, which is nice for files with thousands of lines and you want to make a change that is not conducive to a regex.

As a tip that took me a while to figure out, you can search within a visual selection using `\%V`, which may make it easier to reliably go to a specific part of the current line (compared to t or f like I mention above).

Also wanted to point out that iVim for iOS is pretty good, for those rare cases you want to do some text processing on the move that makes you miss Vim: https://itunes.apple.com/us/app/ivim/id1266544660?mt=8

A decent post on recursive macros: https://jovicailic.org/2018/06/recursive-macros-in-vim/

Re:Intermediate Vim by Izkata on Wednesday May 01, 2019 @11:06AM (#19797670)
A slight alternative to recursive macros, macros are repeatable actions, so this works: 100@a

I use it so I can run the macro in batches a couple times and check if I made any mistakes, before picking an absurdly high number to hit the whole file.

Re:Intermediate Vim by hhmc on Wednesday May 01, 2019 @11:27AM (#19797954)
Another alternative, visually select the region you're interested in then:

:'<,'>normal @q

to apply the macro (in q) to that region. You might want to remap the above command to some shortcut if you find it useful often.

Re:Intermediate Vim by isostatic on Wednesday May 01, 2019 @04:47AM (#19795495)
I've used vim for a couple of decades, but never pushed to many advanced features. For your example above I'd do :%s/^/"/ and :%s/$/",/

Unless I use a feature regularly I find it's a higher cognative load. I use bash, sed and perl regexps on a near daily basis. Macros are very rare.

Re:Intermediate Vim by chongli on Wednesday May 01, 2019 @08:52AM (#19796566)
For that same example, you can accomplish the job in one substitute command:

    :%s/.*/"&",/
The & special character gets replaced with the whole matched pattern.
Re:Intermediate Vim by mooreds on Wednesday May 01, 2019 @11:33AM (#19798026)
How do you escape the & character? I have been bit by this (not escaping &) a few times but never enough to have found the answer.
Re:Intermediate Vim by Asooka on Wednesday May 01, 2019 @12:00PM (#19798379)
The same way you escape anything - with a \. E.g. if you wanted to substitute the character x with the sequence &/\ you would type

:s/x/\&\/\\

Re:Intermediate Vim by jermy on Wednesday May 01, 2019 @08:12AM (#19796344)
Likewise - with visual mode it's normally pretty quick to select an area and do a basic regex, even for things like re-indentation (auto-completes to something like :'<,'>s/^/\t/) even though I'm sure there's a 'proper' way to do that
Re:Intermediate Vim by Izkata on Wednesday May 01, 2019 @11:09AM (#19797711)
> for indent, < for un-indent
Re:Intermediate Vim by brianpgordon on Wednesday May 01, 2019 @10:01AM (#19797033)
For that example I would open the document in Sublime Text, select all, and split selection into lines so that I have an independent caret on every line. Then I'd just type the quote at the beginning and end of each line - the home/end keys will put each caret at the beginning or end of its respective line.
Re:Intermediate Vim by rbavocadotree on Wednesday May 01, 2019 @10:56AM (#19797549)
I've been using vim a lot recently. Multiple cursors for this exact scenario is the only thing I still miss about other editors.

Macros and other solutions are great, but for this very simple and surprisingly common task, multiple cursors are perfect.

Re:Intermediate Vim by FiddlyPack on Wednesday May 01, 2019 @01:49PM (#19799733)
Multiple cursors has been supported for quite some time now in VSCode, as well as related useful default editor shortcuts like jump cursor by word, beginning/end of line, etc, that are especially useful when moving around multiple cursors/selections simultaneously.
Re:Intermediate Vim by weavie on Wednesday May 01, 2019 @05:11AM (#19795579)
I was going to say that one annoying thing about these macros is you can't press . to repeat the last macro. It is annoying having to count out 143 lines and then do 143@x or what I tend to do is do it in batches of say 20 until I get to the end..

But this has prompted me to look this up and it turns out that you can use @@ to do this. This will make my life a lot easier, I can just smash <Shift 2> until all my lines are updated.

Re:Intermediate Vim by mbudde on Wednesday May 01, 2019 @06:56AM (#19795981)
You can also visual select all the lines and then do

  :'<,'>norm @x
Re:Intermediate Vim by tomsmeding on Wednesday May 01, 2019 @07:32AM (#19796145)
Another notable trick is that vim registers are case-insensitive -- and since macro's are just stored in registers, macro's are case-insenstitive as well. so @q == @Q, which alleviates some of the RSI problems with spamming @q.
Re:Intermediate Vim by n8henrie on Wednesday May 01, 2019 @09:39AM (#19796867)
I remember something about a capital register appending instead of overwriting -- is that only for saving (with no influence in execution)?
Re:Intermediate Vim by majewsky on Wednesday May 01, 2019 @12:19PM (#19798606)
Yes, that's only for writing. For example, to collect all lines matching a pattern into a register with

  :g/pattern/y A
you need to use an uppercase register ("A" in this case) because it executes `y` once per match. With `y a` instead of `y A`, you would end up having only the last match in the register.
Re:Intermediate Vim by y7 on Wednesday May 01, 2019 @09:58AM (#19797012)
I also use a lot of macros. I just learned that macro registers are the same as regular registers, so you can actually paste the contents of a macro and examine it or save it to a file (e.g. "xp after recording your macro).
Re:Intermediate Vim by snarfy on Wednesday May 01, 2019 @08:20AM (#19796393)
I use the . (dot) command a lot out of habit. It executes the last command. If the last command was a macro execution, dot doesn't execute the macro - it executes the last command of the macro. Is there a way to fix this?

edit I see someone else answered this - use @@ instead of .

Re:Intermediate Vim by agscala on Wednesday May 01, 2019 @08:22AM (#19796406)
@@ repeats the last macro
Re:Intermediate Vim by wildmusings on Wednesday May 01, 2019 @08:58AM (#19796603)
Yep, and you can just hold down @ to blaze through many lines. If you overshoot, just undo a bit.
Re:Intermediate Vim by mundacho on Wednesday May 01, 2019 @10:49AM (#19797484)
Another simpler way (even simpler than macros) that works great for simple mass editing is visual blocks. In normal mode, press Ctrl + V and you get to select a literal block of text (not like visual mode, where the text is sequential). Then you can for example, do a "c" to change the selected text in each of the rows that your block covers. This is especially practical to remove a column. Just select the column, press d and voilà.
Re:Intermediate Vim by contras1970 on Wednesday May 01, 2019 @07:28AM (#19796132)
this is somewhat shorter:

    qq0i"<Esc>A",<Esc>jq@@
i agree this example is silly. i'd do something like

    :%s/.*/"&",/
Re:Intermediate Vim by jnurmine on Wednesday May 01, 2019 @09:54AM (#19796983)
Yeah, it is a toy example on purpose.

Macros really shine when you need to do a bit more complex stuff, there is certainly a cutoff between ease of regex "from the top of my head" vs. spending time formulating it.

Re:Intermediate Vim by A2017U1 on Wednesday May 01, 2019 @07:15AM (#19796073)
This is really neat, thanks for rundown. Its easy to get far too comfortable with ad-hoc sed commands when there's far better solutions out there.