diff --git a/build/CodeLite/Notepad2.project b/build/CodeLite/Notepad2.project
index 5798212ee5..ef885906f9 100644
--- a/build/CodeLite/Notepad2.project
+++ b/build/CodeLite/Notepad2.project
@@ -23,6 +23,7 @@
+
@@ -181,6 +182,7 @@
+
diff --git a/build/VS2017/Notepad2.vcxproj b/build/VS2017/Notepad2.vcxproj
index b15267a6c8..c8e6eb2263 100644
--- a/build/VS2017/Notepad2.vcxproj
+++ b/build/VS2017/Notepad2.vcxproj
@@ -970,6 +970,7 @@
+
@@ -1073,6 +1074,7 @@
+
diff --git a/build/VS2017/Notepad2.vcxproj.filters b/build/VS2017/Notepad2.vcxproj.filters
index 608e7a337d..219124780c 100644
--- a/build/VS2017/Notepad2.vcxproj.filters
+++ b/build/VS2017/Notepad2.vcxproj.filters
@@ -66,6 +66,9 @@
Scintilla\lexers
+
+ Scintilla\lexers
+
Scintilla\lexers
@@ -375,6 +378,9 @@
Source Files\EditLexers
+
+ Source Files\EditLexers
+
Source Files\EditLexers
diff --git a/doc/FileExt.txt b/doc/FileExt.txt
index fdd949ea8e..e015bef3fa 100644
--- a/doc/FileExt.txt
+++ b/doc/FileExt.txt
@@ -222,11 +222,15 @@ Config File
Doxyfile Doxygen Configuration
.* dot-file
+
D Source
d
di D Interface File
dd Ddoc Source File
+Dart Source
+ dart
+
Diff File
diff
patch
diff --git a/doc/Notepad2 DarkTheme.ini b/doc/Notepad2 DarkTheme.ini
index d43243a161..917db38b5c 100644
Binary files a/doc/Notepad2 DarkTheme.ini and b/doc/Notepad2 DarkTheme.ini differ
diff --git a/scintilla/include/SciLexer.h b/scintilla/include/SciLexer.h
index 5ebf27e436..a77c0e42b7 100644
--- a/scintilla/include/SciLexer.h
+++ b/scintilla/include/SciLexer.h
@@ -71,6 +71,7 @@
#define SCLEX_TOML 214
#define SCLEX_GN 215
#define SCLEX_GO 216
+#define SCLEX_DART 217
#define SCLEX_AUTOMATIC 1000
#define SCE_PY_DEFAULT 0
#define SCE_PY_COMMENTLINE 1
@@ -1041,4 +1042,36 @@
#define SCE_GO_FORMAT_SPECIFIER 21
#define SCE_GO_TASK_MARKER 22
#define SCE_GO_TASK_MARKER_LINE 23
+#define SCE_DART_DEFAULT 0
+#define SCE_DART_COMMENTLINE 1
+#define SCE_DART_COMMENTLINEDOC 2
+#define SCE_DART_COMMENTBLOCK 3
+#define SCE_DART_COMMENTBLOCKDOC 4
+#define SCE_DART_NUMBER 5
+#define SCE_DART_OPERATOR 6
+#define SCE_DART_OPERATOR2 7
+#define SCE_DART_IDENTIFIER 8
+#define SCE_DART_STRING_SQ 9
+#define SCE_DART_STRING_DQ 10
+#define SCE_DART_TRIPLE_SQ_STRING 11
+#define SCE_DART_TRIPLE_DQ_STRING 12
+#define SCE_DART_ESCAPECHAR 13
+#define SCE_DART_RAWSTRING_SQ 14
+#define SCE_DART_RAWSTRING_DQ 15
+#define SCE_DART_TRIPLE_RAWSTRING_SQ 16
+#define SCE_DART_TRIPLE_RAWSTRING_DQ 17
+#define SCE_DART_TRIPLE_SQ_STRINGSTART 18
+#define SCE_DART_TRIPLE_DQ_STRINGSTART 19
+#define SCE_DART_TRIPLE_SQ_STRINGEND 20
+#define SCE_DART_TRIPLE_DQ_STRINGEND 21
+#define SCE_DART_SYMBOL_OPERATOR 22
+#define SCE_DART_SYMBOL_IDENTIFIER 23
+#define SCE_DART_VARIABLE 24
+#define SCE_DART_METADATA 25
+#define SCE_DART_LABEL 26
+#define SCE_DART_FUNCTION 27
+#define SCE_DART_WORD 28
+#define SCE_DART_WORD2 29
+#define SCE_DART_CLASS 30
+#define SCE_DART_ENUM 31
/* --Autogenerated -- end of section automatically generated from SciLexer.iface */
diff --git a/scintilla/include/SciLexer.iface b/scintilla/include/SciLexer.iface
index 3f33cc05a9..2e380c36ae 100644
--- a/scintilla/include/SciLexer.iface
+++ b/scintilla/include/SciLexer.iface
@@ -157,6 +157,7 @@ val SCLEX_WASM=213
val SCLEX_TOML=214
val SCLEX_GN=215
val SCLEX_GO=216
+val SCLEX_DART=217
# When a lexer specifies its language as SCLEX_AUTOMATIC it receives a
# value assigned in sequence from SCLEX_AUTOMATIC+1.
@@ -2602,3 +2603,37 @@ val SCE_GO_FUNCTION_DEFINE=20
val SCE_GO_FORMAT_SPECIFIER=21
val SCE_GO_TASK_MARKER=22
val SCE_GO_TASK_MARKER_LINE=23
+# Lexical states for SCLEX_DART
+lex DART=SCLEX_DART SCE_DART_
+val SCE_DART_DEFAULT=0
+val SCE_DART_COMMENTLINE=1
+val SCE_DART_COMMENTLINEDOC=2
+val SCE_DART_COMMENTBLOCK=3
+val SCE_DART_COMMENTBLOCKDOC=4
+val SCE_DART_NUMBER=5
+val SCE_DART_OPERATOR=6
+val SCE_DART_OPERATOR2=7
+val SCE_DART_IDENTIFIER=8
+val SCE_DART_STRING_SQ=9
+val SCE_DART_STRING_DQ=10
+val SCE_DART_TRIPLE_SQ_STRING=11
+val SCE_DART_TRIPLE_DQ_STRING=12
+val SCE_DART_ESCAPECHAR=13
+val SCE_DART_RAWSTRING_SQ=14
+val SCE_DART_RAWSTRING_DQ=15
+val SCE_DART_TRIPLE_RAWSTRING_SQ=16
+val SCE_DART_TRIPLE_RAWSTRING_DQ=17
+val SCE_DART_TRIPLE_SQ_STRINGSTART=18
+val SCE_DART_TRIPLE_DQ_STRINGSTART=19
+val SCE_DART_TRIPLE_SQ_STRINGEND=20
+val SCE_DART_TRIPLE_DQ_STRINGEND=21
+val SCE_DART_SYMBOL_OPERATOR=22
+val SCE_DART_SYMBOL_IDENTIFIER=23
+val SCE_DART_VARIABLE=24
+val SCE_DART_METADATA=25
+val SCE_DART_LABEL=26
+val SCE_DART_FUNCTION=27
+val SCE_DART_WORD=28
+val SCE_DART_WORD2=29
+val SCE_DART_CLASS=30
+val SCE_DART_ENUM=31
diff --git a/scintilla/lexers/LexDart.cxx b/scintilla/lexers/LexDart.cxx
new file mode 100644
index 0000000000..62f7bab540
--- /dev/null
+++ b/scintilla/lexers/LexDart.cxx
@@ -0,0 +1,485 @@
+// This file is part of Notepad2.
+// See License.txt for details about distribution and modification.
+//! Lexer for Dart.
+
+#include
+#include
+
+#include
+
+#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"
+#include "LexerUtils.h"
+
+using namespace Scintilla;
+
+namespace {
+
+struct EscapeSequence {
+ int outerState = SCE_DART_DEFAULT;
+ int digitsLeft = 0;
+
+ // highlight any character as escape sequence, no highlight for hex in '\u{hex}'.
+ bool resetEscapeState(int state, int chNext) noexcept {
+ outerState = state;
+ digitsLeft = (chNext == 'x')? 3 : ((chNext == 'u') ? 5 : 1);
+ return true;
+ }
+ bool atEscapeEnd(int ch) noexcept {
+ --digitsLeft;
+ return digitsLeft <= 0 || !IsHexDigit(ch);
+ }
+};
+
+enum {
+ MaxDartNestedStateCount = 4,
+ DartLineStateMaskLineComment = 1, // line comment
+ DartLineStateMaskImport = (1 << 1), // import
+};
+
+constexpr int PackState(int state) noexcept {
+ switch (state) {
+ case SCE_DART_STRING_SQ:
+ return 1;
+ case SCE_DART_STRING_DQ:
+ return 2;
+ case SCE_DART_TRIPLE_SQ_STRING:
+ return 3;
+ case SCE_DART_TRIPLE_DQ_STRING:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+constexpr int UnpackState(int state) noexcept {
+ switch (state) {
+ case 1:
+ return SCE_DART_STRING_SQ;
+ case 2:
+ return SCE_DART_STRING_DQ;
+ case 3:
+ return SCE_DART_TRIPLE_SQ_STRING;
+ case 4:
+ return SCE_DART_TRIPLE_DQ_STRING;
+ default:
+ return SCE_DART_DEFAULT;
+ }
+}
+
+int PackNestedState(const std::vector& nestedState) noexcept {
+ return PackLineState<3, MaxDartNestedStateCount, PackState>(nestedState) << 16;
+}
+
+void UnpackNestedState(int lineState, int count, std::vector& nestedState) {
+ UnpackLineState<3, MaxDartNestedStateCount, UnpackState>(lineState, count, nestedState);
+}
+
+void ColouriseDartDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, LexerWordList keywordLists, Accessor &styler) {
+ int lineStateLineComment = 0;
+ int lineStateImport = 0;
+ int commentLevel = 0; // nested block comment level
+
+ int kwType = SCE_DART_DEFAULT;
+ int chBeforeIdentifier = 0;
+
+ int curlyBrace = 0; // "${}"
+ int variableOuter = SCE_DART_DEFAULT; // variable inside string
+ std::vector nestedState;
+
+ int visibleChars = 0;
+ EscapeSequence escSeq;
+
+ StyleContext sc(startPos, lengthDoc, initStyle, styler);
+ if (sc.currentLine > 0) {
+ const int lineState = styler.GetLineState(sc.currentLine - 1);
+ /*
+ 1: lineStateLineComment
+ 1: lineStateImport
+ 6: commentLevel
+ 8: curlyBrace
+ 3*4: nestedState
+ */
+ commentLevel = (lineState >> 2) & 0x3f;
+ curlyBrace = (lineState >> 8) & 0xff;
+ if (curlyBrace) {
+ UnpackNestedState((lineState >> 16) & 0xff, curlyBrace, nestedState);
+ }
+ }
+ if (startPos == 0 && sc.Match('#', '!')) {
+ // Shell Shebang at beginning of file
+ sc.SetState(SCE_DART_COMMENTLINE);
+ lineStateLineComment = DartLineStateMaskLineComment;
+ }
+
+ while (sc.More()) {
+ switch (sc.state) {
+ case SCE_DART_OPERATOR:
+ case SCE_DART_OPERATOR2:
+ sc.SetState(SCE_DART_DEFAULT);
+ break;
+
+ case SCE_DART_NUMBER:
+ if (!IsDecimalNumber(sc.chPrev, sc.ch, sc.chNext)) {
+ sc.SetState(SCE_DART_DEFAULT);
+ }
+ break;
+
+ case SCE_DART_IDENTIFIER:
+ if (!IsIdentifierCharEx(sc.ch)) {
+ char s[128];
+ sc.GetCurrent(s, sizeof(s));
+ if (keywordLists[0]->InList(s)) {
+ sc.ChangeState(SCE_DART_WORD);
+ if (EqualsAny(s, "import", "part")) {
+ if (visibleChars == sc.LengthCurrent()) {
+ lineStateImport = DartLineStateMaskImport;
+ }
+ } else if (EqualsAny(s, "as", "class", "extends", "implements", "is", "new", "throw")) {
+ kwType = SCE_DART_CLASS;
+ } else if (strcmp(s, "enum") == 0) {
+ kwType = SCE_DART_ENUM;
+ }
+ } else if (keywordLists[1]->InList(s)) {
+ sc.ChangeState(SCE_DART_WORD2);
+ } else if (keywordLists[2]->InList(s)) {
+ sc.ChangeState(SCE_DART_CLASS);
+ } else if (keywordLists[3]->InList(s)) {
+ sc.ChangeState(SCE_DART_ENUM);
+ } else if (kwType != SCE_DART_DEFAULT) {
+ sc.ChangeState(kwType);
+ } else {
+ const int chNext = sc.GetNextNSChar();
+ if (chNext == '(') {
+ sc.ChangeState(SCE_DART_FUNCTION);
+ } else if ((chBeforeIdentifier == '<' && chNext == '>')
+ || IsIdentifierStartEx(chNext)) {
+ // type
+ // type identifier
+ sc.ChangeState(SCE_DART_CLASS);
+ }
+ }
+ if (sc.state != SCE_DART_WORD) {
+ kwType = SCE_DART_DEFAULT;
+ }
+ sc.SetState(SCE_DART_DEFAULT);
+ }
+ break;
+
+ case SCE_DART_METADATA:
+ case SCE_DART_SYMBOL_IDENTIFIER:
+ if (sc.ch == '.') {
+ const int state = sc.state;
+ sc.SetState(SCE_DART_OPERATOR);
+ sc.ForwardSetState(state);
+ continue;
+ }
+ if (!IsIdentifierCharEx(sc.ch)) {
+ sc.SetState(SCE_DART_DEFAULT);
+ }
+ break;
+
+ case SCE_DART_SYMBOL_OPERATOR:
+ if (!isoperator(sc.ch)) {
+ sc.SetState(SCE_DART_DEFAULT);
+ }
+ break;
+
+ case SCE_DART_COMMENTLINE:
+ case SCE_DART_COMMENTLINEDOC:
+ if (sc.atLineStart) {
+ sc.SetState(SCE_DART_DEFAULT);
+ }
+ break;
+
+ case SCE_DART_COMMENTBLOCK:
+ case SCE_DART_COMMENTBLOCKDOC:
+ if (sc.Match('*', '/')) {
+ sc.Forward();
+ --commentLevel;
+ if (commentLevel == 0) {
+ sc.ForwardSetState(SCE_DART_DEFAULT);
+ }
+ } else if (sc.Match('/', '*')) {
+ sc.Forward(2);
+ ++commentLevel;
+ }
+ break;
+
+ case SCE_DART_RAWSTRING_SQ:
+ case SCE_DART_RAWSTRING_DQ:
+ if (sc.atLineStart) {
+ sc.SetState(SCE_DART_DEFAULT);
+ } else if ((sc.state == SCE_DART_RAWSTRING_SQ && sc.ch == '\'')
+ || (sc.state == SCE_DART_RAWSTRING_DQ && sc.ch == '"')) {
+ sc.ForwardSetState(SCE_DART_DEFAULT);
+ }
+ break;
+
+ case SCE_DART_TRIPLE_RAWSTRING_SQ:
+ case SCE_DART_TRIPLE_RAWSTRING_DQ:
+ if ((sc.state == SCE_DART_TRIPLE_RAWSTRING_SQ && sc.Match('\'', '\'', '\''))
+ || (sc.state == SCE_DART_TRIPLE_RAWSTRING_DQ && sc.Match('"', '"', '"'))) {
+ sc.Forward(2);
+ sc.ForwardSetState(SCE_DART_DEFAULT);
+ }
+ break;
+
+ case SCE_DART_STRING_SQ:
+ case SCE_DART_STRING_DQ:
+ case SCE_DART_TRIPLE_SQ_STRING:
+ case SCE_DART_TRIPLE_DQ_STRING:
+ if (curlyBrace == 0 && (sc.state == SCE_DART_STRING_SQ || sc.state == SCE_DART_STRING_DQ) && sc.atLineStart) {
+ sc.SetState(SCE_DART_DEFAULT);
+ } else if (sc.ch == '\\') {
+ if (escSeq.resetEscapeState(sc.state, sc.chNext)) {
+ sc.SetState(SCE_DART_ESCAPECHAR);
+ sc.Forward();
+ }
+ } else if (sc.ch == '$' && IsIdentifierStartEx(sc.chNext)) {
+ variableOuter = sc.state;
+ sc.SetState(SCE_DART_VARIABLE);
+ } else if (sc.Match('$', '{')) {
+ ++curlyBrace;
+ nestedState.push_back(sc.state);
+ sc.SetState(SCE_DART_OPERATOR2);
+ sc.Forward();
+ } else if (curlyBrace && sc.ch == '}') {
+ const int outerState = TryPopBack(nestedState);
+ --curlyBrace;
+ sc.SetState(SCE_DART_OPERATOR2);
+ sc.ForwardSetState(outerState);
+ continue;
+ } else if (sc.ch == '\'' && (sc.state == SCE_DART_STRING_SQ
+ || (sc.state == SCE_DART_TRIPLE_SQ_STRING && sc.Match('\'', '\'', '\'')))) {
+ if (sc.state == SCE_DART_TRIPLE_SQ_STRING) {
+ sc.SetState(SCE_DART_TRIPLE_SQ_STRINGEND);
+ sc.Forward(2);
+ }
+ sc.ForwardSetState(SCE_DART_DEFAULT);
+ } else if (sc.ch == '"' && (sc.state == SCE_DART_STRING_DQ
+ || (sc.state == SCE_DART_TRIPLE_DQ_STRING && sc.Match('"', '"', '"')))) {
+ if (sc.state == SCE_DART_TRIPLE_DQ_STRING) {
+ sc.SetState(SCE_DART_TRIPLE_DQ_STRINGEND);
+ sc.Forward(2);
+ }
+ sc.ForwardSetState(SCE_DART_DEFAULT);
+ }
+ break;
+ case SCE_DART_ESCAPECHAR:
+ if (escSeq.atEscapeEnd(sc.ch)) {
+ const int outerState = escSeq.outerState;
+ if (sc.ch == '\\' && escSeq.resetEscapeState(outerState, sc.chNext)) {
+ sc.Forward();
+ } else {
+ sc.SetState(outerState);
+ continue;
+ }
+ }
+ break;
+ case SCE_DART_VARIABLE:
+ if (!IsIdentifierCharEx(sc.ch)) {
+ sc.SetState(variableOuter);
+ continue;
+ }
+ break;
+ }
+
+ if (sc.state == SCE_DART_DEFAULT) {
+ if (sc.Match('/', '/')) {
+ const int chNext = sc.GetRelative(2);
+ sc.SetState((chNext == '/') ? SCE_DART_COMMENTLINEDOC : SCE_DART_COMMENTLINE);
+ if (visibleChars == 0) {
+ lineStateLineComment = DartLineStateMaskLineComment;
+ }
+ } else if (sc.Match('/', '*')) {
+ const int chNext = sc.GetRelative(2);
+ sc.SetState((chNext == '*') ? SCE_DART_COMMENTBLOCKDOC : SCE_DART_COMMENTBLOCK);
+ sc.Forward();
+ commentLevel = 1;
+ } else if (sc.ch == 'r' && (sc.chNext == '\'' || sc.chNext == '"')) {
+ sc.SetState((sc.chNext == '\'') ? SCE_DART_RAWSTRING_SQ : SCE_DART_RAWSTRING_DQ);
+ sc.Forward(2);
+ if (sc.chPrev == '\'' && sc.Match('\'', '\'')) {
+ sc.ChangeState(SCE_DART_TRIPLE_RAWSTRING_SQ);
+ sc.Forward(2);
+ } else if (sc.chPrev == '"' && sc.Match('"', '"')) {
+ sc.ChangeState(SCE_DART_TRIPLE_RAWSTRING_DQ);
+ sc.Forward(2);
+ }
+ continue;
+ } else if (sc.Match('"', '"', '"')) {
+ sc.ChangeState(SCE_DART_TRIPLE_DQ_STRINGSTART);
+ sc.Forward(2);
+ sc.ForwardSetState(SCE_DART_TRIPLE_DQ_STRING);
+ continue;
+ } else if (sc.ch == '"') {
+ sc.SetState(SCE_DART_STRING_DQ);
+ } else if (sc.Match('\'', '\'', '\'')) {
+ sc.ChangeState(SCE_DART_TRIPLE_SQ_STRINGSTART);
+ sc.Forward(2);
+ sc.ForwardSetState(SCE_DART_TRIPLE_SQ_STRING);
+ continue;
+ } else if (sc.ch == '\'') {
+ sc.SetState(SCE_DART_STRING_SQ);
+ } else if (IsNumberStart(sc.ch, sc.chNext)) {
+ sc.SetState(SCE_DART_NUMBER);
+ } else if ((sc.ch == '@' || sc.ch == '$') && IsIdentifierStartEx(sc.chNext)) {
+ variableOuter = SCE_DART_DEFAULT;
+ sc.SetState((sc.ch == '@') ? SCE_DART_METADATA : SCE_DART_VARIABLE);
+ } else if (sc.ch == '#') {
+ if (IsIdentifierStartEx(sc.chNext)) {
+ sc.SetState(SCE_DART_SYMBOL_IDENTIFIER);
+ } else if (isoperator(sc.ch)) {
+ sc.SetState(SCE_DART_SYMBOL_OPERATOR);
+ }
+ } else if (IsIdentifierStartEx(sc.ch)) {
+ chBeforeIdentifier = sc.chPrev;
+ sc.SetState(SCE_DART_IDENTIFIER);
+ } else if (isoperator(sc.ch)) {
+ sc.SetState(curlyBrace ? SCE_DART_OPERATOR2 : SCE_DART_OPERATOR);
+ if (curlyBrace) {
+ if (sc.ch == '{') {
+ ++curlyBrace;
+ nestedState.push_back(SCE_DART_DEFAULT);
+ } else if (sc.ch == '}') {
+ --curlyBrace;
+ const int outerState = TryPopBack(nestedState);
+ sc.ForwardSetState(outerState);
+ continue;
+ }
+ }
+ }
+ }
+
+ if (!isspacechar(sc.ch)) {
+ visibleChars++;
+ }
+ if (sc.atLineEnd) {
+ int lineState = (curlyBrace << 8) | (commentLevel << 2) | lineStateLineComment | lineStateImport;
+ if (curlyBrace) {
+ lineState |= PackNestedState(nestedState);
+ }
+ styler.SetLineState(sc.currentLine, lineState);
+ lineStateLineComment = 0;
+ lineStateImport = 0;
+ visibleChars = 0;
+ kwType = SCE_DART_DEFAULT;
+ }
+ sc.Forward();
+ }
+
+ sc.Complete();
+}
+
+struct FoldLineState {
+ int lineComment;
+ int packageImport;
+ constexpr explicit FoldLineState(int lineState) noexcept:
+ lineComment(lineState & DartLineStateMaskLineComment),
+ packageImport((lineState >> 1) & 1) {
+ }
+};
+
+constexpr bool IsStreamCommentStyle(int style) noexcept {
+ return style == SCE_DART_COMMENTBLOCK || style == SCE_DART_COMMENTBLOCKDOC;
+}
+
+void FoldDartDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, LexerWordList, Accessor &styler) {
+ const int foldComment = styler.GetPropertyInt("fold.comment", 1);
+
+ const Sci_PositionU endPos = startPos + lengthDoc;
+ Sci_Position lineCurrent = styler.GetLine(startPos);
+ FoldLineState foldPrev(0);
+ int levelCurrent = SC_FOLDLEVELBASE;
+ if (lineCurrent > 0) {
+ levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16;
+ foldPrev = FoldLineState(styler.GetLineState(lineCurrent - 1));
+ }
+
+ int levelNext = levelCurrent;
+ FoldLineState foldCurrent(styler.GetLineState(lineCurrent));
+ Sci_PositionU lineStartNext = styler.LineStart(lineCurrent + 1);
+ Sci_PositionU lineEndPos = ((lineStartNext < endPos) ? lineStartNext : endPos) - 1;
+
+ char chNext = styler[startPos];
+ int styleNext = styler.StyleAt(startPos);
+ int style = initStyle;
+
+ for (Sci_PositionU i = startPos; i < endPos; i++) {
+ const char ch = chNext;
+ chNext = styler.SafeGetCharAt(i + 1);
+ const int stylePrev = style;
+ style = styleNext;
+ styleNext = styler.StyleAt(i + 1);
+
+ if (IsStreamCommentStyle(style)) {
+ if (foldComment) {
+ const int level = (ch == '/' && chNext == '*') ? 1 : ((ch == '*' && chNext == '/') ? -1 : 0);
+ if (level != 0) {
+ levelNext += level;
+ i++;
+ chNext = styler.SafeGetCharAt(i + 1);
+ styleNext = styler.StyleAt(i + 1);
+ }
+ }
+ } else if (style == SCE_DART_TRIPLE_RAWSTRING_SQ || style == SCE_DART_TRIPLE_RAWSTRING_DQ) {
+ if (style != stylePrev) {
+ levelNext++;
+ } else if (style != styleNext) {
+ levelNext--;
+ }
+ } else if (style == SCE_DART_TRIPLE_SQ_STRINGSTART || style == SCE_DART_TRIPLE_DQ_STRINGSTART) {
+ if (style != stylePrev) {
+ levelNext++;
+ }
+ } else if (style == SCE_DART_TRIPLE_SQ_STRINGEND || style == SCE_DART_TRIPLE_DQ_STRINGEND) {
+ if (style != styleNext) {
+ levelNext--;
+ }
+ } else if (style == SCE_DART_OPERATOR) {
+ if (ch == '{' || ch == '[' || ch == '(') {
+ levelNext++;
+ } else if (ch == '}' || ch == ']' || ch == ')') {
+ levelNext--;
+ }
+ }
+
+ if (i == lineEndPos) {
+ const FoldLineState foldNext(styler.GetLineState(lineCurrent + 1));
+ if (foldComment & foldCurrent.lineComment) {
+ levelNext += foldNext.lineComment - foldPrev.lineComment;
+ } else if (foldCurrent.packageImport) {
+ levelNext += foldNext.packageImport - foldPrev.packageImport;
+ }
+
+ const int levelUse = levelCurrent;
+ int lev = levelUse | levelNext << 16;
+ if (levelUse < levelNext) {
+ lev |= SC_FOLDLEVELHEADERFLAG;
+ }
+ if (lev != styler.LevelAt(lineCurrent)) {
+ styler.SetLevel(lineCurrent, lev);
+ }
+
+ lineCurrent++;
+ lineStartNext = styler.LineStart(lineCurrent + 1);
+ lineEndPos = ((lineStartNext < endPos) ? lineStartNext : endPos) - 1;
+ levelCurrent = levelNext;
+ foldPrev = foldCurrent;
+ foldCurrent = foldNext;
+ }
+ }
+}
+
+}
+
+LexerModule lmDart(SCLEX_DART, ColouriseDartDoc, "dart", FoldDartDoc);
diff --git a/scintilla/src/Catalogue.cxx b/scintilla/src/Catalogue.cxx
index 1fa5ad5ed3..e8247fa051 100644
--- a/scintilla/src/Catalogue.cxx
+++ b/scintilla/src/Catalogue.cxx
@@ -86,6 +86,7 @@ void Scintilla_LinkLexers() {
//extern LexerModule lmCsound;
extern LexerModule lmCss;
//extern LexerModule lmD;
+ extern LexerModule lmDart;
//extern LexerModule lmDataflex;
extern LexerModule lmDiff;
//extern LexerModule lmDMAP;
@@ -232,6 +233,7 @@ void Scintilla_LinkLexers() {
//&lmCsound,
&lmCss,
//&lmD,
+ &lmDart,
//&lmDataflex,
&lmDiff,
//&lmDMAP,
diff --git a/src/EditLexer.h b/src/EditLexer.h
index de1c41a0e4..4cad672790 100644
--- a/src/EditLexer.h
+++ b/src/EditLexer.h
@@ -142,6 +142,8 @@ typedef const EDITLEXER *LPCEDITLEXER;
#define NP2LEX_WASM 63070 // SCLEX_WASM WebAssembly
#define NP2LEX_TOML 63071 // SCLEX_TOML TOML File
#define NP2LEX_GN 63072 // SCLEX_GN GN Build Script
+#define NP2LEX_DART 63073 // SCLEX_DART Dart Source
+#define NP2LEX_REBOL 63074 // SCLEX_REBOL Rebol Script
#define NP2LEX_AVS 63087 // SCLEX_AVS AviSynth Script
#define NP2LEX_TEHEX 63088 // SCLEX_TEHEX Tektronix extended HEX
diff --git a/src/EditLexers/stlDart.c b/src/EditLexers/stlDart.c
new file mode 100644
index 0000000000..3903bd7de3
--- /dev/null
+++ b/src/EditLexers/stlDart.c
@@ -0,0 +1,66 @@
+#include "EditLexer.h"
+#include "EditStyleX.h"
+
+static KEYWORDLIST Keywords_Dart = {{
+//++Autogenerated -- start of section automatically generated
+"abstract as assert async await break case catch class const continue covariant default deferred do "
+"else enum export extends extension external factory false final finally for get hide "
+"if implements import in interface is late library mixin native new null of on operator part required rethrow return "
+"set show static super switch sync this throw true try typedef var while with yield "
+
+, // 1 types
+"Function bool double dynamic int num void "
+
+, // 2 class
+"BidirectionalIterator BigInt Comparable Comparator Completer "
+"DateTime Deprecated Directory DoubleLinkedQueue DoubleLinkedQueueEntry Duration Error Exception Expando "
+"File FileStat FileSystemEntity FileSystemEvent Future FutureOr HasNextIterator HashMap HashSet "
+"IOException Invocation Iterable IterableBase IterableMixin Iterator "
+"LinkedHashMap LinkedHashSet LinkedList LinkedListEntry List ListBase ListMixin ListQueue "
+"Map MapBase MapEntry MapMixin MapView Match Null OSError Object Pattern Platform Point Process Queue "
+"Random RawSocket RawSocketEvent Rectangle RegExp RegExpMatch RuneIterator Runes "
+"ServerSocket Set SetBase SetMixin Sink Socket SocketException SplayTreeMap SplayTreeSet "
+"StackTrace Stopwatch Stream String StringBuffer StringSink Symbol SystemHash "
+"Timer Type Uri UriData "
+
+, // 3 enum
+NULL
+
+, // 4 metadata
+"Deprecated( Since( deprecated override patch pragma( "
+
+, // 5 function
+"identical( identityHashCode( main( print( "
+
+, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+//--Autogenerated -- end of section automatically generated
+}};
+
+static EDITSTYLE Styles_Dart[] = {
+ EDITSTYLE_DEFAULT,
+ { SCE_DART_WORD, NP2StyleX_Keyword, L"fore:#0000FF" },
+ { SCE_DART_WORD2, NP2StyleX_TypeKeyword, L"fore:#0000FF" },
+ { SCE_DART_METADATA, NP2StyleX_Annotation, L"fore:#FF8000" },
+ { SCE_DART_CLASS, NP2StyleX_Class, L"fore:#0080FF" },
+ { SCE_DART_ENUM, NP2StyleX_Enumeration, L"fore:#FF8000" },
+ { SCE_DART_FUNCTION, NP2StyleX_Function, L"fore:#A46000" },
+ { MULTI_STYLE(SCE_DART_COMMENTBLOCK, SCE_DART_COMMENTLINE, 0, 0), NP2StyleX_Comment, L"fore:#608060" },
+ { MULTI_STYLE(SCE_DART_COMMENTBLOCKDOC, SCE_DART_COMMENTLINEDOC, 0, 0), NP2StyleX_DocComment, L"fore:#408040" },
+ { MULTI_STYLE(SCE_DART_STRING_SQ, SCE_DART_STRING_DQ, 0, 0), NP2StyleX_String, L"fore:#008000" },
+ { MULTI_STYLE(SCE_DART_TRIPLE_SQ_STRING, SCE_DART_TRIPLE_DQ_STRING, 0, 0), NP2StyleX_TripleQuotedString, L"fore:#F08000" },
+ { MULTI_STYLE(SCE_DART_RAWSTRING_SQ, SCE_DART_RAWSTRING_DQ, SCE_DART_TRIPLE_RAWSTRING_SQ, SCE_DART_TRIPLE_RAWSTRING_DQ), NP2StyleX_RawString, L"fore:#F08000" },
+ { SCE_DART_ESCAPECHAR, NP2StyleX_EscapeSequence, L"fore:#0080C0" },
+ { SCE_DART_LABEL, NP2StyleX_Label, L"fore:#7C5AF3" },
+ { SCE_DART_NUMBER, NP2StyleX_Number, L"fore:#FF0000" },
+ { SCE_DART_VARIABLE, NP2StyleX_Variable, L"fore:#9E4D2A" },
+ { MULTI_STYLE(SCE_DART_SYMBOL_OPERATOR, SCE_DART_SYMBOL_IDENTIFIER, 0, 0), NP2StyleX_Symbol, L"fore:#7C5AF3" },
+ { MULTI_STYLE(SCE_DART_OPERATOR, SCE_DART_OPERATOR2, 0, 0), NP2StyleX_Operator, L"fore:#B000B0" },
+};
+
+EDITLEXER lexDart = {
+ SCLEX_DART, NP2LEX_DART,
+ EDITLEXER_HOLE(L"Dart Source", Styles_Dart),
+ L"dart",
+ &Keywords_Dart,
+ Styles_Dart
+};
diff --git a/src/Styles.c b/src/Styles.c
index 9732ac4e1f..896153370b 100644
--- a/src/Styles.c
+++ b/src/Styles.c
@@ -70,6 +70,7 @@ extern EDITLEXER lexCMake;
extern EDITLEXER lexCONF;
extern EDITLEXER lexD;
+extern EDITLEXER lexDart;
extern EDITLEXER lexDIFF;
extern EDITLEXER lexFSharp;
@@ -164,6 +165,7 @@ static PEDITLEXER pLexArray[] = {
&lexCONF,
&lexD,
+ &lexDart,
&lexDIFF,
&lexFSharp,
@@ -1241,6 +1243,10 @@ void Style_UpdateLexerKeywordAttr(LPCEDITLEXER pLexNew) {
attr[6] = KeywordAttr_NoLexer; // long properties
attr[7] = KeywordAttr_NoLexer; // long variables
break;
+ case NP2LEX_DART:
+ attr[4] = KeywordAttr_NoLexer; // metadata
+ attr[5] = KeywordAttr_NoLexer; // function
+ break;
case NP2LEX_GN:
attr[3] = KeywordAttr_NoLexer; // target variables
attr[4] = KeywordAttr_NoLexer; // placeholders
@@ -1741,7 +1747,23 @@ void Style_SetLexer(PEDITLEXER pLexNew, BOOL bLexerChanged) {
Style_SetStyles(iStyle, szValue);
}
}
- if (iLexer == SCLEX_PERL) {
+ switch (iLexer) {
+ case SCLEX_DART:
+ szValue = Style_FindStyleValue(pLexNew, SCE_DART_TRIPLE_SQ_STRING);
+ if (szValue != NULL) {
+ Style_Parse(&style, szValue);
+ uint32_t styles = SCE_DART_TRIPLE_SQ_STRINGSTART
+ | (SCE_DART_TRIPLE_DQ_STRINGSTART << 8)
+ | (SCE_DART_TRIPLE_SQ_STRINGEND << 16)
+ | (SCE_DART_TRIPLE_DQ_STRINGEND << 24);
+ do {
+ Style_SetParsed(&style, (int)(styles & 0xff));
+ styles >>= 8;
+ } while (styles);
+ }
+ break;
+
+ case SCLEX_PERL:
szValue = Style_FindStyleValue(pLexNew, SCE_PL_SCALAR);
if (szValue != NULL) {
Style_Parse(&style, szValue);
@@ -1758,6 +1780,7 @@ void Style_SetLexer(PEDITLEXER pLexNew, BOOL bLexerChanged) {
scalar >>= 8;
} while (scalar);
}
+ break;
}
} else {
szValue = pLexNew->Styles[ANSIArtStyleIndex_LineNumber].szValue;
diff --git a/tools/KeywordCore.py b/tools/KeywordCore.py
index 5b1a8e9969..aa2697ab82 100644
--- a/tools/KeywordCore.py
+++ b/tools/KeywordCore.py
@@ -325,6 +325,44 @@ def get_prefix(name):
]
return keywordList
+def parse_dart_api_file(path):
+ sections = read_api_file(path, '//')
+ keywordMap = {}
+ for key, doc in sections:
+ if key in ('keywords', 'types'):
+ items = set(doc.split())
+ keywordMap[key] = items
+ elif key == 'libraries':
+ items = re.findall(r'(class|typedef)\s+(\w+)', doc)
+ keywordMap['class'] = [item[1] for item in items]
+
+ items = re.findall(r'(enum)\s+(\w+)', doc)
+ keywordMap['enum'] = [item[1] for item in items]
+
+ items = re.findall(r'@(\w+\(?)', doc)
+ keywordMap['metadata'] = items
+
+ items = re.findall(r'\s\w+\(', doc)
+ keywordMap['function'] = [item.strip() for item in items]
+
+ RemoveDuplicateKeyword(keywordMap, [
+ 'keywords',
+ 'types',
+ 'class',
+ 'enum',
+ 'metadata',
+ 'function',
+ ])
+ keywordList = [
+ ('keywords', keywordMap['keywords'], KeywordAttr.Default),
+ ('types', keywordMap['types'], KeywordAttr.Default),
+ ('class', keywordMap['class'], KeywordAttr.Default),
+ ('enum', keywordMap['enum'], KeywordAttr.Default),
+ ('metadata', keywordMap['metadata'], KeywordAttr.NoLexer),
+ ('function', keywordMap['function'], KeywordAttr.NoLexer),
+ ]
+ return keywordList
+
def parse_gn_api_file(path):
sections = read_api_file(path, '#')
keywordMap = {}
@@ -819,9 +857,9 @@ def parse_rust_api_file(path):
]
return keywordList
-def parse_sql_api_files(path_list):
+def parse_sql_api_files(pathList):
keywordMap = {}
- for path in path_list:
+ for path in pathList:
sections = read_api_file(path, '--')
for key, doc in sections:
items = []
diff --git a/tools/KeywordUpdate.py b/tools/KeywordUpdate.py
index daa6fdcdbc..d1ebebac74 100644
--- a/tools/KeywordUpdate.py
+++ b/tools/KeywordUpdate.py
@@ -5,6 +5,7 @@ def update_all_keyword():
items = [
('NP2LEX_AVS', 'stlAviSynth.c', 'AviSynth.avs', 0, parse_avisynth_api_file),
('NP2LEX_CMAKE', 'stlCMake.c', 'CMake.cmake', 0, parse_cmake_api_file),
+ ('NP2LEX_DART', 'stlDart.c', 'Dart.dart', 0, parse_dart_api_file),
('NP2LEX_GN', 'stlGN.c', 'GN.gn', 0, parse_gn_api_file),
('NP2LEX_GO', 'stlGO.c', 'Go.go', 0, parse_go_api_file),
('NP2LEX_JS', 'stlJavaScript.c', 'JavaScript.js', 1, parse_javascript_api_file),
@@ -33,8 +34,8 @@ def update_all_keyword():
if isinstance(path, str):
keywordList = parse('lang/' + path)
else:
- path_list = ['lang/' + name for name in path]
- keywordList = parse(path_list)
+ pathList = ['lang/' + name for name in path]
+ keywordList = parse(pathList)
if keywordList:
output = '../src/EditLexers/' + output
UpdateKeywordFile(rid, output, keywordList, 16 - count)
diff --git a/tools/lang/Dart.dart b/tools/lang/Dart.dart
new file mode 100644
index 0000000000..cb9a76db14
--- /dev/null
+++ b/tools/lang/Dart.dart
@@ -0,0 +1,145 @@
+// 2.12 https://dart.dev/
+// https://dart.dev/guides/language/language-tour
+// https://dart.dev/guides/language/spec
+// https://github.com/dart-lang/sdk
+
+//! keywords
+// https://dart.dev/guides/language/language-tour#keywords
+abstract as assert async await
+break
+case catch class const continue covariant
+default deferred do
+else enum export extends extension external
+factory false final finally for
+get
+hide
+if implements import in interface is
+late library
+mixin
+native new null
+of on operator
+part
+rethrow return required
+set show static super switch sync
+this throw true try typedef
+var
+while with
+yield
+
+//! types
+// https://dart.dev/guides/language/language-tour#built-in-types
+dynamic void Function
+int double
+bool num
+
+//! libraries
+// https://dart.dev/guides/libraries
+library dart._internal {
+ @Since()
+ class SystemHash
+ @patch
+}
+
+library dart.core {
+ main()
+ @pragma()
+ abstract class BigInt implements Comparable
+ typedef Comparator
+ abstract class Comparable
+ class DateTime implements Comparable
+ class Deprecated
+ @Deprecated()
+ @deprecated
+ @override
+ class Duration implements Comparable
+ class Error
+ abstract class Exception
+ class Expando
+ external bool identical(Object? a, Object? b);
+ external int identityHashCode(Object? object);
+ abstract class Invocation
+ abstract class Iterable
+ abstract class BidirectionalIterator implements Iterator
+ abstract class Iterator
+ abstract class List implements EfficientLengthIterable
+ abstract class Map
+ class MapEntry
+ class Null
+ class Object
+ abstract class Pattern
+ abstract class Match
+ void print(Object? object)
+ abstract class RegExp implements Pattern
+ abstract class RegExpMatch implements Match
+ class RuneIterator implements BidirectionalIterator
+ class Runes extends Iterable
+ abstract class Set extends EfficientLengthIterable
+ abstract class Sink
+ abstract class StackTrace
+ class Stopwatch
+ abstract class String implements Comparable, Pattern
+ class Runes extends Iterable
+ class RuneIterator implements BidirectionalIterator
+ class StringBuffer implements StringSink
+ abstract class StringSink
+ abstract class Symbol
+ abstract class Type
+ abstract class Uri
+ class UriData
+}
+
+library dart.async {
+ abstract class FutureOr
+ abstract class Future
+ abstract class Completer
+ abstract class Stream
+ abstract class Timer
+}
+
+library dart.collection {
+ abstract class HashMap implements Map
+ abstract class HashSet implements Set
+ abstract class IterableMixin implements Iterable
+ abstract class IterableBase extends Iterable
+ class HasNextIterator
+ abstract class LinkedHashMap implements Map
+ abstract class LinkedHashSet implements Set
+ class LinkedList> extends Iterable
+ abstract class LinkedListEntry>
+ abstract class ListBase extends Object with ListMixin
+ abstract class ListMixin implements List
+ abstract class MapBase extends MapMixin
+ abstract class MapMixin implements Map
+ class MapView implements Map
+ abstract class Queue implements EfficientLengthIterable
+ class DoubleLinkedQueueEntry extends _DoubleLink>
+ class DoubleLinkedQueue extends Iterable implements Queue
+ class ListQueue extends ListIterable implements Queue
+ abstract class SetMixin implements Set
+ abstract class SetBase with SetMixin
+ class SplayTreeMap extends _SplayTree>
+ class SplayTreeSet extends _SplayTree>
+}
+
+library dart.io {
+ abstract class IOException implements Exception
+ class OSError implements Exception
+ abstract class Directory implements FileSystemEntity
+ abstract class File implements FileSystemEntity
+ class FileStat
+ abstract class FileSystemEntity
+ class FileSystemEvent
+ class Platform
+ abstract class Process
+ abstract class ServerSocket implements Stream
+ class RawSocketEvent
+ abstract class RawSocket implements Stream
+ abstract class Socket implements Stream, IOSink
+ class SocketException implements IOException
+}
+
+library dart.math {
+ class Point
+ abstract class Random
+ class Rectangle extends _RectangleBase
+}