What's the meaning of some advanced patterns in vim errorformat? (%s, %+, %\\@=)
Asked Answered
G

1

9

I tried reading :help errorformat and googling (mostly stackoverflow), but can't understand some of the patterns mentioned there:

  • %s - "specifies the text to search for to locate the error line. [...]"
    • um, first of all, trying to understand the sentence at all, where do I put the "text to search", after the %s? before it? or, I don't know, does it maybe taint the whole pattern? WTF?
    • secondly, what does this pattern actually do, how does it differ from regular text in a pattern, like some kinda set efm+=,foobar? the "foobar" here is for me also "text to search for"... :/
  • %+ - e.g. I I've seen something like that used in one question: %+C%.%#
    • does it mean the whole line will be appended to a %m used in an earlier/later multiline pattern? if yes, then what if there was not %.%# (== regexp .*), but, let's say, %+Ccont.: %.%# - would something like that work to capture only stuff after a cont.: string into the %m?
    • also, what's the difference between %C%.%# and %+C%.%# and %+G?
    • also, what's the difference between %A and %+A, or %E vs. %+E?
  • finally, an example for Python in :help errorformat-multi-line ends with the following characters: %\\@=%m -- WTF does the %\\@= mean?

I'd be very grateful for some help understanding this stuff.

Government answered 16/3, 2015 at 22:57 Comment(0)
A
24

Ah, errorformat, the feature everybody loves to hate. :)

Some meta first.

  • Some Vim commands (such as :make and :cgetexpr) take the output of a compiler and parse it into a quickfix list. errorformat is a string that describes how this parsing is done. It's a list of patterns, each pattern being a sort of hybrid between a regexp and a scanf(3) format. Some of these patterns match single lines in the compiler's output, others try to match multiple lines (%E, %A, %C etc.), others keep various states (%D, %X), others change the way parsing proceeds (%>), while yet others simply produce messages in the qflist (%G), or ignore lines in the input (%-G). Not all combinations make sense, and it's quite likely you won't figure out all details until you look at Vim' sources. shrug
  • You probably want to write errorformats using let &erf='...' rather than set erf=.... The syntax is much more human-friendly.
  • You can experiment with errorformat using cgetexpr. cgetexpr expects a list, which it interprets as the lines in the compiler's output. The result is a qflist (or a syntax error).
  • qflists are lists of errors, each error being a Vim "dictionary". See :help getqflist() for the (simplified) format.
  • Errors can identify a place in a file, they can be simple messages (if essential data that identifies a place is missing), and they can be valid or invalid (the invalid ones are essentially the leftovers from parsing).
  • You can display the current qflist with something like :echomsg string(getqflist()), or you can see it in a nice window with :copen (some important details are not shown in the window though). :cc will take you to the place of the first error (assuming the first error in qflist actually refers to an error in a file).

Now to answer your questions.

um, first of all, trying to understand the sentence at all, where do I put the "text to search", after the %s? before it?

You don't. %s reads a line from the compiler's output and translates it to pattern in the qflist. That's all it does. To see it at work, create a file efm.vim with this content:

let &errorformat ='%f:%s:%m'
cgetexpr ['efm.vim:" bar:baz']
echomsg string(getqflist())
copen
cc

" bar baz
" bar
" foo bar

Then run :so%, and try to understand what's going on. %f:%s:%m looks for three fields: a filename, the %s thing, and the message. The input line is efm.vim:" bar:baz, which is parsed into filename efm.vim (that is, current file), pattern ^\V" bar\$, and message baz. When you run :cc Vim tries to find a line matching ^\V" bar\$, and sends you there. That's the next-to-last line in the current file.

secondly, what does this pattern actually do, how does it differ from regular text in a pattern, like some kinda set efm+=,foobar?

set efm+=foobar %m will look for a line in the compiler's output starting with foobar, then assign the rest of the line to the message field in the corresponding error.

%s reads a line from the compiler's output and translates it to a pattern field in the corresponding error.

%+ - e.g. I I've seen something like that used in one question: %+C%.%# does it mean the whole line will be appended to a %m used in an earlier/later multiline pattern?

Yes, it appends the content of the line matched by %+C to the message produced by an earlier (not later) multiline pattern (%A, %E, %W, or %I).

if yes, then what if there was not %.%# (== regexp .*), but, let's say, %+Ccont.: %.%# - would something like that work to capture only stuff after a cont.: string into the %m?

No. With %+Ccont.: %.%# only the lines matching the regexp ^cont\.: .*$ are considered, the lines not matching it are ignored. Then the entire line is appended to the previous %m, not just the part that follows cont.:.

also, what's the difference between %C%.%# and %+C%.%# and %+G?

%Chead %m trail matches ^head .* trail$, then appends only the middle part to the previous %m (it discards head and trail).

%+Chead %m trail matches ^head .* trail$, then appends the entire line to the previous %m (including head and trail).

%+Gfoo matches a line starting with foo and simply adds the entire line as a message in the qflist (that is, an error that only has a message field).

also, what's the difference between %A and %+A, or %E vs. %+E?

%A and %E start multiline patterns. %+ seems to mean "add the entire line being parsed to message, regardless of the position of %m".

finally, an example for Python in :help errorformat-multi-line ends with the following characters: %\\@=%m -- WTF does the %\\@= mean?

%\\@= translates to the regexp qualifier \@=, "matches preceding atom with zero width".

Admittedly answered 17/3, 2015 at 15:22 Comment(2)
Ahhh, awesome, now I get the %s! So it's like what's in tags files, nice! As to %+G, now I'm surprised, message-field-only in qflist? will have to test, interesting, thanks! As to %+A: :help efm-ignore explicitly lists this as a possibility: "e.g. '%+A'"; are you still sure that's a syntax error? Finally, w.r.t. \@=, ouch... arcane regexp, you say? thanks, I didn't expect that, will have to read more too. That said, could you possibly share a link here for completeness? All in all, huge thanks and totally accepting the response! You're awesome :)Government
Looking at the sources, you're right: %+ is supported for all (prefixed) formats, and the meaning is simply "add the entire line to the message, regardless of %m". I'd imagine this is not very useful for the likes of %A and %E though. :) I'll edit my answer accordingly.Admittedly

© 2022 - 2024 — McMap. All rights reserved.