0

Part of a macro I'm writing deletes any blank lines, and then does some more work (joining the expected two remaining lines and then appending to them). Simplified version:

let @m=':g/^$/d^MggJA ^['

(Where of course ^M and ^[ are the CR and ESC literals.)

However, sometimes my input doesn't include any blank lines, and I can't get the macro to proceed when the :g command fails:

Pattern not found: ^$

(Same happens with different message when I try :v/./d instead: Pattern found in every line: .)

I got my hopes up when I found How to force macro keep running even pattern is not found?, where the answers suggest using :try, but this doesn't seem to work with :g or :v:

:let @m=':try|:g/^$/d|catch||endtry^MggJA ^['

If this is run on input with no blank lines, it leaves the editor in command-line mode and I have to type endtry to get out of it. I try adding an additional endtry to the macro:

:let @m=':try|:g/^$/d|catch||endtry^Mendtry^MggJA ^['

This works for input with no blank lines. But when I go back and try this on input that contains blank lines, I get

E603: :catch without :try

Is there any hope to be had here?

2

I agree with @BLayer that you're crossing into territory where putting this into a function would be a good idea. A nice short way to suppress errors is :silent! (with !). It'll work in your macro like this:

let @m=':silent! g/^$/d^MggJA ^['

This is shorter than try...catch; one side effect is that it silences any output (errors or normal output). With :global, that shouldn't be a problem; elsewhere, it can be avoided via the (somewhat funny) :silent! unsilent {cmd} expression.

2

It's at this point where you ought to consider alternatives to using a macro. For instance, a function and mapping. Off the top of my head...

func! DelEmptyAndStuff()
    if search('^$', 'n') != 0
        exec 'g//d'
    endif
    exec 'norm! ggJA '
endfunc

nnoremap \m :call DelEmptyAndStuff()

(Note: without a pattern :global will use the last used pattern. That's why g//d works here.)

Even a mapping alone with the above code stuffed in it will be easier/cleaner than the equivalent macro...

nnoremap \m if search('^$', 'n') != 0 \| exec 'g//d' \| endif \| norm! ggJA <CR>

But, okay, let's say you are "contractually bound" to use a macro. We could use a modified version of the above code...

let @m=":if search('^$', 'n') != 0^Mexec 'g//d'^Mendif^M^[ggJA ^["

Not pretty but since "the halt on error" behavior of macros probably isn't meant to be defeated...at least this works.

  • 1
    Great, thanks! I'm enough of a noob that I'd not even considered a non-macro solution. A function is a lot more readable and presumably maintainable too. – Owen Nov 30 '18 at 4:13
  • @Owen Yep. Both those things. Cheers. – B Layer Nov 30 '18 at 9:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.