Vim errorformat and ncvhdl - vim

I am trying to set up my Vim environment, to be able to compile VHDL code by using the Cadence VHDL Compiler (ncvhdl). However, my errorformat string is not working properly. A typical ncvhdl error line is:
ncvhdl_p: *E,EXPBEG (tc_lg_and2-rtl-a.vhd,3|34): expecting the
reserved word 'BEGIN' [1.2].
I am setting the errorformat to:
set errorformat=ncvhdl_p:\ *E\\,%m\ (%f\\,%l\|%c)
Any hints out there?
Thanks!

This is what you want to do:
set errorformat=ncvhdl_p:\ \*%t\\,%.%#\ (%f\\,%l\\|%c):\ %m
The * character needs to be escaped.
Use %t to identify a single character indicating the error type (Error/Warning/Lint).
Use %.%# to skip a string, like .* in regular expressions.
For more information:
:help errorformat
The setting set makeprg=cat\ example.txt can be used as a quick way of testing the errorformat expression if example.txt contains a list of error lines copied from the command output.

Related

Vim errorformat non-greedy match of %m operator

I have an errorfile which I want to be read by vi. The format looks as if:
myfile.txt_:_80_:_3_:_this is the message: oh no!_:_comment
I.e., filename, lineno, colno, message and comment separated by "_:_". Note the trailing "comment" which I do not want to appear in the vi message. However, when I use the errorformat string
:set errorformat=%f_:_%l_:_%c_:_%m
The "%m" operator has greedy matching and matches everything, including the whole "_:_comment" portion. This is even true if I make the errorformat
:set errorformat=%f_:_%l_:_%c_:_%m_:_
I do not know how to customize what text "%m" matches. The vi documentation speaks that pretty much everything that is possible with vi regex should be possible, but I cannot figure out a way to make it work (the documentation is vague in this respect in my opinion).
How can I use an errorformat that ignores the last column field?
You can finish the format with the generic %s (for "search text"):
:set errorformat=%f_:_%l_:_%c_:_%m_:_%s
Note that this is relatively fragile. The following error, with several more _:_ separators:
myfile.txt_:_80_:_3_:_this is the message: oh no!_:_comment_:_foo_:_bar
would give you this message:
this is the message: oh no!_:_comment_:_foo
Improvement opportunities:
outside of Vim, make sure your errorfile is formatted in a non-ambiguous way,
in Vim, use a function to transform ambiguous error strings into non-ambiguous ones, see :help :cgetexpr.

need examples for %s in errorformat of vim

this looks like simple question, anyone know what does the %s mean for errorformat option in VIM?
The help text in vim is not clear to me, I need an example to understand it.
%s is for cases where:
there is no line number in the compiler output (so %l can't be used),
the exact content of the line is available in the compiler output.
For example, the following compiler output:
foo/bar.xml: <foo bar="baz">hamburger</foo>
could be consumed with the following &errorformat:
set errorformat=%f:%\\s%s

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

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.
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".

Vim errorformat: include part of expression in message string

With vim's errorformat syntax, is there any way to use part of the message in filtering results?
As an example, some linker errors don't have anything explicit to distinguish them as an error on the line, other than the error itself:
/path/to/foo.cpp:42: undefined reference to 'UnimplementedFunction'
or
/path/to/foo.cpp:43: multiple definition of 'MultiplyDefinedFunction'
Using an errorformat of:
set efm=%f:%l:\ %m
would catch and display both of these correctly, but will falsely match many other cases (any line that starts with "[string]:[number]: ").
Or, explicitly specifying them both:
set efm=
set efm+=%f:%l:\ undefined\ reference\ to\ %m
set efm+=%f:%l:\ multiple\ definition\ of\ %m
removes the false positives, but the 'message' becomes far less useful -- the actual error is no longer included (just whatever is after it).
Is there anything in the syntax I'm missing to deal with this situation?
Ideally I'd like to be able to say something along the lines of:
set efm+=%f:%l:\ %{StartMessage}undefined\ reference\ to\ %*\\S%{EndMessage}
set efm+=%f:%l:\ %{StartMessage}multiple\ definition\ of\ %*\\S%{EndMessage}
... where everything matched between StartMessage and EndMessage is used as the error's message.
The errorformat can also use vim's regular expression syntax (albeit in a rather awkward way) which gives us a solution to the problem. We can use a non-capturing group and a zero-width assertion to require the presence of these signaling phrases without consuming them. This then allows the %m to pick them up. As plain regular expression syntax this zero-width assertion looks like:
\%(undefined reference\|multiple definition\)\#=
But in order to use it in efm we need to replace \ by %\ and % by %% and for use in a :set line we need to escape the backslashes, spaces and vertical bar so we finally have:
:set efm=%f:%l:\ %\\%%(undefined\ reference%\\\|multiple\ definitions%\\)%\\#=%m
With that the error file
/path/to/foo.cpp:42: undefined reference to 'UnimplementedFunction'
/path/to/foo.cpp:43: multiple definition of 'MultiplyDefinedFunction'
notafile:123: just some other text
comes out as the following in :copen:
/path/to/foo.cpp|42| undefined reference to 'UnimplementedFunction'
/path/to/foo.cpp|43| multiple definition of 'MultiplyDefinedFunction'
|| notafile:123: just some other text
I've been using sed to rewrite the output in cases like this where I want to get some arbitrary output that's not nessicarily homogenous into the quickfix window.
You could write make.sh that fires off make (or whatever your're using to build) and trims off stuff you're not concerned with:
make | sed '/undefined reference\|multiple definition/!d'
(Deletes lines not containing 'undefined reference' or 'multiple definition')
If that's going to get too unweildly because of the number of error strings you care about, you could do the inverse and just kill stuff you don't care about:
make | sed 's/some garbage\|other useless message//'
then :set makeprg=make.sh in vim

What's the error type for in errorformat for Vim’s quickfix list?

I’m unsure about the %t format specifier in Vim’s quickfix list. How does it affect the behavior/display of the quickfix buffer?
I tried to find it out with the following test file:
$ cat test.out
foo Error 1 foo.h foobar
bar Error 2 foo.h foobar
foobar Warning 3 foo.h foobar
barfoo Warning 4 foo.h foobar
And the following errorformat first:
set errorformat+=%.%#%*\\s%.%#%*\\s%l\ %f%*\\s%m
With this errorformat in place I can use :cgetfile test.out and jump to the line numbers in foo.h, but with the following errorformat:
set errorformat+=%.%#%*\\s%t%.%#%*\\s%l\ %f%*\\s%m
All that has changed is that now I see some spaces after the line numbers in the quickfix buffer, e.g. I see (two spaces after the 1)
foo.h|1 | foobar
instead of
foo.h|1| foobar
So I have two questions:
What is wrong with my errorformat?
What should I see if the error type could be extracted?
I'm unsure about the %t format specifier in Vim's quickfix list, how does it affect the behavior/display of the quickfix buffer?
It tells the quickfix buffer what type of error a match is (error, warning, or informational). The quickfix buffer will then show that information after the line number and highlight it in a different color. For example, here is a warning and an error:
hosts.cfg|3473 error| Could not add object property
hosts.cfg|3790 warning| Duplicate definition found for host 'mailgateway'
In the quickfix window the word "warning" is in yellow and the word "error" is white on red. In my errorformat I am using %t where the E or W would be in Error or Warning. For example:
%trror: %m in file '%f' on line %l
This is not really an answer to your question, but an alternate solution I use myself.
Personally I find the errorformat system too complicated, and instead use a common very simple errorformat fed by the output of a real function, that I pipe the output of my make command through.
I use this: "%f\ %l\ %c\ %m".
I write these error parsing functions in python, but any of the supported scripting languages should do, or even vimL.
The logic of this being that such a function is much easier to debug, usable outside of vim, and (at least for me) quicker to write than crafting an errorformat string.
I have found the following example in quickfix.txt where %t is used.
Examples
The format of the file from the Amiga Aztec compiler is:
filename>linenumber:columnnumber:errortype:errornumber:errormessage
filename name of the file in which the error was detected
linenumber line number where the error was detected
columnnumber column number where the error was detected
errortype type of the error, normally a single 'E' or 'W'
errornumber number of the error (for lookup in the manual)
errormessage description of the error
This can be matched with this errorformat entry:
%f>%l:%c:%t:%n:%m
It seems that some compiler are storing the error type in a single character E or W, presumably for Error and Warning.
Keep in mind that it is a single character, so it won't match "Warning" or "Error".
%t error type (finds a single character)

Resources