diff --git a/Build/Notepad3.ini b/Build/Notepad3.ini
index 6bd8cbbcf..b6adc4a9f 100644
--- a/Build/Notepad3.ini
+++ b/Build/Notepad3.ini
@@ -132,6 +132,7 @@ SettingsVersion=3
[Shell Script]
[SQL Query]
[Tcl Script]
+[TOML Config]
[VBScript]
[VHDL]
[Visual Basic]
diff --git a/Versions/build.txt b/Versions/build.txt
index 7f8dea745..f5008320a 100644
--- a/Versions/build.txt
+++ b/Versions/build.txt
@@ -1 +1 @@
-2252
+2255
diff --git a/res/Notepad3.exe.manifest.conf b/res/Notepad3.exe.manifest.conf
index cdb30d52b..9cb482527 100644
--- a/res/Notepad3.exe.manifest.conf
+++ b/res/Notepad3.exe.manifest.conf
@@ -3,7 +3,7 @@
Notepad3 Oniguruma
diff --git a/sciXlexers/CharSetX.h b/sciXlexers/CharSetX.h
index b0ae3e320..978845d05 100644
--- a/sciXlexers/CharSetX.h
+++ b/sciXlexers/CharSetX.h
@@ -18,6 +18,18 @@
//- IsUpperOrLowerCase(int ch);
//- IsAlphaNumeric(int ch);
+constexpr bool IsASpaceX(const int ch) noexcept {
+ return ((ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)));
+}
+
+constexpr bool IsABlankOrTabX(const int ch) noexcept {
+ return ((ch == ' ') || (ch == '\t'));
+}
+
+constexpr bool IsADigitX(const int ch) noexcept {
+ return ((ch >= '0') && (ch <= '9'));
+}
+
constexpr bool IsALetter(const int ch) noexcept {
// 97 to 122 || 65 to 90
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
@@ -28,7 +40,8 @@ constexpr bool IsLineBreak(const int ch) noexcept {
}
inline int IsNumber(const Scintilla::StyleContext& sc) {
- return Scintilla::IsADigit(sc.ch) || (((sc.ch == '+') || (sc.ch == '-')) && Scintilla::IsADigit(sc.chNext));
+ return Scintilla::IsADigit(sc.ch) ||
+ (((sc.ch == '+') || (sc.ch == '-')) && Scintilla::IsADigit(sc.chNext));
}
constexpr int IsNumHex(const Scintilla::StyleContext& sc) noexcept {
@@ -47,10 +60,16 @@ inline int IsNumExponent(const Scintilla::StyleContext& sc) {
return Scintilla::IsADigit(sc.ch) && ((sc.chNext == 'e') || (sc.chNext == 'E'));
}
-inline bool IsAIdentifierChar(const int ch) {
- return (Scintilla::IsAlphaNumeric(ch) || ch == '_' || ch == '.');
+inline void TrimIdentifier(const char* input, char* output)
+{
+ size_t j = 0;
+ for (size_t i = 0; input[i] != '\0'; ++i) {
+ if (!IsASpaceX(input[i])) {
+ output[j++] = input[i];
+ }
+ }
+ output[j] = '\0';
}
-
#endif //_CHARSETX_H_
diff --git a/sciXlexers/LexTOML.cxx b/sciXlexers/LexTOML.cxx
index 5dd65c27d..5ef5edeeb 100644
--- a/sciXlexers/LexTOML.cxx
+++ b/sciXlexers/LexTOML.cxx
@@ -64,7 +64,7 @@ namespace {
}
};
- static const char* const tomlWordListsDesc[] = {
+ static const char* const tomlWordLists[] = {
"Keyword",
nullptr
};
@@ -75,7 +75,7 @@ namespace {
DefineProperty("fold", &OptionsTOML::fold, "FOLD COMMENT");
DefineProperty("fold.compact", &OptionsTOML::foldCompact, "FOLDCOMPACT COMMENT");
- DefineWordListSets(tomlWordListsDesc);
+ DefineWordListSets(tomlWordLists);
}
};
@@ -99,7 +99,7 @@ namespace {
class LexerTOML : public DefaultLexer {
CharacterSet validKey;
- //CharacterSet validKeyWord;
+ CharacterSet validKeyWord;
CharacterSet validNumberEnd;
CharacterSet chDateTime;
@@ -112,7 +112,7 @@ public:
LexerTOML()
: DefaultLexer(lexicalClasses, ELEMENTS(lexicalClasses))
, validKey(CharacterSet::setAlphaNum, R"(-_.)", 0x80, false)
- //, validKeyWord(CharacterSet::setAlphaNum, "_", 0x80, false)
+ , validKeyWord(CharacterSet::setAlphaNum, "_+-", 0x80, false)
, validNumberEnd(CharacterSet::setNone, " \t\n\v\f\r#,)}]", 0x80, false)
, chDateTime(CharacterSet::setNone, "-:TZ", 0x80, false)
{ }
@@ -215,6 +215,17 @@ constexpr bool IsAssignChar(const int ch) noexcept {
}
// ----------------------------------------------------------------------------
+inline bool IsAIdentifierChar(const int ch) {
+ return (IsAlphaNumeric(ch) || ch == '_' || ch == '.');
+}
+// ----------------------------------------------------------------------------
+
+inline bool IsAKeywordChar(const int ch) {
+ return (IsAIdentifierChar(ch) || ch == '+' || ch == '-');
+}
+// ----------------------------------------------------------------------------
+
+
static int GetBracketLevel(StyleContext& sc, const bool stopAtLnBreak = false)
{
Sci_Position const posCurrent = static_cast(sc.currentPos);
@@ -257,9 +268,9 @@ static bool IsDateTimeStr(StyleContext& sc, const CharacterSet& validCh, const C
Sci_Position const posCurrent = static_cast(sc.currentPos);
Sci_Position const posEnd = static_cast(sc.lineStartNext);
- Sci_Position i = 0;
bool bDateTimeFlag = false;
+ Sci_Position i = 0;
while ((++i + posCurrent) < posEnd)
{
int const ch = sc.GetRelative(i);
@@ -286,9 +297,9 @@ static bool IsLookAheadLineEmpty(StyleContext& sc)
Sci_Position const posCurrent = static_cast(sc.currentPos);
Sci_Position const posEnd = static_cast(sc.lineStartNext);
- Sci_Position i = 0;
bool bLHLineEmpty = true;
+ Sci_Position i = 0;
while ((++i + posCurrent) < posEnd)
{
int const ch = sc.GetRelative(i);
@@ -305,6 +316,40 @@ static bool IsLookAheadLineEmpty(StyleContext& sc)
}
// ----------------------------------------------------------------------------
+static bool IsLookAheadInList(StyleContext& sc, const CharacterSet& validCh, const WordList& keywords)
+{
+ Sci_Position const posCurrent = static_cast(sc.currentPos);
+ Sci_Position const posEnd = static_cast(sc.lineStartNext);
+
+ static char identifier[1024] = { '\0' };
+
+ int j = 0;
+ Sci_Position i = -1;
+ while (((++i + posCurrent) < posEnd) && (j < 1023))
+ {
+ int const ch = sc.GetRelative(i);
+
+ if (IsABlankOrTabX(ch)) {
+ if (j == 0) { continue; }
+ }
+ if (validCh.Contains(ch)) {
+ identifier[j++] = static_cast(ch);
+ continue;
+ }
+ identifier[j] = '\0';
+ break;
+ }
+
+ if (identifier[0] != '\0') {
+ TrimIdentifier(identifier, identifier);
+ if (keywords.InList(identifier)) {
+ return true;
+ }
+ }
+ return false;
+}
+// ----------------------------------------------------------------------------
+
// ----------------------------------------------------------------------------
@@ -327,15 +372,20 @@ void SCI_METHOD LexerTOML::Lex(Sci_PositionU startPos, Sci_Position length, int
bool inBin = false;
bool inOct = false;
+ bool bPossibleKeyword = true;
+
for (; sc.More(); sc.Forward())
{
// --------------------------------------------------
// check if in the middle of a line continuation ...
// --------------------------------------------------
+ // reset context infos
if (sc.atLineStart) {
inMultiLnArrayDef = (GetBracketLevel(sc) >= 0);
- inSQuotedKey = inDQuotedKey = inInnerQKey = false; // clear
+ inSQuotedKey = inDQuotedKey = inInnerQKey = false;
+ bPossibleKeyword = true;
+
switch (sc.state)
{
case SCE_TOML_STR_BASIC:
@@ -344,11 +394,14 @@ void SCI_METHOD LexerTOML::Lex(Sci_PositionU startPos, Sci_Position length, int
sc.SetState(SCE_TOML_PARSINGERROR);
}
break;
+ case SCE_TOML_KEY:
case SCE_TOML_ASSIGNMENT:
sc.SetState(SCE_TOML_PARSINGERROR);
break;
case SCE_TOML_PARSINGERROR:
- // preserve error
+ if (!inMultiLnArrayDef) {
+ sc.SetState(SCE_TOML_DEFAULT);
+ }
break;
default:
if (!inMultiLnArrayDef) {
@@ -365,7 +418,7 @@ void SCI_METHOD LexerTOML::Lex(Sci_PositionU startPos, Sci_Position length, int
continue; // eat line breaks
}
- if (sc.ch != SCE_TOML_PARSINGERROR)
+ if (sc.state != SCE_TOML_PARSINGERROR)
{
if (IsCommentChar(sc.ch)) {
if (inSectionDef) {
@@ -440,13 +493,18 @@ void SCI_METHOD LexerTOML::Lex(Sci_PositionU startPos, Sci_Position length, int
case SCE_TOML_KEY:
- if ((sc.ch == '"') && inDQuotedKey) {
+ if (sc.atLineEnd) {
+ sc.SetState(SCE_TOML_PARSINGERROR);
+ break;
+ }
+ else if ((sc.ch == '"') && inDQuotedKey) {
if (inInnerQKey) {
sc.SetState(SCE_TOML_PARSINGERROR);
}
else {
sc.ForwardSetState(SCE_TOML_ASSIGNMENT); // end of key
}
+ break;
}
else if ((sc.ch == '\'') && inSQuotedKey) {
if (inInnerQKey) {
@@ -455,21 +513,23 @@ void SCI_METHOD LexerTOML::Lex(Sci_PositionU startPos, Sci_Position length, int
else {
sc.ForwardSetState(SCE_TOML_ASSIGNMENT); // end of key
}
+ break;
}
else if (IsASpaceOrTab(sc.ch)) {
if (!(inSQuotedKey || inDQuotedKey || inInnerQKey)) {
sc.SetState(SCE_TOML_ASSIGNMENT); // end of key
}
- // else eat
+ break; // else eat
}
else if (IsAssignChar(sc.ch)) {
- if (!(inSQuotedKey || inDQuotedKey || inInnerQKey)) {
- sc.SetState(SCE_TOML_ASSIGNMENT);
+ if ((inSQuotedKey || inDQuotedKey || inInnerQKey)) {
+ break;
}
- // else eat
+ sc.SetState(SCE_TOML_ASSIGNMENT); // end of key
+ // === fall through === case SCE_TOML_ASSIGNMENT:
}
else if (validKey.Contains(sc.ch)) {
- // eat
+ break; // eat
}
else {
if ((sc.ch == '"') && inSQuotedKey) {
@@ -481,20 +541,24 @@ void SCI_METHOD LexerTOML::Lex(Sci_PositionU startPos, Sci_Position length, int
else if (!(inSQuotedKey || inDQuotedKey || inInnerQKey)) {
sc.SetState(SCE_TOML_PARSINGERROR);
}
- // else eat
+ break; // else eat
}
- break;
-
+ // === fall through ===
case SCE_TOML_ASSIGNMENT:
- if (IsAssignChar(sc.ch)) {
- if (!IsLookAheadLineEmpty(sc)) {
- sc.ForwardSetState(SCE_TOML_VALUE);
+ if (sc.atLineEnd) {
+ sc.SetState(SCE_TOML_PARSINGERROR);
+ break;
+ }
+ else if (IsAssignChar(sc.ch)) {
+ if (IsLookAheadLineEmpty(sc)) {
+ sc.ForwardSetState(SCE_TOML_PARSINGERROR);
+ break;
}
else {
- sc.SetState(SCE_TOML_PARSINGERROR);
+ sc.ForwardSetState(SCE_TOML_VALUE);
+ // === fall through === case SCE_TOML_VALUE:
}
- // fall through case SCE_TOML_VALUE:
}
else if (IsASpace(sc.ch)) {
break; // OK
@@ -503,9 +567,16 @@ void SCI_METHOD LexerTOML::Lex(Sci_PositionU startPos, Sci_Position length, int
sc.SetState(SCE_TOML_PARSINGERROR);
break;
}
- // fall through
+ // === fall through ===
case SCE_TOML_VALUE:
+ if (bPossibleKeyword && IsLookAheadInList(sc, validKeyWord, keywords)) {
+ sc.SetState(SCE_TOML_KEYWORD);
+ break;
+ }
+ else {
+ bPossibleKeyword = false;
+ }
if (sc.ch == '[') {
inMultiLnArrayDef = true;
}
@@ -559,6 +630,13 @@ void SCI_METHOD LexerTOML::Lex(Sci_PositionU startPos, Sci_Position length, int
break;
+ case SCE_TOML_KEYWORD:
+ if (!(IsASpaceX(sc.ch) || validKeyWord.Contains(sc.ch))) {
+ sc.SetState(SCE_TOML_VALUE);
+ }
+ break;
+
+
case SCE_TOML_NUMBER:
if (sc.ch == '_') {
// eat // TODO: only once
@@ -765,7 +843,7 @@ void SCI_METHOD LexerTOML::Fold(Sci_PositionU startPos, Sci_Position length, int
}
// ----------------------------------------------------------------------------
-LexerModule lmTOML(SCLEX_TOML, LexerTOML::LexerFactoryTOML, "toml", tomlWordListsDesc);
+LexerModule lmTOML(SCLEX_TOML, LexerTOML::LexerFactoryTOML, "toml", tomlWordLists);
// ----------------------------------------------------------------------------
diff --git a/src/StyleLexers/styleLexTOML.c b/src/StyleLexers/styleLexTOML.c
index 4e2cfdead..fe9c90873 100644
--- a/src/StyleLexers/styleLexTOML.c
+++ b/src/StyleLexers/styleLexTOML.c
@@ -4,7 +4,7 @@
//KEYWORDLIST KeyWords_TOML = EMPTY_KEYWORDLIST;
KEYWORDLIST KeyWords_TOML = {
- "false inf nan table true", // Keyword
+ "+inf -inf +nan -nan inf nan true false", // Keyword
"", "", "", "", "", "", "", "" };
@@ -13,7 +13,7 @@ SCLEX_TOML, IDS_LEX_TOML_CFG, L"TOML Config", L"toml", L"",
&KeyWords_TOML,{
{ {STYLE_DEFAULT}, IDS_LEX_STR_63126, L"Default", L"", L"" },
//{ {SCE_TOML_DEFAULT}, IDS_LEX_STR_63126, L"Default", L"", L"" },
- { {SCE_TOML_KEYWORD}, IDS_LEX_STR_63128, L"Keyword", L"fore:#E00000", L"" },
+ { {SCE_TOML_KEYWORD}, IDS_LEX_STR_63128, L"Keyword", L"bold; fore:#FF0080", L"" },
{ {SCE_TOML_COMMENT}, IDS_LEX_STR_63127, L"Comment", L"fore:#008000", L"" },
{ {SCE_TOML_SECTION}, IDS_LEX_STR_63232, L"Section", L"bold; fore:#000000; back:#FFF1A8; eolfilled", L"" },
{ {SCE_TOML_KEY}, IDS_LEX_STR_63348, L"Key", L"bold; fore:#5E608F", L"" },
@@ -21,6 +21,6 @@ SCLEX_TOML, IDS_LEX_TOML_CFG, L"TOML Config", L"toml", L"",
{ {SCE_TOML_VALUE}, IDS_LEX_STR_63201, L"Value", L"fore:#202020", L"" },
{ {SCE_TOML_NUMBER}, IDS_LEX_STR_63130, L"Number", L"fore:#0000E0", L"" },
{ {SCE_TOML_DATETIME}, IDS_LEX_STR_63356, L"Date-Time", L"fore:#950095", L"" },
- { {MULTI_STYLE(SCE_TOML_STR_BASIC, SCE_TOML_STR_LITERAL,0,0)}, IDS_LEX_STR_63131, L"String", L"italic; fore:#800000", L"" },
- { {SCE_TOML_PARSINGERROR}, IDS_LEX_STR_63252, L"Parsing Error", L"fore:#FFFF00; back:#A00000", L"" },
+ { {MULTI_STYLE(SCE_TOML_STR_BASIC, SCE_TOML_STR_LITERAL,0,0)}, IDS_LEX_STR_63131, L"String", L"italic; fore:#606060", L"" },
+ { {SCE_TOML_PARSINGERROR}, IDS_LEX_STR_63252, L"Parsing Error", L"fore:#FFFF00; back:#A00000; eolfilled", L"" },
EDITLEXER_SENTINEL } };
diff --git a/src/Styles.c b/src/Styles.c
index e37a40195..e807e9d47 100644
--- a/src/Styles.c
+++ b/src/Styles.c
@@ -1419,8 +1419,8 @@ void Style_SetLexer(HWND hwnd, PEDITLEXER pLexNew)
switch (s_pLexCurrent->lexerID)
{
case SCLEX_PYTHON:
- SendMessage(hwnd, SCI_INDICSETSTYLE, 1, INDIC_COMPOSITIONTHIN);
- SendMessage(hwnd, SCI_INDICSETFORE, 1, (LPARAM)RGB(0xAF, 0, 0)); // (light red)
+ SendMessage(hwnd, SCI_INDICSETSTYLE, 1, INDIC_BOX);
+ SendMessage(hwnd, SCI_INDICSETFORE, 1, (LPARAM)RGB(0xBF, 0, 0)); // (light red)
//SendMessage(hwnd, SCI_INDICSETALPHA, 1, 40);
//SendMessage(hwnd, SCI_INDICSETOUTLINEALPHA, 1, 100);
break;
diff --git a/src/VersionEx.h b/src/VersionEx.h
index f8300f6a8..600b2d2fb 100644
--- a/src/VersionEx.h
+++ b/src/VersionEx.h
@@ -7,8 +7,8 @@
#define SAPPNAME "Notepad3"
#define VERSION_MAJOR 5
#define VERSION_MINOR 19
-#define VERSION_REV 613
-#define VERSION_BUILD 2252
+#define VERSION_REV 614
+#define VERSION_BUILD 2255
#define SCINTILLA_VER 416
#define ONIGURUMA_REGEX_VER 6.9.2
#define VERSION_PATCH Oniguruma
diff --git a/test/txtfiles/TOML.toml b/test/txtfiles/TOML.toml
index 5f9171e35..e41bcd885 100644
--- a/test/txtfiles/TOML.toml
+++ b/test/txtfiles/TOML.toml
@@ -41,6 +41,9 @@ bare-key = "value"
'key2' = "value"
'quoted "value"' = "value"
+# boolean
+bool1 = true
+bool2 = false
[strings]
str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."
@@ -137,10 +140,6 @@ sf4 = nan # actual sNaN/qNaN encoding is implementation specific
sf5 = +nan # same as `nan`
sf6 = -nan # valid, actual encoding is implementation specific
-# boolean
-bool1 = true
-bool2 = false
-
[date time]
# Offset Date-Time ( RFC 3339 : http://tools.ietf.org/html/rfc3339 )