2

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?

Owen
  • 213
  • 2
  • 5

2 Answers2

4

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.

Ingo Karkat
  • 17,819
  • 1
  • 45
  • 61
3

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.

B Layer
  • 19,834
  • 2
  • 30
  • 57
  • 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 04:13
  • @Owen Yep. Both those things. Cheers. – B Layer Nov 30 '18 at 09:08