diff --git a/build/CodeLite/Notepad4.project b/build/CodeLite/Notepad4.project
index 3b01dab4c2..9b520535cf 100644
--- a/build/CodeLite/Notepad4.project
+++ b/build/CodeLite/Notepad4.project
@@ -26,6 +26,7 @@
+
@@ -212,6 +213,7 @@
+
diff --git a/build/VS2017/Notepad4.vcxproj b/build/VS2017/Notepad4.vcxproj
index 345b07c93f..8e8f2d7510 100644
--- a/build/VS2017/Notepad4.vcxproj
+++ b/build/VS2017/Notepad4.vcxproj
@@ -485,6 +485,7 @@
+
@@ -614,6 +615,7 @@
+
diff --git a/build/VS2017/Notepad4.vcxproj.filters b/build/VS2017/Notepad4.vcxproj.filters
index 381b14801d..4b242d4ddb 100644
--- a/build/VS2017/Notepad4.vcxproj.filters
+++ b/build/VS2017/Notepad4.vcxproj.filters
@@ -63,6 +63,9 @@
Scintilla\lexers
+
+ Scintilla\lexers
+
Scintilla\lexers
@@ -450,6 +453,9 @@
Source Files\EditLexers
+
+ Source Files\EditLexers
+
Source Files\EditLexers
diff --git a/doc/FileExt.txt b/doc/FileExt.txt
index d6eee7e6d1..282a2e1c6f 100644
--- a/doc/FileExt.txt
+++ b/doc/FileExt.txt
@@ -223,6 +223,9 @@ blockdiag
diag
+Cangjie Source
+ cj
+
CIL Assembly
il
diff --git a/doc/Notepad4 DarkTheme.ini b/doc/Notepad4 DarkTheme.ini
index 69794891d8..45469b90e2 100644
--- a/doc/Notepad4 DarkTheme.ini
+++ b/doc/Notepad4 DarkTheme.ini
@@ -142,6 +142,11 @@ Operator=fore:#A349A4
Keyword=fore:#00B050
Number=fore:#F84C4C
Operator=fore:#A349A4
+[Cangjie Source]
+Keyword=fore:#00B050
+Type Keyword=fore:#00B050
+Number=fore:#F84C4C
+Operator=fore:#A349A4
[CIL Assembly]
Keyword=fore:#00B050
Type Keyword=fore:#00B050
diff --git a/readme.md b/readme.md
index 9072866095..2ac37eec00 100644
--- a/readme.md
+++ b/readme.md
@@ -50,6 +50,7 @@ Latest development builds (artifacts in Release configuration for each compiler
* Objective-C/C++, [Screenshots](https://github.com/zufuliu/notepad4/wiki/Screenshots#objective-cc)
* [C Standard Library](tools/lang/C.c), up to C2x.
* [C++ STL](tools/lang/CPP.cpp), up to C++20.
+ * [Cangjie (仓颉)](tools/lang/Cangjie.cj), up to June 2024.
* [CSS Style Sheet](tools/lang/CSS.css), up to December 2023 snapshot.
* [SCSS Style Sheet](tools/lang/SCSS.scss), up to Dart Sass 1.50.
* [Less Style Sheet](tools/lang/Less.less), up to Less 4.1.
diff --git a/scintilla/include/SciLexer.h b/scintilla/include/SciLexer.h
index c973f6fcee..f848131598 100644
--- a/scintilla/include/SciLexer.h
+++ b/scintilla/include/SciLexer.h
@@ -98,6 +98,7 @@
#define SCLEX_ZIG 224
#define SCLEX_MATHEMATICA 225
#define SCLEX_WINHEX 226
+#define SCLEX_CANGJIE 227
#define SCLEX_AUTOMATIC 1000
#define SCE_PY_DEFAULT 0
#define SCE_PY_COMMENTLINE 1
@@ -1864,4 +1865,36 @@
#define SCE_WINHEX_KEYWORD 7
#define SCE_WINHEX_TYPE 8
#define SCE_WINHEX_COMMAND 9
+#define SCE_CANGJIE_DEFAULT 0
+#define SCE_CANGJIE_COMMENTLINE 1
+#define SCE_CANGJIE_COMMENTLINEDOC 2
+#define SCE_CANGJIE_COMMENTBLOCK 3
+#define SCE_CANGJIE_COMMENTBLOCKDOC 4
+#define SCE_CANGJIE_TASKMARKER 5
+#define SCE_CANGJIE_NUMBER 6
+#define SCE_CANGJIE_IDENTIFIER 7
+#define SCE_CANGJIE_IDENTIFIER_BT 8
+#define SCE_CANGJIE_MACRO 9
+#define SCE_CANGJIE_VARIABLE 10
+#define SCE_CANGJIE_STRING_SQ 11
+#define SCE_CANGJIE_STRING_DQ 12
+#define SCE_CANGJIE_TRIPLE_STRING_SQ 13
+#define SCE_CANGJIE_TRIPLE_STRING_DQ 14
+#define SCE_CANGJIE_RUNE_SQ 15
+#define SCE_CANGJIE_RUNE_DQ 16
+#define SCE_CANGJIE_RAWSTRING_SQ 17
+#define SCE_CANGJIE_RAWSTRING_DQ 18
+#define SCE_CANGJIE_ESCAPECHAR 19
+#define SCE_CANGJIE_OPERATOR 20
+#define SCE_CANGJIE_OPERATOR2 21
+#define SCE_CANGJIE_WORD 22
+#define SCE_CANGJIE_WORD2 23
+#define SCE_CANGJIE_TYPE 24
+#define SCE_CANGJIE_ANNOTATION 25
+#define SCE_CANGJIE_CLASS 26
+#define SCE_CANGJIE_STRUCT 27
+#define SCE_CANGJIE_INTERFACE 28
+#define SCE_CANGJIE_ENUM 29
+#define SCE_CANGJIE_FUNCTION_DEFINITION 30
+#define SCE_CANGJIE_FUNCTION 31
/* --Autogenerated -- end of section automatically generated from SciLexer.iface */
diff --git a/scintilla/include/SciLexer.iface b/scintilla/include/SciLexer.iface
index 5b41076a60..e00c4ae85a 100644
--- a/scintilla/include/SciLexer.iface
+++ b/scintilla/include/SciLexer.iface
@@ -171,6 +171,7 @@ val SCLEX_CSV=223
val SCLEX_ZIG=224
val SCLEX_MATHEMATICA=225
val SCLEX_WINHEX=226
+val SCLEX_CANGJIE=227
# When a lexer specifies its language as SCLEX_AUTOMATIC it receives a
# value assigned in sequence from SCLEX_AUTOMATIC+1.
@@ -3173,3 +3174,37 @@ val SCE_WINHEX_IDENTIFIER=
val SCE_WINHEX_KEYWORD=
val SCE_WINHEX_TYPE=
val SCE_WINHEX_COMMAND=
+# Lexical states for SCLEX_CANGJIE
+lex Cangjie=SCLEX_CANGJIE SCE_CANGJIE_
+val SCE_CANGJIE_DEFAULT=
+val SCE_CANGJIE_COMMENTLINE=
+val SCE_CANGJIE_COMMENTLINEDOC=
+val SCE_CANGJIE_COMMENTBLOCK=
+val SCE_CANGJIE_COMMENTBLOCKDOC=
+val SCE_CANGJIE_TASKMARKER=
+val SCE_CANGJIE_NUMBER=
+val SCE_CANGJIE_IDENTIFIER=
+val SCE_CANGJIE_IDENTIFIER_BT=
+val SCE_CANGJIE_MACRO=
+val SCE_CANGJIE_VARIABLE=
+val SCE_CANGJIE_STRING_SQ=11
+val SCE_CANGJIE_STRING_DQ=12
+val SCE_CANGJIE_TRIPLE_STRING_SQ=13
+val SCE_CANGJIE_TRIPLE_STRING_DQ=14
+val SCE_CANGJIE_RUNE_SQ=
+val SCE_CANGJIE_RUNE_DQ=
+val SCE_CANGJIE_RAWSTRING_SQ=
+val SCE_CANGJIE_RAWSTRING_DQ=
+val SCE_CANGJIE_ESCAPECHAR=
+val SCE_CANGJIE_OPERATOR=
+val SCE_CANGJIE_OPERATOR2=
+val SCE_CANGJIE_WORD=
+val SCE_CANGJIE_WORD2=
+val SCE_CANGJIE_TYPE=
+val SCE_CANGJIE_ANNOTATION=
+val SCE_CANGJIE_CLASS=
+val SCE_CANGJIE_STRUCT=
+val SCE_CANGJIE_INTERFACE=
+val SCE_CANGJIE_ENUM=
+val SCE_CANGJIE_FUNCTION_DEFINITION=
+val SCE_CANGJIE_FUNCTION=
diff --git a/scintilla/lexers/LexCangjie.cxx b/scintilla/lexers/LexCangjie.cxx
new file mode 100644
index 0000000000..1e3b633acd
--- /dev/null
+++ b/scintilla/lexers/LexCangjie.cxx
@@ -0,0 +1,522 @@
+// This file is part of Notepad4.
+// See License.txt for details about distribution and modification.
+//! Lexer for Cangjie.
+
+#include
+#include
+
+#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 "StringUtils.h"
+#include "LexerModule.h"
+#include "LexerUtils.h"
+
+using namespace Lexilla;
+
+namespace {
+
+struct EscapeSequence {
+ int outerState = SCE_CANGJIE_DEFAULT;
+ int digitsLeft = 0;
+ bool brace = false;
+
+ // highlight any character as escape sequence.
+ bool resetEscapeState(int state, int chNext) noexcept {
+ if (IsEOLChar(chNext)) {
+ return false;
+ }
+ outerState = state;
+ brace = false;
+ digitsLeft = 1;
+ return true;
+ }
+ bool atEscapeEnd(int ch) noexcept {
+ --digitsLeft;
+ return digitsLeft <= 0 || !IsHexDigit(ch);
+ }
+};
+
+enum {
+ CangjieLineStateMaskLineComment = 1, // line comment
+ CangjieLineStateMaskImport = (1 << 1), // import
+};
+
+//KeywordIndex++Autogenerated -- start of section automatically generated
+enum {
+ KeywordIndex_Keyword = 0,
+ KeywordIndex_Type = 1,
+ KeywordIndex_Annotation = 3,
+ KeywordIndex_Class = 4,
+ KeywordIndex_Struct = 5,
+ KeywordIndex_Interface = 6,
+ KeywordIndex_Enumeration = 7,
+};
+//KeywordIndex--Autogenerated -- end of section automatically generated
+
+enum class KeywordType {
+ None = SCE_CANGJIE_DEFAULT,
+ Type = SCE_CANGJIE_TYPE,
+ Class = SCE_CANGJIE_CLASS,
+ Struct = SCE_CANGJIE_STRUCT,
+ Interface = SCE_CANGJIE_INTERFACE,
+ Enum = SCE_CANGJIE_ENUM,
+ Function = SCE_CANGJIE_FUNCTION_DEFINITION,
+};
+
+static_assert(DefaultNestedStateBaseStyle + 1 == SCE_CANGJIE_STRING_SQ);
+static_assert(DefaultNestedStateBaseStyle + 2 == SCE_CANGJIE_STRING_DQ);
+static_assert(DefaultNestedStateBaseStyle + 3 == SCE_CANGJIE_TRIPLE_STRING_SQ);
+static_assert(DefaultNestedStateBaseStyle + 4 == SCE_CANGJIE_TRIPLE_STRING_DQ);
+
+constexpr bool IsSpaceEquiv(int state) noexcept {
+ return state <= SCE_CANGJIE_TASKMARKER;
+}
+
+constexpr bool IsTripleString(int state) noexcept {
+ return state == SCE_CANGJIE_TRIPLE_STRING_SQ || state == SCE_CANGJIE_TRIPLE_STRING_DQ;
+}
+
+constexpr int GetStringQuote(int state) noexcept {
+ if constexpr (SCE_CANGJIE_STRING_SQ & 1) {
+ return (state & 1) ? '\'' : '\"';
+ } else {
+ return (state & 1) ? '\"' : '\'';
+ }
+}
+
+void ColouriseCangjieDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, LexerWordList keywordLists, Accessor &styler) {
+ int lineStateLineType = 0;
+ int commentLevel = 0; // nested block comment level
+
+ KeywordType kwType = KeywordType::None;
+ int chBeforeIdentifier = 0;
+
+ int delimiterCount = 0; // count of '#'
+ std::vector nestedState; // string interpolation "${}"
+
+ int visibleChars = 0;
+ int visibleCharsBefore = 0;
+ int chPrevNonWhite = 0;
+ EscapeSequence escSeq;
+
+ StyleContext sc(startPos, lengthDoc, initStyle, styler);
+ if (sc.currentLine > 0) {
+ int lineState = styler.GetLineState(sc.currentLine - 1);
+ /*
+ 2: lineStateLineType
+ 6: commentLevel
+ 8: delimiterCount
+ 3: nestedState count
+ 3*4: nestedState
+ */
+ commentLevel = (lineState >> 2) & 0x3f;
+ delimiterCount = (lineState >> 8) & 0xff;
+ lineState >>= 16;
+ if (lineState) {
+ UnpackLineState(lineState, nestedState);
+ }
+ }
+
+ while (sc.More()) {
+ switch (sc.state) {
+ case SCE_CANGJIE_OPERATOR:
+ case SCE_CANGJIE_OPERATOR2:
+ sc.SetState(SCE_CANGJIE_DEFAULT);
+ break;
+
+ case SCE_CANGJIE_NUMBER:
+ if (!IsDecimalNumberEx(sc.chPrev, sc.ch, sc.chNext)) {
+ sc.SetState(SCE_CANGJIE_DEFAULT);
+ }
+ break;
+
+ case SCE_CANGJIE_IDENTIFIER:
+ case SCE_CANGJIE_IDENTIFIER_BT:
+ case SCE_CANGJIE_MACRO:
+ case SCE_CANGJIE_VARIABLE:
+ if (!IsIdentifierChar(sc.ch)) {
+ if (sc.state == SCE_CANGJIE_IDENTIFIER_BT) {
+ if (sc.ch == '`') {
+ sc.Forward();
+ }
+ } else if (sc.state != SCE_CANGJIE_VARIABLE) {
+ char s[128];
+ sc.GetCurrent(s, sizeof(s));
+ if (sc.state == SCE_CANGJIE_MACRO) {
+ // TODO: prefer annotation when next line is class definition
+ if (keywordLists[KeywordIndex_Annotation].InList(s + 1)) {
+ sc.ChangeState(SCE_CANGJIE_ANNOTATION);
+ }
+ } else {
+ if (keywordLists[KeywordIndex_Keyword].InList(s)) {
+ sc.ChangeState(SCE_CANGJIE_WORD);
+ if (StrEqualsAny(s, "import")) {
+ if (visibleChars == sc.LengthCurrent()) {
+ lineStateLineType = CangjieLineStateMaskImport;
+ }
+ } else if (StrEqualsAny(s, "class", "extend", "throw", "as", "is")) {
+ if (lineStateLineType != CangjieLineStateMaskImport) {
+ // import as
+ kwType = KeywordType::Class;
+ }
+ } else if (StrEqual(s, "struct")) {
+ kwType = KeywordType::Struct;
+ } else if (StrEqual(s, "interface")) {
+ kwType = KeywordType::Interface;
+ } else if (StrEqual(s, "enum")) {
+ kwType = KeywordType::Enum;
+ } else if (StrEqualsAny(s, "func", "macro")) {
+ kwType = KeywordType::Function;
+ } else if (StrEqual(s, "type")) {
+ kwType = KeywordType::Type; // type alias
+ }
+ if (kwType != KeywordType::None) {
+ const int chNext = sc.GetLineNextChar();
+ if (!IsIdentifierStart(chNext)) {
+ kwType = KeywordType::None;
+ }
+ }
+ } else if (keywordLists[KeywordIndex_Type].InList(s)) {
+ sc.ChangeState(SCE_CANGJIE_WORD2);
+ } else if (keywordLists[KeywordIndex_Class].InList(s)) {
+ sc.ChangeState(SCE_CANGJIE_CLASS);
+ } else if (keywordLists[KeywordIndex_Struct].InList(s)) {
+ sc.ChangeState(SCE_CANGJIE_STRUCT);
+ } else if (keywordLists[KeywordIndex_Interface].InList(s)) {
+ sc.ChangeState(SCE_CANGJIE_INTERFACE);
+ } else if (keywordLists[KeywordIndex_Enumeration].InList(s)) {
+ sc.ChangeState(SCE_CANGJIE_ENUM);
+ }
+ }
+ }
+ if (sc.state == SCE_CANGJIE_IDENTIFIER || sc.state == SCE_CANGJIE_IDENTIFIER_BT) {
+ if (sc.ch != '.') {
+ if (kwType != KeywordType::None) {
+ sc.ChangeState(static_cast(kwType));
+ } else {
+ const int chNext = sc.GetLineNextChar();
+ if (chNext == '(') {
+ sc.ChangeState(SCE_CANGJIE_FUNCTION);
+ } else if ((chBeforeIdentifier == '<' && (chNext == '>' || chNext == '<'))) {
+ // type
+ // type>
+ // type
+ sc.ChangeState(SCE_CANGJIE_CLASS);
+ }
+ }
+ }
+ }
+ if (sc.state != SCE_CANGJIE_WORD && sc.ch != '.') {
+ kwType = KeywordType::None;
+ }
+ sc.SetState(SCE_CANGJIE_DEFAULT);
+ }
+ break;
+
+ case SCE_CANGJIE_COMMENTLINE:
+ case SCE_CANGJIE_COMMENTLINEDOC:
+ if (sc.atLineStart) {
+ sc.SetState(SCE_CANGJIE_DEFAULT);
+ } else {
+ HighlightTaskMarker(sc, visibleChars, visibleCharsBefore, SCE_CANGJIE_TASKMARKER);
+ }
+ break;
+
+ case SCE_CANGJIE_COMMENTBLOCK:
+ case SCE_CANGJIE_COMMENTBLOCKDOC:
+ if (sc.Match('*', '/')) {
+ sc.Forward();
+ --commentLevel;
+ if (commentLevel == 0) {
+ sc.ForwardSetState(SCE_CANGJIE_DEFAULT);
+ }
+ } else if (sc.Match('/', '*')) {
+ sc.Forward();
+ ++commentLevel;
+ } else if (HighlightTaskMarker(sc, visibleChars, visibleCharsBefore, SCE_CANGJIE_TASKMARKER)) {
+ continue;
+ }
+ break;
+
+ case SCE_CANGJIE_RUNE_SQ:
+ case SCE_CANGJIE_RUNE_DQ:
+ case SCE_CANGJIE_STRING_SQ:
+ case SCE_CANGJIE_STRING_DQ:
+ case SCE_CANGJIE_TRIPLE_STRING_SQ:
+ case SCE_CANGJIE_TRIPLE_STRING_DQ:
+ if (sc.atLineStart && !IsTripleString(sc.state)) {
+ sc.SetState(SCE_CANGJIE_DEFAULT);
+ } else if (sc.ch == '\\') {
+ if (escSeq.resetEscapeState(sc.state, sc.chNext)) {
+ sc.SetState(SCE_CANGJIE_ESCAPECHAR);
+ sc.Forward();
+ if (sc.Match('u', '{')) {
+ escSeq.brace = true;
+ escSeq.digitsLeft = 9;
+ sc.Forward();
+ }
+ }
+ } else if (sc.Match('$', '{') && sc.state < SCE_CANGJIE_RUNE_SQ) {
+ nestedState.push_back(sc.state);
+ sc.SetState(SCE_CANGJIE_OPERATOR2);
+ sc.Forward();
+ } else if (sc.ch == GetStringQuote(sc.state) && (!IsTripleString(sc.state) || sc.MatchNext())) {
+ if (IsTripleString(sc.state)) {
+ sc.Advance(2);
+ }
+ sc.ForwardSetState(SCE_CANGJIE_DEFAULT);
+ }
+ break;
+
+ case SCE_CANGJIE_RAWSTRING_SQ:
+ case SCE_CANGJIE_RAWSTRING_DQ:
+ if (sc.chNext == '#' && sc.ch == GetStringQuote(sc.state)) {
+ int count = delimiterCount;
+ do {
+ sc.Forward();
+ --count;
+ } while (count != 0 && sc.ch == '#');
+ if (count == 0) {
+ delimiterCount = 0;
+ sc.ForwardSetState(SCE_CANGJIE_DEFAULT);
+ }
+ }
+ break;
+
+ case SCE_CANGJIE_ESCAPECHAR:
+ if (escSeq.atEscapeEnd(sc.ch)) {
+ if (escSeq.brace && sc.ch == '}') {
+ sc.Forward();
+ }
+ sc.SetState(escSeq.outerState);
+ continue;
+ }
+ break;
+ }
+
+ if (sc.state == SCE_CANGJIE_DEFAULT) {
+ if (sc.ch == '/' && (sc.chNext == '/' || sc.chNext == '*')) {
+ visibleCharsBefore = visibleChars;
+ const int chNext = sc.chNext;
+ sc.SetState((chNext == '/') ? SCE_CANGJIE_COMMENTLINE : SCE_CANGJIE_COMMENTBLOCK);
+ sc.Forward(2);
+ if (sc.ch == chNext && sc.chNext != chNext) {
+ sc.ChangeState((chNext == '/') ? SCE_CANGJIE_COMMENTLINEDOC : SCE_CANGJIE_COMMENTBLOCKDOC);
+ }
+ if (chNext == '/') {
+ if (visibleChars == 0) {
+ lineStateLineType = CangjieLineStateMaskLineComment;
+ }
+ } else {
+ commentLevel = 1;
+ }
+ continue;
+ }
+ if (sc.ch == 'r' && (sc.chNext == '\'' || sc.chNext == '"')) {
+ sc.SetState((sc.chNext == '\'') ? SCE_CANGJIE_RUNE_SQ : SCE_CANGJIE_RUNE_DQ);
+ sc.Forward();
+ } else if (sc.ch == '"') {
+ if (sc.MatchNext('"', '"')) {
+ sc.SetState(SCE_CANGJIE_TRIPLE_STRING_DQ);
+ sc.Advance(2);
+ } else {
+ sc.SetState(SCE_CANGJIE_STRING_DQ);
+ }
+ } else if (sc.ch == '\'') {
+ if (sc.MatchNext('\'', '\'')) {
+ sc.SetState(SCE_CANGJIE_TRIPLE_STRING_SQ);
+ sc.Advance(2);
+ } else {
+ sc.SetState(SCE_CANGJIE_STRING_SQ);
+ }
+ } else if (IsNumberStartEx(sc.chPrev, sc.ch, sc.chNext)) {
+ sc.SetState(SCE_CANGJIE_NUMBER);
+ } else if (sc.ch == '@' && IsIdentifierStart(sc.chNext)) {
+ sc.SetState(SCE_CANGJIE_MACRO);
+ } else if (sc.ch == '$' && IsIdentifierChar(sc.chNext)) {
+ sc.SetState(SCE_CANGJIE_VARIABLE);
+ } else if (IsIdentifierStart(sc.ch) || (sc.ch == '`' && IsIdentifierStart(sc.chNext))) {
+ if (chPrevNonWhite != '.') {
+ chBeforeIdentifier = chPrevNonWhite;
+ }
+ sc.SetState((sc.ch == '`') ? SCE_CANGJIE_IDENTIFIER_BT : SCE_CANGJIE_IDENTIFIER);
+ } else if (sc.ch == '#') {
+ sc.SetState(SCE_CANGJIE_OPERATOR);
+ int count = 1;
+ while (sc.chNext == '#') {
+ ++count;
+ sc.Forward();
+ }
+ if (sc.chNext == '\'' || sc.chNext == '"') {
+ delimiterCount = count;
+ sc.ChangeState((sc.chNext == '\'') ? SCE_CANGJIE_RUNE_SQ : SCE_CANGJIE_RAWSTRING_DQ);
+ sc.Forward();
+ }
+ } else if (IsAGraphic(sc.ch)) {
+ sc.SetState(SCE_CANGJIE_OPERATOR);
+ if (sc.Match('<', ':')) {
+ kwType = KeywordType::Class;
+ }
+ if (!nestedState.empty()) {
+ sc.ChangeState(SCE_CANGJIE_OPERATOR2);
+ if (sc.ch == '{') {
+ nestedState.push_back(SCE_CANGJIE_DEFAULT);
+ } else if (sc.ch == '}') {
+ const int outerState = TakeAndPop(nestedState);
+ sc.ForwardSetState(outerState);
+ continue;
+ }
+ }
+ }
+ }
+
+ if (!isspacechar(sc.ch)) {
+ visibleChars++;
+ if (!IsSpaceEquiv(sc.state)) {
+ chPrevNonWhite = sc.ch;
+ }
+ }
+ if (sc.atLineEnd) {
+ int lineState = (commentLevel << 2) | (delimiterCount << 8) | lineStateLineType;
+ if (!nestedState.empty()) {
+ lineState |= PackLineState(nestedState) << 16;
+ }
+ styler.SetLineState(sc.currentLine, lineState);
+ lineStateLineType = 0;
+ visibleChars = 0;
+ visibleCharsBefore = 0;
+ kwType = KeywordType::None;
+ }
+ sc.Forward();
+ }
+
+ sc.Complete();
+}
+
+struct FoldLineState {
+ int lineComment;
+ int packageImport;
+ constexpr explicit FoldLineState(int lineState) noexcept:
+ lineComment(lineState & CangjieLineStateMaskLineComment),
+ packageImport((lineState >> 1) & 1) {
+ }
+};
+
+void FoldCangjieDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, LexerWordList /*keywordLists*/, Accessor &styler) {
+ const Sci_PositionU endPos = startPos + lengthDoc;
+ Sci_Line 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));
+ const Sci_PositionU bracePos = CheckBraceOnNextLine(styler, lineCurrent - 1, SCE_CANGJIE_OPERATOR, SCE_CANGJIE_TASKMARKER);
+ if (bracePos) {
+ startPos = bracePos + 1; // skip the brace
+ }
+ }
+
+ int levelNext = levelCurrent;
+ FoldLineState foldCurrent(styler.GetLineState(lineCurrent));
+ Sci_PositionU lineStartNext = styler.LineStart(lineCurrent + 1);
+ lineStartNext = sci::min(lineStartNext, endPos);
+
+ char chNext = styler[startPos];
+ int styleNext = styler.StyleAt(startPos);
+ int style = initStyle;
+ int visibleChars = 0;
+
+ while (startPos < endPos) {
+ const char ch = chNext;
+ const int stylePrev = style;
+ style = styleNext;
+ chNext = styler[++startPos];
+ styleNext = styler.StyleAt(startPos);
+
+ switch (style) {
+ case SCE_CANGJIE_COMMENTBLOCKDOC:
+ case SCE_CANGJIE_COMMENTBLOCK: {
+ const int level = (ch == '/' && chNext == '*') ? 1 : ((ch == '*' && chNext == '/') ? -1 : 0);
+ if (level != 0) {
+ levelNext += level;
+ startPos++;
+ chNext = styler[startPos];
+ styleNext = styler.StyleAt(startPos);
+ }
+ } break;
+
+ case SCE_CANGJIE_TRIPLE_STRING_SQ:
+ case SCE_CANGJIE_TRIPLE_STRING_DQ:
+ case SCE_CANGJIE_RAWSTRING_SQ:
+ case SCE_CANGJIE_RAWSTRING_DQ:
+ if (style != stylePrev) {
+ levelNext++;
+ }
+ if (style != styleNext) {
+ levelNext--;
+ }
+ break;
+
+ case SCE_CANGJIE_OPERATOR:
+ case SCE_CANGJIE_OPERATOR2:
+ if (ch == '{' || ch == '[' || ch == '(') {
+ levelNext++;
+ } else if (ch == '}' || ch == ']' || ch == ')') {
+ levelNext--;
+ }
+ break;
+ }
+
+ if (visibleChars == 0 && !IsSpaceEquiv(style)) {
+ ++visibleChars;
+ }
+ if (startPos == lineStartNext) {
+ const FoldLineState foldNext(styler.GetLineState(lineCurrent + 1));
+ levelNext = sci::max(levelNext, SC_FOLDLEVELBASE);
+ if (foldCurrent.lineComment) {
+ levelNext += foldNext.lineComment - foldPrev.lineComment;
+ } else if (foldCurrent.packageImport) {
+ levelNext += foldNext.packageImport - foldPrev.packageImport;
+ } else if (visibleChars) {
+ const Sci_PositionU bracePos = CheckBraceOnNextLine(styler, lineCurrent, SCE_CANGJIE_OPERATOR, SCE_CANGJIE_TASKMARKER);
+ if (bracePos) {
+ levelNext++;
+ startPos = bracePos + 1; // skip the brace
+ style = SCE_CANGJIE_OPERATOR;
+ chNext = styler[startPos];
+ styleNext = styler.StyleAt(startPos);
+ }
+ }
+
+ const int levelUse = levelCurrent;
+ int lev = levelUse | (levelNext << 16);
+ if (levelUse < levelNext) {
+ lev |= SC_FOLDLEVELHEADERFLAG;
+ }
+ styler.SetLevel(lineCurrent, lev);
+
+ lineCurrent++;
+ lineStartNext = styler.LineStart(lineCurrent + 1);
+ lineStartNext = sci::min(lineStartNext, endPos);
+ levelCurrent = levelNext;
+ foldPrev = foldCurrent;
+ foldCurrent = foldNext;
+ visibleChars = 0;
+ }
+ }
+}
+
+}
+
+LexerModule lmCangjie(SCLEX_CANGJIE, ColouriseCangjieDoc, "cj", FoldCangjieDoc);
diff --git a/scintilla/lexers/LexSwift.cxx b/scintilla/lexers/LexSwift.cxx
index 2b61ff553f..7989d1c87b 100644
--- a/scintilla/lexers/LexSwift.cxx
+++ b/scintilla/lexers/LexSwift.cxx
@@ -399,12 +399,8 @@ void ColouriseSwiftDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initS
}
} else if (IsNumberStartEx(sc.chPrev, sc.ch, sc.chNext)) {
sc.SetState(SCE_SWIFT_NUMBER);
- } else if ((sc.ch == '@' || sc.ch == '`') && IsIdentifierStartEx(sc.chNext)) {
- chBefore = chPrevNonWhite;
- if (chPrevNonWhite != '.') {
- chBeforeIdentifier = chPrevNonWhite;
- }
- sc.SetState((sc.ch == '@') ? SCE_SWIFT_ATTRIBUTE : SCE_SWIFT_IDENTIFIER_BT);
+ } else if (sc.ch == '@' && IsIdentifierStartEx(sc.chNext)) {
+ sc.SetState(SCE_SWIFT_ATTRIBUTE);
} else if (sc.ch == '$' && IsIdentifierCharEx(sc.chNext)) {
sc.SetState(SCE_SWIFT_VARIABLE);
} else if (sc.ch == '#') {
@@ -425,12 +421,12 @@ void ColouriseSwiftDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initS
}
}
}
- } else if (IsIdentifierStartEx(sc.ch)) {
+ } else if (IsIdentifierStartEx(sc.ch) || (sc.ch == '`' && IsIdentifierStartEx(sc.chNext))) {
chBefore = chPrevNonWhite;
if (chPrevNonWhite != '.') {
chBeforeIdentifier = chPrevNonWhite;
}
- sc.SetState(SCE_SWIFT_IDENTIFIER);
+ sc.SetState((sc.ch == '`') ? SCE_SWIFT_IDENTIFIER_BT : SCE_SWIFT_IDENTIFIER);
} else if (sc.ch == '+' || sc.ch == '-') {
if (sc.ch == sc.chNext) {
// highlight ++ and -- as different style to simplify regex detection.
diff --git a/scintilla/lexlib/LexerModule.cxx b/scintilla/lexlib/LexerModule.cxx
index d1c4e91428..8e068e27b2 100644
--- a/scintilla/lexlib/LexerModule.cxx
+++ b/scintilla/lexlib/LexerModule.cxx
@@ -37,6 +37,7 @@ extern LexerModule lmAviSynth;
extern LexerModule lmAwk;
extern LexerModule lmBash;
extern LexerModule lmBatch;
+extern LexerModule lmCangjie;
extern LexerModule lmCIL;
extern LexerModule lmCMake;
extern LexerModule lmCoffeeScript;
@@ -121,6 +122,7 @@ const LexerModule * const lexerCatalogue[] = {
&lmAwk,
&lmBash,
&lmBatch,
+ &lmCangjie,
&lmCIL,
&lmCMake,
&lmCoffeeScript,
diff --git a/src/EditAutoC.cpp b/src/EditAutoC.cpp
index fe0d391db2..44a3ace823 100644
--- a/src/EditAutoC.cpp
+++ b/src/EditAutoC.cpp
@@ -671,6 +671,8 @@ enum {
CSSKeywordIndex_PseudoElement = 3,
CSharpKeywordIndex_Preprocessor = 3,
CSharpKeywordIndex_CommentTag = 10,
+ CangjieKeywordIndex_Macro = 2,
+ CangjieKeywordIndex_Annotation = 3,
DKeywordIndex_Preprocessor = 2,
DKeywordIndex_Attribute = 3,
DartKeywordIndex_Metadata = 4,
@@ -1105,6 +1107,14 @@ static AddWordResult AutoC_AddSpecWord(WordList &pWList, int iCurrentStyle, int
}
break;
+ case NP2LEX_CANGJIE:
+ if (ch == '@' && iCurrentStyle == SCE_CANGJIE_DEFAULT) {
+ pWList.AddList(pLex->pKeyWords->pszKeyWords[CangjieKeywordIndex_Macro]);
+ pWList.AddList(pLex->pKeyWords->pszKeyWords[CangjieKeywordIndex_Annotation]);
+ return AddWordResult_IgnoreLexer;
+ }
+ break;
+
case NP2LEX_CSS:
if (ch == '@' && iCurrentStyle == SCE_CSS_DEFAULT) {
pWList.AddList(pLex->pKeyWords->pszKeyWords[CSSKeywordIndex_AtRule]);
@@ -1378,7 +1388,7 @@ static AddWordResult AutoC_AddSpecWord(WordList &pWList, int iCurrentStyle, int
break;
case NP2LEX_SAS:
- if (ch == '%') {
+ if (ch == '%' && iCurrentStyle == SCE_SAS_DEFAULT) {
pWList.AddList(pLex->pKeyWords->pszKeyWords[SASKeywordIndex_Macro]);
return AddWordResult_IgnoreLexer;
}
@@ -2460,6 +2470,7 @@ void EditToggleCommentLine(bool alternative) noexcept {
case NP2LEX_ACTIONSCRIPT:
case NP2LEX_ASYMPTOTE:
case NP2LEX_BLOCKDIAG:
+ case NP2LEX_CANGJIE:
case NP2LEX_CIL:
case NP2LEX_CPP:
case NP2LEX_CSHARP:
@@ -2723,6 +2734,7 @@ void EditToggleCommentBlock(bool alternative) noexcept {
case NP2LEX_ASYMPTOTE:
case NP2LEX_AUTOHOTKEY:
case NP2LEX_AVISYNTH:
+ case NP2LEX_CANGJIE:
case NP2LEX_CIL:
case NP2LEX_CPP:
case NP2LEX_CSHARP:
@@ -2991,6 +3003,17 @@ void InitAutoCompletionCache(LPCEDITLEXER pLex) noexcept {
RawStringStyleMask[SCE_SH_STRING_SQ >> 5] |= (1U << (SCE_SH_STRING_SQ & 31));
break;
+ case NP2LEX_CANGJIE:
+ CharacterPrefixMask['r' >> 5] |= (1 << ('r' & 31));
+ RawStringStyleMask[SCE_CANGJIE_RAWSTRING_SQ >> 5] |= (1U << (SCE_CANGJIE_RAWSTRING_SQ & 31));
+ RawStringStyleMask[SCE_CANGJIE_RAWSTRING_DQ >> 5] |= (1U << (SCE_CANGJIE_RAWSTRING_DQ & 31));
+ GenericTypeStyleMask[SCE_CANGJIE_CLASS >> 5] |= (1U << (SCE_CANGJIE_CLASS & 31));
+ GenericTypeStyleMask[SCE_CANGJIE_INTERFACE >> 5] |= (1U << (SCE_CANGJIE_INTERFACE & 31));
+ GenericTypeStyleMask[SCE_CANGJIE_STRUCT >> 5] |= (1U << (SCE_CANGJIE_STRUCT & 31));
+ GenericTypeStyleMask[SCE_CANGJIE_ENUM >> 5] |= (1U << (SCE_CANGJIE_ENUM & 31));
+ GenericTypeStyleMask[SCE_CANGJIE_WORD2 >> 5] |= (1U << (SCE_CANGJIE_WORD2 & 31));
+ break;
+
case NP2LEX_CPP:
CurrentWordCharSet[':' >> 5] |= (1 << (':' & 31));
CharacterPrefixMask['L' >> 5] |= (1 << ('L' & 31));
diff --git a/src/EditLexer.h b/src/EditLexer.h
index 47a711878b..d20b93b4bd 100644
--- a/src/EditLexer.h
+++ b/src/EditLexer.h
@@ -205,7 +205,7 @@ using LPCEDITLEXER = const EDITLEXER *;
#define NP2LEX_ZIG 63082 // SCLEX_ZIG Zig Source
#define NP2LEX_OCAML 63083 // SCLEX_OCAML OCaml Source
#define NP2LEX_HASKELL 63084 // SCLEX_HASKELL Haskell Source
-
+#define NP2LEX_CANGJIE 63085 // SCLEX_CANGJIE Cangjie Source
#define NP2LEX_WINHEX 63086 // SCLEX_WINHEX WinHex Script
#define NP2LEX_AVISYNTH 63087 // SCLEX_AVISYNTH AviSynth Script
#define NP2LEX_TEKEXTHEX 63088 // SCLEX_TEKEXTHEX Tektronix extended HEX
diff --git a/src/EditLexers/stlCangjie.cpp b/src/EditLexers/stlCangjie.cpp
new file mode 100644
index 0000000000..ddaf54b0b5
--- /dev/null
+++ b/src/EditLexers/stlCangjie.cpp
@@ -0,0 +1,95 @@
+#include "EditLexer.h"
+#include "EditStyleX.h"
+
+static KEYWORDLIST Keywords_Cangjie = {{
+//++Autogenerated -- start of section automatically generated
+"abstract as break case catch class const continue do else enum extend false finally for foreign func "
+"if import in init interface is let macro main match mut open operator override package private prop protected public "
+"quote redef return spawn static struct super synchronized this throw true try type unsafe var where while "
+
+, // 1 types
+"Bool Byte CPointer CString Float16 Float32 Float64 Int Int16 Int32 Int64 Int8 IntNative Nothing Rune This "
+"UInt UInt16 UInt32 UInt64 UInt8 UIntNative Unit VArray "
+
+, // 2 macro
+"C CallingConv FastNative Intrinsic When sourceFile( sourceLine( sourcePackage( "
+
+, // 3 annotation
+"Annotation "
+
+, // 4 class
+"ArrayIterator ArrayList Box BufferedInputStream BufferedOutputStream ByteArrayStream Directory Error Exception "
+"File Future HashMap HashSet IOException Iterator LinkedList Object RangeIterator "
+"StringBuilder StringReader StringWriter Thread ThreadLocal TreeMap "
+
+, // 5 struct
+"Array CPointerHandle CPointerResource CStringResource DefaultHasher FileDescriptor FileInfo Path Range String "
+
+, // 6 interface
+"Any CType Collection Comparable Countable Equal Equatable Hashable Hasher IOStream InputStream Iterable Map "
+"OutputStream Resource Seekable Set ThreadContext ToString "
+
+, // 7 enumeration
+"Endian OpenOption Option Ordering SeekPosition "
+
+, // 8 function
+"alignOf( all( any( eprint( eprintln( ifNone( ifSome( init( main( print( println( refEq( sizeOf( zeroValue( "
+
+, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
+//--Autogenerated -- end of section automatically generated
+}};
+
+static EDITSTYLE Styles_Cangjie[] = {
+ EDITSTYLE_DEFAULT,
+ { SCE_CANGJIE_WORD, NP2StyleX_Keyword, L"fore:#0000FF" },
+ { SCE_CANGJIE_WORD2, NP2StyleX_TypeKeyword, L"fore:#0000FF" },
+ { SCE_CANGJIE_MACRO, NP2StyleX_Macro, L"fore:#FF8000" },
+ { SCE_CANGJIE_TYPE, NP2StyleX_Type, L"fore:#007F7F" },
+ { SCE_CANGJIE_ANNOTATION, NP2StyleX_Annotation, L"fore:#FF8000" },
+ { SCE_CANGJIE_CLASS, NP2StyleX_Class, L"fore:#0080FF" },
+ { SCE_CANGJIE_STRUCT, NP2StyleX_Structure, L"fore:#0080FF" },
+ { SCE_CANGJIE_INTERFACE, NP2StyleX_Interface, L"bold; fore:#1E90FF" },
+ { SCE_CANGJIE_ENUM, NP2StyleX_Enumeration, L"fore:#FF8000" },
+ { SCE_CANGJIE_FUNCTION_DEFINITION, NP2StyleX_FunctionDefinition, L"bold; fore:#A46000" },
+ { SCE_CANGJIE_FUNCTION, NP2StyleX_Function, L"fore:#A46000" },
+ { MULTI_STYLE(SCE_CANGJIE_COMMENTBLOCK, SCE_CANGJIE_COMMENTLINE, 0, 0), NP2StyleX_Comment, L"fore:#608060" },
+ { MULTI_STYLE(SCE_CANGJIE_COMMENTBLOCKDOC, SCE_CANGJIE_COMMENTLINEDOC, 0, 0), NP2StyleX_DocComment, L"fore:#408040" },
+ { SCE_CANGJIE_TASKMARKER, NP2StyleX_TaskMarker, L"bold; fore:#408080" },
+ { MULTI_STYLE(SCE_CANGJIE_STRING_SQ, SCE_CANGJIE_STRING_DQ, SCE_CANGJIE_RUNE_SQ, SCE_CANGJIE_RUNE_DQ), NP2StyleX_String, L"fore:#008000" },
+ { MULTI_STYLE(SCE_CANGJIE_TRIPLE_STRING_SQ, SCE_CANGJIE_TRIPLE_STRING_DQ, 0, 0), NP2StyleX_TripleQuotedString, L"fore:#F08000" },
+ { MULTI_STYLE(SCE_CANGJIE_RAWSTRING_SQ, SCE_CANGJIE_RAWSTRING_DQ, 0, 0), NP2StyleX_RawString, L"fore:#F08000" },
+ { SCE_CANGJIE_ESCAPECHAR, NP2StyleX_EscapeSequence, L"fore:#0080C0" },
+ { SCE_CANGJIE_VARIABLE, NP2StyleX_Variable, L"fore:#9E4D2A" },
+ { SCE_CANGJIE_NUMBER, NP2StyleX_Number, L"fore:#FF0000" },
+ { MULTI_STYLE(SCE_CANGJIE_OPERATOR, SCE_CANGJIE_OPERATOR2, 0, 0), NP2StyleX_Operator, L"fore:#B000B0" },
+};
+
+EDITLEXER lexCangjie = {
+ SCLEX_CANGJIE, NP2LEX_CANGJIE,
+//Settings++Autogenerated -- start of section automatically generated
+ LexerAttr_AngleBracketGeneric |
+ LexerAttr_CharacterPrefix,
+ TAB_WIDTH_4, INDENT_WIDTH_4,
+ (1 << 0) | (1 << 1), // class, function
+ SCE_CANGJIE_FUNCTION_DEFINITION,
+ '\\', SCE_CANGJIE_ESCAPECHAR, 0,
+ 0,
+ SCE_CANGJIE_RUNE_SQ, 0,
+ SCE_CANGJIE_OPERATOR, SCE_CANGJIE_OPERATOR2
+ , KeywordAttr32(0, KeywordAttr_PreSorted) // keywords
+ | KeywordAttr32(1, KeywordAttr_PreSorted) // types
+ | KeywordAttr32(2, KeywordAttr_NoLexer | KeywordAttr_NoAutoComp) // macro
+ | KeywordAttr32(3, KeywordAttr_PreSorted | KeywordAttr_NoAutoComp) // annotation
+ | KeywordAttr32(4, KeywordAttr_PreSorted) // class
+ | KeywordAttr32(5, KeywordAttr_PreSorted) // struct
+ | KeywordAttr32(6, KeywordAttr_PreSorted) // interface
+ | KeywordAttr64(7, KeywordAttr_PreSorted) // enumeration
+ | KeywordAttr64(8, KeywordAttr_NoLexer) // function
+ , SCE_CANGJIE_TASKMARKER,
+ SCE_CANGJIE_STRING_SQ, SCE_CANGJIE_ESCAPECHAR,
+//Settings--Autogenerated -- end of section automatically generated
+ EDITLEXER_HOLE(L"Cangjie Source", Styles_Cangjie),
+ L"cj",
+ &Keywords_Cangjie,
+ Styles_Cangjie
+};
diff --git a/src/Styles.cpp b/src/Styles.cpp
index 4fac6eec83..9aabe798e8 100644
--- a/src/Styles.cpp
+++ b/src/Styles.cpp
@@ -73,6 +73,7 @@ extern EDITLEXER lexAwk;
extern EDITLEXER lexBatch;
extern EDITLEXER lexBlockdiag;
+extern EDITLEXER lexCangjie;
extern EDITLEXER lexCIL;
extern EDITLEXER lexCMake;
extern EDITLEXER lexCoffeeScript;
@@ -186,6 +187,7 @@ static PEDITLEXER pLexArray[] = {
&lexBatch,
&lexBlockdiag,
+ &lexCangjie,
&lexCIL,
&lexCMake,
&lexCoffeeScript,
diff --git a/tools/KeywordCore.py b/tools/KeywordCore.py
index 76e06e641e..c054c6779d 100644
--- a/tools/KeywordCore.py
+++ b/tools/KeywordCore.py
@@ -562,6 +562,45 @@ def parse_batch_api_file(path):
('command options', keywordMap['options'], KeywordAttr.NoLexer),
]
+def parse_cangjie_api_file(path):
+ sections = read_api_file(path, '//')
+ keywordMap = {
+ 'function': ['main()', 'init()']
+ }
+ for key, doc in sections:
+ if key in ('keywords', 'types'):
+ keywordMap[key] = doc.split()
+ elif key in ('macro', 'annotation'):
+ keywordMap[key] = re.findall(r'@(\w+\(?)', doc)
+ elif key == 'api':
+ keywordMap['class'] = re.findall(r'class\s+(\w+)', doc)
+ keywordMap['struct'] = re.findall(r'struct\s+(\w+)', doc)
+ keywordMap['interface'] = re.findall(r'interface\s+(\w+)', doc)
+ keywordMap['enumeration'] = re.findall(r'enum\s+(\w+)', doc)
+ items = re.findall(r'func\s+(\w+)', doc)
+ keywordMap['function'].extend(item + '()' for item in items)
+
+ RemoveDuplicateKeyword(keywordMap, [
+ 'keywords',
+ 'types',
+ 'class',
+ 'struct',
+ 'interface',
+ 'enumeration',
+ ])
+
+ return [
+ ('keywords', keywordMap['keywords'], KeywordAttr.Default),
+ ('types', keywordMap['types'], KeywordAttr.Default),
+ ('macro', keywordMap['macro'], KeywordAttr.NoLexer | KeywordAttr.Special | KeywordAttr.NoAutoComp),
+ ('annotation', keywordMap['annotation'], KeywordAttr.Special | KeywordAttr.NoAutoComp),
+ ('class', keywordMap['class'], KeywordAttr.Default),
+ ('struct', keywordMap['struct'], KeywordAttr.Default),
+ ('interface', keywordMap['interface'], KeywordAttr.Default),
+ ('enumeration', keywordMap['enumeration'], KeywordAttr.Default),
+ ('function', keywordMap['function'], KeywordAttr.NoLexer),
+ ]
+
def parse_coffeescript_api_file(path):
sections = read_api_file(path, '#')
keywordMap = {}
diff --git a/tools/KeywordUpdate.py b/tools/KeywordUpdate.py
index eb0ea427ed..f605145ade 100644
--- a/tools/KeywordUpdate.py
+++ b/tools/KeywordUpdate.py
@@ -18,6 +18,7 @@
('NP2LEX_BASH', 'stlBash.cpp', 'LexBash.cxx', ['Bash.sh', 'CShell.csh'], 0, parse_bash_api_file),
('NP2LEX_BATCH', 'stlBatch.cpp', 'LexBatch.cxx', 'Batch.bat', 0, parse_batch_api_file),
+ ('NP2LEX_CANGJIE', 'stlCangjie.cpp', 'LexCangjie.cxx', 'Cangjie.cj', 0, parse_cangjie_api_file),
('NP2LEX_CIL', 'stlCIL.cpp', 'LexCIL.cxx', '', 0, None),
('NP2LEX_CMAKE', 'stlCMake.cpp', 'LexCMake.cxx', 'CMake.cmake', 0, parse_cmake_api_file),
('NP2LEX_CONFIG', 'stlDefault.cpp', 'LexConfig.cxx', '', (0, 'Config'), None),
diff --git a/tools/LexerConfig.py b/tools/LexerConfig.py
index 14a82d54ba..556f4c786b 100644
--- a/tools/LexerConfig.py
+++ b/tools/LexerConfig.py
@@ -254,6 +254,20 @@ class KeywordAttr(IntFlag):
'string_style_range': ['SCE_GRAPHVIZ_STRING', 'SCE_GRAPHVIZ_ESCAPECHAR'],
},
+ 'NP2LEX_CANGJIE': {
+ 'cpp_style_comment': True,
+ 'comment_style_marker': 'SCE_CANGJIE_TASKMARKER',
+ 'default_fold_level': ['class', 'function'],
+ 'default_fold_ignore_inner': 'SCE_CANGJIE_FUNCTION_DEFINITION',
+ 'escape_char_style': 'SCE_CANGJIE_ESCAPECHAR',
+ 'raw_string_style': ['SCE_CANGJIE_RAWSTRING_SQ', 'SCE_CANGJIE_RAWSTRING_DQ'],
+ 'character_style': ['SCE_CANGJIE_RUNE_SQ', 'SCE_CANGJIE_RUNE_DQ'],
+ 'character_prefix': ['r'],
+ 'angle_bracket_generic': True,
+ 'generic_type_style': ['SCE_CANGJIE_CLASS', 'SCE_CANGJIE_INTERFACE', 'SCE_CANGJIE_STRUCT', 'SCE_CANGJIE_ENUM', 'SCE_CANGJIE_WORD2'],
+ 'operator_style': ['SCE_CANGJIE_OPERATOR', 'SCE_CANGJIE_OPERATOR2'],
+ 'string_style_range': ['SCE_CANGJIE_STRING_SQ', 'SCE_CANGJIE_ESCAPECHAR'],
+ },
'NP2LEX_CIL': {
'cpp_style_comment': True,
'comment_style_marker': 'SCE_CIL_COMMENTBLOCK',
diff --git a/tools/lang/Cangjie.cj b/tools/lang/Cangjie.cj
new file mode 100644
index 0000000000..d727744e37
--- /dev/null
+++ b/tools/lang/Cangjie.cj
@@ -0,0 +1,140 @@
+// 2024-06-21 https://developer.huawei.com/consumer/cn/cangjie
+
+//! keywords ===========================================================
+// https://developer.huawei.com/consumer/cn/doc/openharmony-cangjie/keyword
+abstract as
+break
+case catch class const continue
+do
+else enum extend
+false finally for foreign func
+if import in init interface is
+let
+macro main match mut
+open operator override
+package private prop protected public
+quote
+redef return
+spawn static struct super synchronized
+this throw true try type
+unsafe
+var
+where while
+
+//! types ===========================================================
+Nothing This VArray
+// std.core types
+Byte Int UInt
+Int8 Int16 Int32 Int64 IntNative
+UInt8 UInt16 UInt32 UInt64 UIntNative
+Float16 Float32 Float64
+Bool Rune Unit
+CPointer CString
+
+//! macro ===========================================================
+@sourcePackage()
+@sourceFile()
+@sourceLine()
+@Intrinsic
+@FastNative
+@When
+
+@C
+@CallingConv
+
+//! annotation ===========================================================
+@Annotation
+
+//! api ===========================================================
+package std.core {
+ func alignOf(): UIntNative where T <: CType
+ func eprint(str: String, flush!: Bool = true): Unit
+ func eprintln(str: String): Unit
+ func ifNone(o: Option, action: () -> Unit): Unit
+ func ifSome(o: Option, action: (T) -> Unit): Unit
+ func print(arg: T, flush!: Bool = false): Unit where T <: ToString
+ func println(arg: T): Unit where T <: ToString
+ func refEq(a: Object, b: Object): Bool
+ func sizeOf(): UIntNative where T <: CType
+ func zeroValue(): T
+
+ interface Any
+ interface CType
+ interface Collection <: Iterable
+ interface Comparable <: Equatable & Less & Greater & LessOrEqual & GreaterOrEqual
+ interface Countable
+ interface Equal
+ interface Equatable
+ interface Hashable
+ interface Hasher
+ interface Iterable
+ interface Resource
+ interface ThreadContext
+ interface ToString
+
+ class ArrayIterator <: Iterator
+ class Box
+ class Future
+ abstract class Iterator <: Iterable
+ open class Object <: Any
+ class RangeIterator <: Iterator where T <: Countable & Comparable & Equatable
+ class StringBuilder <: ToString
+ class Thread
+ class ThreadLocal
+
+ enum Endian
+ enum Option
+ enum Ordering
+
+ struct Array
+ struct CPointerHandle where T <: CType
+ struct CPointerResource <: Resource where T <: CType
+ struct CStringResource <: Resource
+ struct DefaultHasher <: Hasher
+ struct Range <: Iterable where T <: Countable & Comparable & Equatable
+ struct String <: Collection & Equatable & Comparable & Hashable & ToString
+
+ open class Error <: ToString
+ open class Exception <: ToString
+}
+
+package std.collection {
+ func all(predicate: (T) -> Bool): (Iterable) -> Bool
+ func any(predicate: (T) -> Bool): (Iterable) -> Bool
+
+ interface Map <: Collection<(K, V)> where K <: Equatable
+ interface Set <: Collection where T <: Equatable
+
+ class ArrayList <: Collection
+ class HashMap <: Map where K <: Hashable & Equatable
+ class HashSet <: Set where T <: Hashable & Equatable
+ class LinkedList <: Collection
+ class TreeMap <: Map where K <: Comparable
+}
+
+package std.fs {
+ class Directory <: Iterable
+ class File <: Resource & IOStream & Seekable
+
+ enum OpenOption
+
+ struct FileDescriptor
+ struct FileInfo <: Equatable
+ struct Path <: Equatable & Hashable & ToString
+}
+
+package std.io {
+ interface IOStream <: InputStream & OutputStream
+ interface InputStream
+ interface OutputStream
+ interface Seekable
+
+ class BufferedInputStream <: InputStream where T <: InputStream
+ class BufferedOutputStream <: OutputStream where T <: OutputStream
+ class ByteArrayStream <: IOStream & Seekable
+ class StringReader where T <: InputStream
+ class StringWriter where T <: OutputStream
+
+ enum SeekPosition
+ class IOException <: Exception
+}
diff --git a/tools/lang/SAS.sas b/tools/lang/SAS.sas
index 8527bdea68..60854a7a11 100644
--- a/tools/lang/SAS.sas
+++ b/tools/lang/SAS.sas
@@ -2,7 +2,7 @@
/* SAS Viya 2024.06 https://go.documentation.sas.com/doc/en/pgmsascdc/v_052/pgmsaswlcm/home.htm */
/* SAS 9.4 / Viya 3.5 https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/pgmsashome/home.htm */
-/*! keywords =============================================================== */
+/*! keywords ======================================================== */
/* Operators */
/* https://go.documentation.sas.com/doc/en/pgmsascdc/v_052/lepg/titlepage.htm */
eq ne gt lt ge le in
@@ -110,7 +110,7 @@ update where
validate
where
-/*! macro ================================================================== */
+/*! macro ======================================================== */
/* Macro Language */
/* https://go.documentation.sas.com/doc/en/pgmsascdc/v_052/mcrolref/titlepage.htm */
%include
@@ -189,7 +189,7 @@ where
%ds2csv(argument-1=value-1, argument-2=value-2 <,argument-3=value-3 ...>)
%tslit(literal text)
-/*! functions ============================================================== */
+/*! functions ======================================================== */
/* Functions and CALL Routines */
/* https://go.documentation.sas.com/doc/en/pgmsascdc/v_052/lefunctionsref/titlepage.htm */
abs()