Improve error message formatting for tool interop#1285
Improve error message formatting for tool interop#1285epost wants to merge 2 commits intopurescript:masterfrom
Conversation
|
Looks good to me as a default. Later we can add JSON support too, perhaps, for other editors. I'd be interested, as a non-Emacs user, to see how this looks. |
|
Cool! There's a pic in #1098. I think JSON support is already in there; didn't @hdgarrood add it (somewhat) recently? |
|
I didn't, I guess you might be thinking of |
|
I'm not sure about this, I think the current format is quite a bit easier to read. Also, does this mean we lose the information about where the problematic part of the code ends? |
|
Hi Harry, thanks for your comments. A few thoughts:
|
Yes, I often do this. I use Vim; I don't know how Vim would react to the current output, as I haven't tried to set that up.
I agree that it is a clear win for people who have their editor parse the compiler output, but I also think it is a clear loss for people who read it themselves. I think the default should be optimized for human readability. Could the editor-friendly output be off by default, and turned on with a command line switch?
I like this suggestion very much. |
This is somewhat subjective. Having been writing software since the late 80's, the "editor-friendly" style is very easy for me to read, in fact I have great difficulty parsing the current PureScript error messages. But as long as you can change the mode from the command-line / build tool, works for me. |
|
I agree that we should try to keep the end position of the range. Maybe this should be a format string as a command line argument or something? |
|
There is already a convention for editors to specify the range in the error / warning message: it's generally, public static final ErrorWarningPattern GNU_STYLE_ROW_COL_WITH_END = BUILDER.build("${FILE}:${ROW}${REGEXP=[:\\.]}${COL}-${END_ROW}${REGEXP=[:\\.]}${END_COL}: ${MESSAGE}");
public static final ErrorWarningPattern GNU_STYLE_ROW_COL = BUILDER.build("${FILE}:${ROW}${REGEXP=[:\\.]}${COL}: ${MESSAGE}");
public static final ErrorWarningPattern GNU_STYLE_ROW = BUILDER.build("${FILE}:${ROW}: ${MESSAGE}");
public static final ErrorWarningPattern GNU_STYLE_ROW_COL_WITH_END_E = BUILDER.build("${FILE}:${ROW}${REGEXP=[:\\.]}${COL}-${END_ROW}${REGEXP=[:\\.]}${END_COL}: Error: ${MESSAGE}");
public static final ErrorWarningPattern GNU_STYLE_ROW_COL_E = BUILDER.build("${FILE}:${ROW}${REGEXP=[:\\.]}${COL}: Error: ${MESSAGE}");
public static final ErrorWarningPattern GNU_STYLE_ROW_E = BUILDER.build("${FILE}:${ROW}: Error: ${MESSAGE}");
public static final ErrorWarningPattern GNU_STYLE_ROW_COL_WITH_END_W = BUILDER.build("${FILE}:${ROW}:${COL}-${END_ROW}:${END_COL}: Warning: ${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern GNU_STYLE_ROW_COL_W = BUILDER.build("${FILE}:${ROW}:${COL}: Warning: ${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern GNU_STYLE_ROW_W = BUILDER.build("${FILE}:${ROW}: Warning: ${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern ABS_FORTRAN_77_E = BUILDER.build("Error on line ${ROW} of ${FILE}: ${MESSAGE}");
public static final ErrorWarningPattern ABS_FORTRAN_77_W = BUILDER.build("warning on line ${ROW} of ${FILE}: ${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern D_ERROR = BUILDER.build("${FILE}(${ROW}): ${MESSAGE}");
public static final ErrorWarningPattern D_ERROR_MULTILINE = BUILDER.build("${FILE}(${ROW}): called with argument types:${NEWLINE}\\t${MESSAGE}${NEWLINE}${MESSAGE}${NEWLINE}\\t${MESSAGE}${NEWLINE}${MESSAGE}${NEWLINE}\\t${MESSAGE}");
public static final ErrorWarningPattern DELPHI_ERROR = BUILDER.build("${FILE}(${ROW}) Error: ${MESSAGE}");
public static final ErrorWarningPattern DELPHI_WARNING = BUILDER.build("${FILE}(${ROW}) Warning: ${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern ANT_JAVAC_ERROR = BUILDER.build("[javac] ${FILE}:${ROW}: ${MESSAGE}");
public static final ErrorWarningPattern ANT_JAVAC_WARNING = BUILDER.build("[javac] ${FILE}:${ROW}: warning: ${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern FAN_LANGUAGE = BUILDER.build("${FILE}(${ROW},${COL}): ${MESSAGE}");
public static final ErrorWarningPattern ANT_JIKES_ERROR = BUILDER.build("[jikes] ${FILE}:${ROW}:${COL}:${END_ROW}:${END_COL}: Semantic:${MESSAGE}");
public static final ErrorWarningPattern ANT_JIKES_WARN1 = BUILDER.build("[jikes] ${FILE}:${ROW}:${COL}:${END_ROW}:${END_COL}: Warning:${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern ANT_JIKES_WARN2 = BUILDER.build("[jikes] ${FILE}:${ROW}:${COL}:${END_ROW}:${END_COL}: Caution:${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern JAVAC_ERROR = BUILDER.build("${NUMBER}. ERROR in ${FILE} (at line ${ROW})${NEWLINE}${ANYTHING}${NEWLINE}${COL_INDICATOR}${NEWLINE}${MESSAGE}");
public static final ErrorWarningPattern JAVAC_WARNING = BUILDER.build("${NUMBER}. WARNING in ${FILE} (at line ${ROW})${NEWLINE}${ANYTHING}${NEWLINE}${COL_INDICATOR}${NEWLINE}${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern MICROSOFT_CPP_ERROR = BUILDER.build("${FILE}(${ROW}) : error ${REGEXP=[A-Z]+}${NUMBER}: ${MESSAGE}");
public static final ErrorWarningPattern MICROSOFT_CPP_WARN = BUILDER.build("${FILE}(${ROW}) : warning ${REGEXP=[A-Z]+}${NUMBER}: ${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern MICROSOFT_CS_ERROR = BUILDER.build("${FILE}(${ROW}) error ${REGEXP=[A-Z]+}${NUMBER}: ${MESSAGE}");
public static final ErrorWarningPattern MICROSOFT_CS_WARN = BUILDER.build("${FILE}(${ROW}) warning ${REGEXP=[A-Z]+}${NUMBER}: ${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern PERL_ERROR1 = BUILDER.build("${MESSAGE} at ${FILE} line ${ROW}");
public static final ErrorWarningPattern PERL_ERROR2 = BUILDER.build("${MESSAGE} in file ${FILE} at line ${ROW}");
public static final ErrorWarningPattern PHP_ERROR1 = BUILDER.build("Parse error: syntax error, ${MESSAGE} in ${FILE} on line ${ROW}");
public static final ErrorWarningPattern PHP_ERROR2 = BUILDER.build("Fatal error: ${MESSAGE} in ${FILE} on line ${ROW}");
public static final ErrorWarningPattern GPL_XML_ERROR = BUILDER.build("Error: ${MESSAGE}${NEWLINE}${MESSAGE} at line ${ROW} char ${COL} of file://${FILE}");
public static final ErrorWarningPattern GPL_XML_WARNING = BUILDER.build("Warning: ${MESSAGE}${NEWLINE}${MESSAGE} at line ${ROW} char ${COL} of file://${FILE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern RUBY_SYNTAX_ERROR = BUILDER.build("${FILE}:${ROW}: syntax error, ${MESSAGE}");
public static final ErrorWarningPattern CAML_ERROR = BUILDER.build("File \"${FILE}\", line ${ROW}, characters ${COL}-${END_COL}:${NEWLINE}Error: ${MESSAGE}");
public static final ErrorWarningPattern CAML_ERROR_2 = BUILDER.build("File \"${FILE}\", line ${ROW}, characters ${COL}-${END_COL}:${NEWLINE}Parse error: ${MESSAGE}");
public static final ErrorWarningPattern CAML_WARNING = BUILDER.build("File \"${FILE}\", line ${ROW}, characters ${COL}-${END_COL}:${NEWLINE}Warning: ${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern CAML_WARNING_2 = BUILDER.build("File \"${FILE}\", line ${ROW}, characters ${COL}-${END_COL}:${NEWLINE}Warning ${REGEXP=[A-Z]}: ${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern PYTHON_ERROR1 = BUILDER.build(" File \"${FILE}\", line ${ROW}${NEWLINE}${ANYTHING}${NEWLINE} ${COL_INDICATOR}${NEWLINE}${REGEXP=\\w+Error}: ${MESSAGE}");
public static final ErrorWarningPattern PYTHON_ERROR2 = BUILDER.build(" File \"${FILE}\", line ${ROW}${NEWLINE}${ANYTHING}${NEWLINE}${REGEXP=\\w+Error}: ${MESSAGE}");
public static final ErrorWarningPattern PYTHON_ERROR3 = BUILDER.build(" File \"${FILE}\", line ${ROW}${NEWLINE}${REGEXP=\\w+Error}: ${MESSAGE}");
public static final ErrorWarningPattern PYTHON_ERROR4 = BUILDER.build(" File \"${FILE}\", line ${ROW}, in ${ANYTHING}${NEWLINE}${ANYTHING}${NEWLINE} ${COL_INDICATOR}${NEWLINE}${REGEXP=\\w+Error}: ${MESSAGE}");
public static final ErrorWarningPattern PYTHON_ERROR5 = BUILDER.build(" File \"${FILE}\", line ${ROW}, in ${ANYTHING}${NEWLINE}${ANYTHING}${NEWLINE}${REGEXP=\\w+Error}: ${MESSAGE}");
public static final ErrorWarningPattern PYTHON_ERROR6 = BUILDER.build(" File \"${FILE}\", line ${ROW}, in ${ANYTHING}${NEWLINE}${REGEXP=\\w+Error}: ${MESSAGE}");
public static final ErrorWarningPattern PYTHON_ERROR7 = BUILDER.build(" SyntaxError: ${MESSAGE} (${FILE}, line ${ROW})${NEWLINE}${ANYTHING}${NEWLINE} ${COL_INDICATOR}");
public static final ErrorWarningPattern PYTHON_ERROR8 = BUILDER.build(" SyntaxError: ${MESSAGE} (${FILE}, line ${ROW})");
public static final ErrorWarningPattern PYTHON_INDENT_ERROR = BUILDER.build(" IndentationError: ${MESSAGE} (${FILE}, line ${ROW})");
public static final ErrorWarningPattern PMD_PATTERN = BUILDER.build("${FILE}:${ROW}${TAB}${MESSAGE}", Classifications.WARNING_CLASSIFICATION);
public static final ErrorWarningPattern PHP_WIN_ERROR = BUILDER.build("PHP Parse error:${SPACES}syntax error, ${MESSAGE} in ${FILE} on line ${ROW}");
public static final ErrorWarningPattern LUA_ERROR = BUILDER.build("${IGNORE_FILE}: ${FILE}:${ROW}: ${MESSAGE}");
public static final ErrorWarningPattern OPEN_PASCAL_ERROR = BUILDER.build("${FILE}(${ROW},${COL}) Error: ${MESSAGE}");
public static final ErrorWarningPattern OPEN_PASCAL_WARNING = BUILDER.build("${FILE}(${ROW},${COL}) Warning: ${MESSAGE}", Classifications.WARNING_CLASSIFICATION); |
|
@jdegoes Interesting, what's the source of your list? Here are some of the regexes that emacs supports out of the box; the colon-separated format seems to be a GNU thing. In the meantime, as I'm not sure how to sensibly move this forward, I'll be using https://gist.github.com/epost/6db5fac97956d0050137#file-purescript-support-el-L45 to parse the existing message format from within emacs compilation-mode instead. |
|
Can we make the format controllable via a command line option then? |
|
Parsing the current output in https://github.com/nwolverson/atom-linter-purescript - variable number of lines and lack of a "headline" error makes the experience less than ideal. But definitely want both start/end for row and column. |
I created it many years ago when writing a text editor that needed to extract out errors from lots of different tools and compilers. The regexes above can parse most errors and warnings, with start and optionally end columns for those format that support them. |
|
Am I correct in thinking that the new |
|
Yes, I think so, although there is quite likely work still to do. |
|
It could, but I think it'd still be a shame not to settle on a sensible
|
|
I realise that this viewpoint goes against the grain somewhat, but I don't think we should be supporting or even encouraging editors to be trying to parse the default textual output. It seems to me that by trying to support both, we'll inevitably up with a format that's not particularly good at either (ie, reading by humans, reading by editors), and it also means we won't be able to make changes to the text format without breaking everyone's editor interop. |
|
Agreed with @hdgarrood. If at all possible, I'd love for the default output to be for humans, and (@jdegoes' list shows us that formats that people are previously used to are all over the place. As a number of us are starting with experience with tools that aren't gcc, ghc or javac, I'm doubly leery of biasing output in that direction.) |
|
I think this has been superceded by |
Improve editor interop by printing compiler errors in a format like that of gcc, ghc, javac, etc.
The new format allows editors like emacs to highlight errors and warnings correctly, and in such a way that the highlighting depends on the error level. Additionally, (emacs) features like 'go to error line' and 'go to next error' now work (more) correctly. See also #1098.
Changes:
Error:andWarning:at the top of the error list are interpreted by emacs as proper errors, which causes problem with highlighting and with jumping to the error line, because it doesn't exist. Fix: replaceError:byError found:and so on. The introduction of a space character fixes the problem.PositionErrorsare now formatted like/path/to/File.purs:3:5:warning:Some descriptive message, following gcc. This allows emacs to parse the source position and error loevel correctly.Before:
After: