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 +}