2019-05-04 18:14:48 +00:00
|
|
|
// Scintilla source code edit control
|
|
|
|
/** @file LexErrorList.cxx
|
|
|
|
** Lexer for error lists. Used for the output pane in SciTE.
|
|
|
|
**/
|
|
|
|
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
|
|
|
|
// The License.txt file describes the conditions under which this software may be distributed.
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
#include <string>
|
2022-01-04 23:07:50 +00:00
|
|
|
#include <string_view>
|
2021-02-21 04:53:09 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
#include "ILexer.h"
|
|
|
|
#include "Scintilla.h"
|
|
|
|
#include "SciLexer.h"
|
|
|
|
|
|
|
|
#include "WordList.h"
|
|
|
|
#include "LexAccessor.h"
|
|
|
|
#include "Accessor.h"
|
|
|
|
#include "StyleContext.h"
|
|
|
|
#include "CharacterSet.h"
|
|
|
|
#include "LexerModule.h"
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
using namespace Lexilla;
|
2019-05-04 18:14:48 +00:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
bool strstart(const char *haystack, const char *needle) noexcept {
|
|
|
|
return strncmp(haystack, needle, strlen(needle)) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool Is0To9(char ch) noexcept {
|
|
|
|
return (ch >= '0') && (ch <= '9');
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool Is1To9(char ch) noexcept {
|
|
|
|
return (ch >= '1') && (ch <= '9');
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsAlphabetic(int ch) {
|
|
|
|
return IsASCII(ch) && isalpha(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool AtEOL(Accessor &styler, Sci_PositionU i) {
|
|
|
|
return (styler[i] == '\n') ||
|
|
|
|
((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n'));
|
|
|
|
}
|
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
bool IsGccExcerpt(const char *s) noexcept {
|
|
|
|
while (*s) {
|
|
|
|
if (s[0] == ' ' && s[1] == '|' && (s[2] == ' ' || s[2] == '+')) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!(s[0] == ' ' || s[0] == '+' || Is0To9(s[0]))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Update: Scintilla 5.3.6 and Lexilla 5.2.6
update to Scinitlla Release 5.3.6 (https://www.scintilla.org/scintilla536.zip)
Released 26 July 2023.
Redraw calltip after showing as didn't update when size of new text exactly same as previous. Feature #1486.
On Win32 fix reverse arrow cursor when scaled. Bug #2382.
On Win32 hide cursor when typing if that system preference has been chosen. Bug #2333.
On Win32 and Qt, stop aligning IME candidate window to target. It is now always aligned to start of composition string. This undoes part of feature #1300. Feature #1488, Bug #2391, Feature #1300.
On Qt, for IMEs, update micro focus when selection changes. This may move the location of IME popups to align with the caret.
On Qt, implement replacement for IMEs which may help with actions like reconversion. This is similar to delete-surrounding on GTK.
and Lexilla Release 5.2.6 (https://www.scintilla.org/lexilla526.zip)
Released 26 July 2023.
Include empty word list names in value returned by DescribeWordListSets and SCI_DESCRIBEKEYWORDSETS. Issue #175, Pull request #176.
Bash: style here-doc end delimiters as SCE_SH_HERE_DELIM instead of SCE_SH_HERE_Q. Issue #177.
Bash: allow '$' as last character in string. Issue #180, Pull request #181.
Bash: fix state after expansion. Highlight all numeric and file test operators. Don't highlight dash in long option as operator. Issue #182, Pull request #183.
Bash: strict checking of special parameters ($*, $@, $$, ...) with property lexer.bash.special.parameter to specify valid parameters. Issue #184, Pull request #186.
Bash: recognize keyword before redirection operators (< and >). Issue #188, Pull request #189.
Errorlist: recognize Bash diagnostic messages.
HTML: allow ASP block to terminate inside line comment. Issue #185.
HTML: fix folding with JSP/ASP.NET <%-- comment. Issue #191.
HTML: fix incremental styling of multi-line ASP.NET directive. Issue #191.
Matlab: improve arguments blocks. Add support for multiple arguments blocks. Prevent "arguments" from being keyword in function declaration line. Fix semicolon handling. Pull request #179.
Visual Prolog: add support for embedded syntax with SCE_VISUALPROLOG_EMBEDDED and SCE_VISUALPROLOG_PLACEHOLDER.
Styling of string literals changed with no differentiation between literals with quotes and those that are prefixed with "@". Quote characters are in a separate style (SCE_VISUALPROLOG_STRING_QUOTE) to contents (SCE_VISUALPROLOG_STRING).
SCE_VISUALPROLOG_CHARACTER, SCE_VISUALPROLOG_CHARACTER_TOO_MANY, SCE_VISUALPROLOG_CHARACTER_ESCAPE_ERROR, SCE_VISUALPROLOG_STRING_EOL_OPEN, and SCE_VISUALPROLOG_STRING_VERBATIM_SPECIAL were removed (replaced with SCE_VISUALPROLOG_UNUSED[1-5]). Pull request #178.
Fix #13901, fix #13911, fix #13943, close #13940
2023-07-27 17:57:12 +00:00
|
|
|
const std::string_view bashDiagnosticMark = ": line ";
|
|
|
|
bool IsBashDiagnostic(std::string_view sv) {
|
|
|
|
const size_t mark = sv.find(bashDiagnosticMark);
|
|
|
|
if (mark == std::string_view::npos) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::string_view rest = sv.substr(mark + bashDiagnosticMark.length());
|
|
|
|
if (rest.empty() || !Is0To9(rest.front())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
while (!rest.empty() && Is0To9(rest.front())) {
|
|
|
|
rest.remove_prefix(1);
|
|
|
|
}
|
|
|
|
return !rest.empty() && (rest.front() == ':');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
int RecogniseErrorListLine(const char *lineBuffer, Sci_PositionU lengthLine, Sci_Position &startValue) {
|
|
|
|
if (lineBuffer[0] == '>') {
|
|
|
|
// Command or return status
|
|
|
|
return SCE_ERR_CMD;
|
|
|
|
} else if (lineBuffer[0] == '<') {
|
|
|
|
// Diff removal.
|
|
|
|
return SCE_ERR_DIFF_DELETION;
|
|
|
|
} else if (lineBuffer[0] == '!') {
|
|
|
|
return SCE_ERR_DIFF_CHANGED;
|
|
|
|
} else if (lineBuffer[0] == '+') {
|
|
|
|
if (strstart(lineBuffer, "+++ ")) {
|
|
|
|
return SCE_ERR_DIFF_MESSAGE;
|
|
|
|
} else {
|
|
|
|
return SCE_ERR_DIFF_ADDITION;
|
|
|
|
}
|
|
|
|
} else if (lineBuffer[0] == '-') {
|
|
|
|
if (strstart(lineBuffer, "--- ")) {
|
|
|
|
return SCE_ERR_DIFF_MESSAGE;
|
|
|
|
} else {
|
|
|
|
return SCE_ERR_DIFF_DELETION;
|
|
|
|
}
|
|
|
|
} else if (strstart(lineBuffer, "cf90-")) {
|
|
|
|
// Absoft Pro Fortran 90/95 v8.2 error and/or warning message
|
|
|
|
return SCE_ERR_ABSF;
|
|
|
|
} else if (strstart(lineBuffer, "fortcom:")) {
|
|
|
|
// Intel Fortran Compiler v8.0 error/warning message
|
|
|
|
return SCE_ERR_IFORT;
|
|
|
|
} else if (strstr(lineBuffer, "File \"") && strstr(lineBuffer, ", line ")) {
|
|
|
|
return SCE_ERR_PYTHON;
|
|
|
|
} else if (strstr(lineBuffer, " in ") && strstr(lineBuffer, " on line ")) {
|
|
|
|
return SCE_ERR_PHP;
|
|
|
|
} else if ((strstart(lineBuffer, "Error ") ||
|
|
|
|
strstart(lineBuffer, "Warning ")) &&
|
|
|
|
strstr(lineBuffer, " at (") &&
|
|
|
|
strstr(lineBuffer, ") : ") &&
|
|
|
|
(strstr(lineBuffer, " at (") < strstr(lineBuffer, ") : "))) {
|
|
|
|
// Intel Fortran Compiler error/warning message
|
|
|
|
return SCE_ERR_IFC;
|
|
|
|
} else if (strstart(lineBuffer, "Error ")) {
|
|
|
|
// Borland error message
|
|
|
|
return SCE_ERR_BORLAND;
|
|
|
|
} else if (strstart(lineBuffer, "Warning ")) {
|
|
|
|
// Borland warning message
|
|
|
|
return SCE_ERR_BORLAND;
|
|
|
|
} else if (strstr(lineBuffer, "at line ") &&
|
|
|
|
(strstr(lineBuffer, "at line ") < (lineBuffer + lengthLine)) &&
|
|
|
|
strstr(lineBuffer, "file ") &&
|
|
|
|
(strstr(lineBuffer, "file ") < (lineBuffer + lengthLine))) {
|
|
|
|
// Lua 4 error message
|
|
|
|
return SCE_ERR_LUA;
|
|
|
|
} else if (strstr(lineBuffer, " at ") &&
|
|
|
|
(strstr(lineBuffer, " at ") < (lineBuffer + lengthLine)) &&
|
|
|
|
strstr(lineBuffer, " line ") &&
|
|
|
|
(strstr(lineBuffer, " line ") < (lineBuffer + lengthLine)) &&
|
|
|
|
(strstr(lineBuffer, " at ") + 4 < (strstr(lineBuffer, " line ")))) {
|
|
|
|
// perl error message:
|
|
|
|
// <message> at <file> line <line>
|
|
|
|
return SCE_ERR_PERL;
|
|
|
|
} else if ((lengthLine >= 6) &&
|
|
|
|
(memcmp(lineBuffer, " at ", 6) == 0) &&
|
|
|
|
strstr(lineBuffer, ":line ")) {
|
|
|
|
// A .NET traceback
|
|
|
|
return SCE_ERR_NET;
|
|
|
|
} else if (strstart(lineBuffer, "Line ") &&
|
|
|
|
strstr(lineBuffer, ", file ")) {
|
|
|
|
// Essential Lahey Fortran error message
|
|
|
|
return SCE_ERR_ELF;
|
|
|
|
} else if (strstart(lineBuffer, "line ") &&
|
|
|
|
strstr(lineBuffer, " column ")) {
|
|
|
|
// HTML tidy style: line 42 column 1
|
|
|
|
return SCE_ERR_TIDY;
|
|
|
|
} else if (strstart(lineBuffer, "\tat ") &&
|
2022-08-27 07:35:52 +00:00
|
|
|
strchr(lineBuffer, '(') &&
|
2019-05-04 18:14:48 +00:00
|
|
|
strstr(lineBuffer, ".java:")) {
|
|
|
|
// Java stack back trace
|
|
|
|
return SCE_ERR_JAVA_STACK;
|
|
|
|
} else if (strstart(lineBuffer, "In file included from ") ||
|
|
|
|
strstart(lineBuffer, " from ")) {
|
|
|
|
// GCC showing include path to following error
|
|
|
|
return SCE_ERR_GCC_INCLUDED_FROM;
|
2022-01-04 23:07:50 +00:00
|
|
|
} else if (strstart(lineBuffer, "NMAKE : fatal error")) {
|
|
|
|
// Microsoft nmake fatal error:
|
|
|
|
// NMAKE : fatal error <code>: <program> : return code <return>
|
|
|
|
return SCE_ERR_MS;
|
|
|
|
} else if (strstr(lineBuffer, "warning LNK") ||
|
|
|
|
strstr(lineBuffer, "error LNK")) {
|
2019-05-04 18:14:48 +00:00
|
|
|
// Microsoft linker warning:
|
2022-01-04 23:07:50 +00:00
|
|
|
// {<object> : } (warning|error) LNK9999
|
2019-05-04 18:14:48 +00:00
|
|
|
return SCE_ERR_MS;
|
Update: Scintilla 5.3.6 and Lexilla 5.2.6
update to Scinitlla Release 5.3.6 (https://www.scintilla.org/scintilla536.zip)
Released 26 July 2023.
Redraw calltip after showing as didn't update when size of new text exactly same as previous. Feature #1486.
On Win32 fix reverse arrow cursor when scaled. Bug #2382.
On Win32 hide cursor when typing if that system preference has been chosen. Bug #2333.
On Win32 and Qt, stop aligning IME candidate window to target. It is now always aligned to start of composition string. This undoes part of feature #1300. Feature #1488, Bug #2391, Feature #1300.
On Qt, for IMEs, update micro focus when selection changes. This may move the location of IME popups to align with the caret.
On Qt, implement replacement for IMEs which may help with actions like reconversion. This is similar to delete-surrounding on GTK.
and Lexilla Release 5.2.6 (https://www.scintilla.org/lexilla526.zip)
Released 26 July 2023.
Include empty word list names in value returned by DescribeWordListSets and SCI_DESCRIBEKEYWORDSETS. Issue #175, Pull request #176.
Bash: style here-doc end delimiters as SCE_SH_HERE_DELIM instead of SCE_SH_HERE_Q. Issue #177.
Bash: allow '$' as last character in string. Issue #180, Pull request #181.
Bash: fix state after expansion. Highlight all numeric and file test operators. Don't highlight dash in long option as operator. Issue #182, Pull request #183.
Bash: strict checking of special parameters ($*, $@, $$, ...) with property lexer.bash.special.parameter to specify valid parameters. Issue #184, Pull request #186.
Bash: recognize keyword before redirection operators (< and >). Issue #188, Pull request #189.
Errorlist: recognize Bash diagnostic messages.
HTML: allow ASP block to terminate inside line comment. Issue #185.
HTML: fix folding with JSP/ASP.NET <%-- comment. Issue #191.
HTML: fix incremental styling of multi-line ASP.NET directive. Issue #191.
Matlab: improve arguments blocks. Add support for multiple arguments blocks. Prevent "arguments" from being keyword in function declaration line. Fix semicolon handling. Pull request #179.
Visual Prolog: add support for embedded syntax with SCE_VISUALPROLOG_EMBEDDED and SCE_VISUALPROLOG_PLACEHOLDER.
Styling of string literals changed with no differentiation between literals with quotes and those that are prefixed with "@". Quote characters are in a separate style (SCE_VISUALPROLOG_STRING_QUOTE) to contents (SCE_VISUALPROLOG_STRING).
SCE_VISUALPROLOG_CHARACTER, SCE_VISUALPROLOG_CHARACTER_TOO_MANY, SCE_VISUALPROLOG_CHARACTER_ESCAPE_ERROR, SCE_VISUALPROLOG_STRING_EOL_OPEN, and SCE_VISUALPROLOG_STRING_VERBATIM_SPECIAL were removed (replaced with SCE_VISUALPROLOG_UNUSED[1-5]). Pull request #178.
Fix #13901, fix #13911, fix #13943, close #13940
2023-07-27 17:57:12 +00:00
|
|
|
} else if (IsBashDiagnostic(lineBuffer)) {
|
|
|
|
// Bash diagnostic
|
|
|
|
// <filename>: line <line>:<message>
|
|
|
|
return SCE_ERR_BASH;
|
2021-02-21 04:53:09 +00:00
|
|
|
} else if (IsGccExcerpt(lineBuffer)) {
|
|
|
|
// GCC code excerpt and pointer to issue
|
|
|
|
// 73 | GTimeVal last_popdown;
|
|
|
|
// | ^~~~~~~~~~~~
|
|
|
|
return SCE_ERR_GCC_EXCERPT;
|
2019-05-04 18:14:48 +00:00
|
|
|
} else {
|
|
|
|
// Look for one of the following formats:
|
|
|
|
// GCC: <filename>:<line>:<message>
|
|
|
|
// Microsoft: <filename>(<line>) :<message>
|
|
|
|
// Common: <filename>(<line>): warning|error|note|remark|catastrophic|fatal
|
|
|
|
// Common: <filename>(<line>) warning|error|note|remark|catastrophic|fatal
|
|
|
|
// Microsoft: <filename>(<line>,<column>)<message>
|
|
|
|
// CTags: <identifier>\t<filename>\t<message>
|
|
|
|
// Lua 5 traceback: \t<filename>:<line>:<message>
|
|
|
|
// Lua 5.1: <exe>: <filename>:<line>:<message>
|
|
|
|
const bool initialTab = (lineBuffer[0] == '\t');
|
|
|
|
bool initialColonPart = false;
|
|
|
|
bool canBeCtags = !initialTab; // For ctags must have an identifier with no spaces then a tab
|
|
|
|
enum { stInitial,
|
|
|
|
stGccStart, stGccDigit, stGccColumn, stGcc,
|
|
|
|
stMsStart, stMsDigit, stMsBracket, stMsVc, stMsDigitComma, stMsDotNet,
|
|
|
|
stCtagsStart, stCtagsFile, stCtagsStartString, stCtagsStringDollar, stCtags,
|
|
|
|
stUnrecognized
|
|
|
|
} state = stInitial;
|
|
|
|
for (Sci_PositionU i = 0; i < lengthLine; i++) {
|
|
|
|
const char ch = lineBuffer[i];
|
|
|
|
char chNext = ' ';
|
|
|
|
if ((i + 1) < lengthLine)
|
|
|
|
chNext = lineBuffer[i + 1];
|
|
|
|
if (state == stInitial) {
|
|
|
|
if (ch == ':') {
|
|
|
|
// May be GCC, or might be Lua 5 (Lua traceback same but with tab prefix)
|
|
|
|
if ((chNext != '\\') && (chNext != '/') && (chNext != ' ')) {
|
|
|
|
// This check is not completely accurate as may be on
|
|
|
|
// GTK+ with a file name that includes ':'.
|
|
|
|
state = stGccStart;
|
|
|
|
} else if (chNext == ' ') { // indicates a Lua 5.1 error message
|
|
|
|
initialColonPart = true;
|
|
|
|
}
|
|
|
|
} else if ((ch == '(') && Is1To9(chNext) && (!initialTab)) {
|
|
|
|
// May be Microsoft
|
|
|
|
// Check against '0' often removes phone numbers
|
|
|
|
state = stMsStart;
|
|
|
|
} else if ((ch == '\t') && canBeCtags) {
|
|
|
|
// May be CTags
|
|
|
|
state = stCtagsStart;
|
|
|
|
} else if (ch == ' ') {
|
|
|
|
canBeCtags = false;
|
|
|
|
}
|
|
|
|
} else if (state == stGccStart) { // <filename>:
|
|
|
|
state = ((ch == '-') || Is0To9(ch)) ? stGccDigit : stUnrecognized;
|
|
|
|
} else if (state == stGccDigit) { // <filename>:<line>
|
|
|
|
if (ch == ':') {
|
|
|
|
state = stGccColumn; // :9.*: is GCC
|
|
|
|
startValue = i + 1;
|
|
|
|
} else if (!Is0To9(ch)) {
|
|
|
|
state = stUnrecognized;
|
|
|
|
}
|
|
|
|
} else if (state == stGccColumn) { // <filename>:<line>:<column>
|
|
|
|
if (!Is0To9(ch)) {
|
|
|
|
state = stGcc;
|
|
|
|
if (ch == ':')
|
|
|
|
startValue = i + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (state == stMsStart) { // <filename>(
|
|
|
|
state = Is0To9(ch) ? stMsDigit : stUnrecognized;
|
|
|
|
} else if (state == stMsDigit) { // <filename>(<line>
|
|
|
|
if (ch == ',') {
|
|
|
|
state = stMsDigitComma;
|
|
|
|
} else if (ch == ')') {
|
|
|
|
state = stMsBracket;
|
|
|
|
} else if ((ch != ' ') && !Is0To9(ch)) {
|
|
|
|
state = stUnrecognized;
|
|
|
|
}
|
|
|
|
} else if (state == stMsBracket) { // <filename>(<line>)
|
|
|
|
if ((ch == ' ') && (chNext == ':')) {
|
|
|
|
state = stMsVc;
|
|
|
|
} else if ((ch == ':' && chNext == ' ') || (ch == ' ')) {
|
|
|
|
// Possibly Delphi.. don't test against chNext as it's one of the strings below.
|
|
|
|
char word[512];
|
|
|
|
unsigned numstep;
|
|
|
|
if (ch == ' ')
|
|
|
|
numstep = 1; // ch was ' ', handle as if it's a delphi errorline, only add 1 to i.
|
|
|
|
else
|
|
|
|
numstep = 2; // otherwise add 2.
|
|
|
|
Sci_PositionU chPos = 0;
|
|
|
|
for (Sci_PositionU j = i + numstep; j < lengthLine && IsAlphabetic(lineBuffer[j]) && chPos < sizeof(word) - 1; j++)
|
|
|
|
word[chPos++] = lineBuffer[j];
|
|
|
|
word[chPos] = 0;
|
|
|
|
if (!CompareCaseInsensitive(word, "error") || !CompareCaseInsensitive(word, "warning") ||
|
|
|
|
!CompareCaseInsensitive(word, "fatal") || !CompareCaseInsensitive(word, "catastrophic") ||
|
|
|
|
!CompareCaseInsensitive(word, "note") || !CompareCaseInsensitive(word, "remark")) {
|
|
|
|
state = stMsVc;
|
|
|
|
} else {
|
|
|
|
state = stUnrecognized;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
state = stUnrecognized;
|
|
|
|
}
|
|
|
|
} else if (state == stMsDigitComma) { // <filename>(<line>,
|
|
|
|
if (ch == ')') {
|
|
|
|
state = stMsDotNet;
|
|
|
|
break;
|
|
|
|
} else if ((ch != ' ') && !Is0To9(ch)) {
|
|
|
|
state = stUnrecognized;
|
|
|
|
}
|
|
|
|
} else if (state == stCtagsStart) {
|
|
|
|
if (ch == '\t') {
|
|
|
|
state = stCtagsFile;
|
|
|
|
}
|
|
|
|
} else if (state == stCtagsFile) {
|
|
|
|
if ((lineBuffer[i - 1] == '\t') &&
|
|
|
|
((ch == '/' && chNext == '^') || Is0To9(ch))) {
|
|
|
|
state = stCtags;
|
|
|
|
break;
|
|
|
|
} else if ((ch == '/') && (chNext == '^')) {
|
|
|
|
state = stCtagsStartString;
|
|
|
|
}
|
|
|
|
} else if ((state == stCtagsStartString) && ((lineBuffer[i] == '$') && (lineBuffer[i + 1] == '/'))) {
|
|
|
|
state = stCtagsStringDollar;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (state == stGcc) {
|
|
|
|
return initialColonPart ? SCE_ERR_LUA : SCE_ERR_GCC;
|
|
|
|
} else if ((state == stMsVc) || (state == stMsDotNet)) {
|
|
|
|
return SCE_ERR_MS;
|
|
|
|
} else if ((state == stCtagsStringDollar) || (state == stCtags)) {
|
|
|
|
return SCE_ERR_CTAG;
|
|
|
|
} else if (initialColonPart && strstr(lineBuffer, ": warning C")) {
|
|
|
|
// Microsoft warning without line number
|
|
|
|
// <filename>: warning C9999
|
|
|
|
return SCE_ERR_MS;
|
|
|
|
} else {
|
|
|
|
return SCE_ERR_DEFAULT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CSI "\033["
|
|
|
|
|
|
|
|
constexpr bool SequenceEnd(int ch) noexcept {
|
|
|
|
return (ch == 0) || ((ch >= '@') && (ch <= '~'));
|
|
|
|
}
|
|
|
|
|
|
|
|
int StyleFromSequence(const char *seq) noexcept {
|
|
|
|
int bold = 0;
|
|
|
|
int colour = 0;
|
|
|
|
while (!SequenceEnd(*seq)) {
|
|
|
|
if (Is0To9(*seq)) {
|
|
|
|
int base = *seq - '0';
|
|
|
|
if (Is0To9(seq[1])) {
|
|
|
|
base = base * 10;
|
|
|
|
base += seq[1] - '0';
|
|
|
|
seq++;
|
|
|
|
}
|
|
|
|
if (base == 0) {
|
|
|
|
colour = 0;
|
|
|
|
bold = 0;
|
|
|
|
}
|
|
|
|
else if (base == 1) {
|
|
|
|
bold = 1;
|
|
|
|
}
|
|
|
|
else if (base >= 30 && base <= 37) {
|
|
|
|
colour = base - 30;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
seq++;
|
|
|
|
}
|
|
|
|
return SCE_ERR_ES_BLACK + bold * 8 + colour;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ColouriseErrorListLine(
|
2021-02-21 04:53:09 +00:00
|
|
|
const std::string &lineBuffer,
|
2019-05-04 18:14:48 +00:00
|
|
|
Sci_PositionU endPos,
|
|
|
|
Accessor &styler,
|
|
|
|
bool valueSeparate,
|
|
|
|
bool escapeSequences) {
|
|
|
|
Sci_Position startValue = -1;
|
2021-02-21 04:53:09 +00:00
|
|
|
const Sci_PositionU lengthLine = lineBuffer.length();
|
|
|
|
const int style = RecogniseErrorListLine(lineBuffer.c_str(), lengthLine, startValue);
|
|
|
|
if (escapeSequences && strstr(lineBuffer.c_str(), CSI)) {
|
2019-05-04 18:14:48 +00:00
|
|
|
const Sci_Position startPos = endPos - lengthLine;
|
2021-02-21 04:53:09 +00:00
|
|
|
const char *linePortion = lineBuffer.c_str();
|
2019-05-04 18:14:48 +00:00
|
|
|
Sci_Position startPortion = startPos;
|
|
|
|
int portionStyle = style;
|
|
|
|
while (const char *startSeq = strstr(linePortion, CSI)) {
|
|
|
|
if (startSeq > linePortion) {
|
|
|
|
styler.ColourTo(startPortion + static_cast<int>(startSeq - linePortion), portionStyle);
|
|
|
|
}
|
|
|
|
const char *endSeq = startSeq + 2;
|
|
|
|
while (!SequenceEnd(*endSeq))
|
|
|
|
endSeq++;
|
|
|
|
const Sci_Position endSeqPosition = startPortion + static_cast<Sci_Position>(endSeq - linePortion) + 1;
|
|
|
|
switch (*endSeq) {
|
|
|
|
case 0:
|
|
|
|
styler.ColourTo(endPos, SCE_ERR_ESCSEQ_UNKNOWN);
|
|
|
|
return;
|
|
|
|
case 'm': // Colour command
|
|
|
|
styler.ColourTo(endSeqPosition, SCE_ERR_ESCSEQ);
|
|
|
|
portionStyle = StyleFromSequence(startSeq+2);
|
|
|
|
break;
|
|
|
|
case 'K': // Erase to end of line -> ignore
|
|
|
|
styler.ColourTo(endSeqPosition, SCE_ERR_ESCSEQ);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
styler.ColourTo(endSeqPosition, SCE_ERR_ESCSEQ_UNKNOWN);
|
|
|
|
portionStyle = style;
|
|
|
|
}
|
|
|
|
startPortion = endSeqPosition;
|
|
|
|
linePortion = endSeq + 1;
|
|
|
|
}
|
|
|
|
styler.ColourTo(endPos, portionStyle);
|
|
|
|
} else {
|
|
|
|
if (valueSeparate && (startValue >= 0)) {
|
|
|
|
styler.ColourTo(endPos - (lengthLine - startValue), style);
|
|
|
|
styler.ColourTo(endPos, SCE_ERR_VALUE);
|
|
|
|
} else {
|
|
|
|
styler.ColourTo(endPos, style);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ColouriseErrorListDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
|
2021-02-21 04:53:09 +00:00
|
|
|
std::string lineBuffer;
|
2019-05-04 18:14:48 +00:00
|
|
|
styler.StartAt(startPos);
|
|
|
|
styler.StartSegment(startPos);
|
|
|
|
|
|
|
|
// property lexer.errorlist.value.separate
|
|
|
|
// For lines in the output pane that are matches from Find in Files or GCC-style
|
|
|
|
// diagnostics, style the path and line number separately from the rest of the
|
|
|
|
// line with style 21 used for the rest of the line.
|
|
|
|
// This allows matched text to be more easily distinguished from its location.
|
|
|
|
const bool valueSeparate = styler.GetPropertyInt("lexer.errorlist.value.separate", 0) != 0;
|
|
|
|
|
|
|
|
// property lexer.errorlist.escape.sequences
|
|
|
|
// Set to 1 to interpret escape sequences.
|
|
|
|
const bool escapeSequences = styler.GetPropertyInt("lexer.errorlist.escape.sequences") != 0;
|
|
|
|
|
|
|
|
for (Sci_PositionU i = startPos; i < startPos + length; i++) {
|
2021-02-21 04:53:09 +00:00
|
|
|
lineBuffer.push_back(styler[i]);
|
|
|
|
if (AtEOL(styler, i)) {
|
|
|
|
// End of line met, colourise it
|
|
|
|
ColouriseErrorListLine(lineBuffer, i, styler, valueSeparate, escapeSequences);
|
|
|
|
lineBuffer.clear();
|
2019-05-04 18:14:48 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-21 04:53:09 +00:00
|
|
|
if (!lineBuffer.empty()) { // Last line does not have ending characters
|
|
|
|
ColouriseErrorListLine(lineBuffer, startPos + length - 1, styler, valueSeparate, escapeSequences);
|
2019-05-04 18:14:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *const emptyWordListDesc[] = {
|
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
LexerModule lmErrorList(SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist", 0, emptyWordListDesc);
|