mirror of
https://github.com/rizonesoft/Notepad3.git
synced 2026-06-11 21:03:05 +08:00
+fix: notification adjustment in case of externally deleted file
+rfc: minor refactorings
This commit is contained in:
parent
210aa34803
commit
1e89129af8
@ -111,10 +111,10 @@ struct OptionsJSON {
|
||||
bool allowComments;
|
||||
bool escapeSequence;
|
||||
OptionsJSON() {
|
||||
foldCompact = true;
|
||||
fold = true;
|
||||
allowComments = true;
|
||||
escapeSequence = true;
|
||||
foldCompact = false;
|
||||
fold = false;
|
||||
allowComments = false;
|
||||
escapeSequence = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -236,13 +236,13 @@ constexpr bool IsAssignChar(const int ch) noexcept
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
inline bool IsAIdentifierChar(const int ch)
|
||||
constexpr bool IsAIdentifierChar(const int ch) noexcept
|
||||
{
|
||||
return (IsAlphaNumeric(ch) || ch == '_' || ch == '.');
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
inline bool IsAKeywordChar(const int ch)
|
||||
constexpr bool IsAKeywordChar(const int ch) noexcept
|
||||
{
|
||||
return (IsAIdentifierChar(ch) || ch == '+' || ch == '-');
|
||||
}
|
||||
|
||||
554
lexilla/lexers_x/orig/zufuliu/LexDart.cxx
Normal file
554
lexilla/lexers_x/orig/zufuliu/LexDart.cxx
Normal file
@ -0,0 +1,554 @@
|
||||
// This file is part of Notepad2.
|
||||
// See License.txt for details about distribution and modification.
|
||||
//! Lexer for Dart.
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#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_DART_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 = (chNext == 'x')? 3 : ((chNext == 'u') ? 5 : 1);
|
||||
return true;
|
||||
}
|
||||
bool atEscapeEnd(int ch) noexcept {
|
||||
--digitsLeft;
|
||||
return digitsLeft <= 0 || !IsHexDigit(ch);
|
||||
}
|
||||
};
|
||||
|
||||
enum {
|
||||
DartLineStateMaskLineComment = 1, // line comment
|
||||
DartLineStateMaskImport = (1 << 1), // import
|
||||
};
|
||||
|
||||
//KeywordIndex++Autogenerated -- start of section automatically generated
|
||||
enum {
|
||||
KeywordIndex_Keyword = 0,
|
||||
KeywordIndex_Type = 1,
|
||||
KeywordIndex_Class = 2,
|
||||
KeywordIndex_Enumeration = 3,
|
||||
};
|
||||
//KeywordIndex--Autogenerated -- end of section automatically generated
|
||||
|
||||
enum class KeywordType {
|
||||
None = SCE_DART_DEFAULT,
|
||||
Class = SCE_DART_CLASS,
|
||||
Enum = SCE_DART_ENUM,
|
||||
Label = SCE_DART_LABEL,
|
||||
Return = 0x40,
|
||||
While,
|
||||
};
|
||||
|
||||
static_assert(DefaultNestedStateBaseStyle + 1 == SCE_DART_STRING_SQ);
|
||||
static_assert(DefaultNestedStateBaseStyle + 2 == SCE_DART_STRING_DQ);
|
||||
static_assert(DefaultNestedStateBaseStyle + 3 == SCE_DART_TRIPLE_STRING_SQ);
|
||||
static_assert(DefaultNestedStateBaseStyle + 4 == SCE_DART_TRIPLE_STRING_DQ);
|
||||
|
||||
constexpr bool IsDeclarableOperator(int ch) noexcept {
|
||||
// https://github.com/dart-lang/sdk/blob/main/sdk/lib/core/symbol.dart
|
||||
return AnyOf(ch, '+', '-', '*', '/', '%', '~', '&', '|',
|
||||
'^', '<', '>', '=', '[', ']');
|
||||
}
|
||||
|
||||
constexpr bool IsSpaceEquiv(int state) noexcept {
|
||||
return state <= SCE_DART_TASKMARKER;
|
||||
}
|
||||
|
||||
void ColouriseDartDoc(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;
|
||||
|
||||
std::vector<int> nestedState; // string interpolation "${}"
|
||||
|
||||
int visibleChars = 0;
|
||||
int chBefore = 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
|
||||
3: nestedState count
|
||||
3*4: nestedState
|
||||
*/
|
||||
commentLevel = (lineState >> 2) & 0x3f;
|
||||
lineState >>= 8;
|
||||
if (lineState) {
|
||||
UnpackLineState(lineState, nestedState);
|
||||
}
|
||||
} else if (startPos == 0 && sc.Match('#', '!')) {
|
||||
// Shell Shebang at beginning of file
|
||||
sc.SetState(SCE_DART_COMMENTLINE);
|
||||
sc.Forward();
|
||||
lineStateLineType = 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:
|
||||
case SCE_DART_VARIABLE:
|
||||
case SCE_DART_VARIABLE2:
|
||||
case SCE_DART_METADATA:
|
||||
case SCE_DART_SYMBOL_IDENTIFIER:
|
||||
if (!IsIdentifierCharEx(sc.ch)) {
|
||||
switch (sc.state) {
|
||||
case SCE_DART_VARIABLE2:
|
||||
sc.SetState(escSeq.outerState);
|
||||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_DART_IDENTIFIER: {
|
||||
char s[128];
|
||||
sc.GetCurrent(s, sizeof(s));
|
||||
if (keywordLists[KeywordIndex_Keyword].InList(s)) {
|
||||
sc.ChangeState(SCE_DART_WORD);
|
||||
if (StrEqualsAny(s, "import", "part")) {
|
||||
if (visibleChars == sc.LengthCurrent()) {
|
||||
lineStateLineType = DartLineStateMaskImport;
|
||||
}
|
||||
} else if (StrEqualsAny(s, "class", "extends", "implements", "new", "throw", "as", "is")) {
|
||||
kwType = KeywordType::Class;
|
||||
} else if (StrEqual(s, "enum")) {
|
||||
kwType = KeywordType::Enum;
|
||||
} else if (StrEqualsAny(s, "break", "continue")) {
|
||||
kwType = KeywordType::Label;
|
||||
} else if (StrEqualsAny(s, "return", "await", "yield")) {
|
||||
kwType = KeywordType::Return;
|
||||
}
|
||||
if (kwType > KeywordType::None && kwType < KeywordType::Return) {
|
||||
const int chNext = sc.GetLineNextChar();
|
||||
if (!IsIdentifierStartEx(chNext)) {
|
||||
kwType = KeywordType::None;
|
||||
}
|
||||
}
|
||||
} else if (keywordLists[KeywordIndex_Type].InList(s)) {
|
||||
sc.ChangeState(SCE_DART_WORD2);
|
||||
} else if (keywordLists[KeywordIndex_Class].InList(s)) {
|
||||
sc.ChangeState(SCE_DART_CLASS);
|
||||
} else if (keywordLists[KeywordIndex_Enumeration].InList(s)) {
|
||||
sc.ChangeState(SCE_DART_ENUM);
|
||||
} else if (sc.ch == ':') {
|
||||
if (visibleChars == sc.LengthCurrent()) {
|
||||
const int chNext = sc.GetLineNextChar(true);
|
||||
if (IsJumpLabelNextChar(chNext)) {
|
||||
sc.ChangeState(SCE_DART_LABEL);
|
||||
}
|
||||
}
|
||||
} else if (sc.ch != '.') {
|
||||
if (kwType > KeywordType::None && kwType < KeywordType::Return) {
|
||||
sc.ChangeState(static_cast<int>(kwType));
|
||||
} else {
|
||||
const int chNext = sc.GetDocNextChar(sc.ch == '?');
|
||||
if (chNext == '(') {
|
||||
// type method()
|
||||
// type[] method()
|
||||
// type<type> method()
|
||||
if (kwType != KeywordType::Return && (IsIdentifierCharEx(chBefore) || chBefore == ']')) {
|
||||
sc.ChangeState(SCE_DART_FUNCTION_DEFINITION);
|
||||
} else {
|
||||
sc.ChangeState(SCE_DART_FUNCTION);
|
||||
}
|
||||
} else if ((chBeforeIdentifier == '<' && (chNext == '>' || chNext == '<'))
|
||||
|| IsIdentifierStartEx(chNext)) {
|
||||
// type<type>
|
||||
// type<type?>
|
||||
// type<type<type>>
|
||||
// type identifier
|
||||
// type? identifier
|
||||
sc.ChangeState(SCE_DART_CLASS);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sc.state != SCE_DART_WORD && sc.ch != '.') {
|
||||
kwType = KeywordType::None;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
sc.SetState(SCE_DART_DEFAULT);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_DART_SYMBOL_OPERATOR:
|
||||
if (!IsDeclarableOperator(sc.ch)) {
|
||||
sc.SetState(SCE_DART_DEFAULT);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_DART_COMMENTLINE:
|
||||
case SCE_DART_COMMENTLINEDOC:
|
||||
if (sc.atLineStart) {
|
||||
sc.SetState(SCE_DART_DEFAULT);
|
||||
} else {
|
||||
HighlightTaskMarker(sc, visibleChars, visibleCharsBefore, SCE_DART_TASKMARKER);
|
||||
}
|
||||
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();
|
||||
++commentLevel;
|
||||
} else if (HighlightTaskMarker(sc, visibleChars, visibleCharsBefore, SCE_DART_TASKMARKER)) {
|
||||
continue;
|
||||
}
|
||||
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.Advance(2);
|
||||
sc.ForwardSetState(SCE_DART_DEFAULT);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_DART_STRING_SQ:
|
||||
case SCE_DART_STRING_DQ:
|
||||
case SCE_DART_TRIPLE_STRING_SQ:
|
||||
case SCE_DART_TRIPLE_STRING_DQ:
|
||||
if ((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();
|
||||
if (sc.Match('u', '{')) {
|
||||
escSeq.brace = true;
|
||||
escSeq.digitsLeft = 7; // Unicode code point
|
||||
sc.Forward();
|
||||
}
|
||||
}
|
||||
} else if (sc.ch == '$') {
|
||||
if (sc.chNext == '{') {
|
||||
nestedState.push_back(sc.state);
|
||||
sc.SetState(SCE_DART_OPERATOR2);
|
||||
sc.Forward();
|
||||
} else if (IsIdentifierStartEx(sc.chNext)) {
|
||||
escSeq.outerState = sc.state;
|
||||
sc.SetState(SCE_DART_VARIABLE2);
|
||||
}
|
||||
} else if ((sc.ch == '\'' && (sc.state == SCE_DART_STRING_SQ || (sc.state == SCE_DART_TRIPLE_STRING_SQ && sc.MatchNext('\'', '\''))))
|
||||
|| (sc.ch == '"' && (sc.state == SCE_DART_STRING_DQ || (sc.state == SCE_DART_TRIPLE_STRING_DQ && sc.MatchNext('"', '"'))))) {
|
||||
if (sc.state == SCE_DART_TRIPLE_STRING_SQ || sc.state == SCE_DART_TRIPLE_STRING_DQ) {
|
||||
sc.Advance(2);
|
||||
}
|
||||
sc.ForwardSetState(SCE_DART_DEFAULT);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_DART_ESCAPECHAR:
|
||||
if (escSeq.atEscapeEnd(sc.ch)) {
|
||||
if (escSeq.brace && sc.ch == '}') {
|
||||
sc.Forward();
|
||||
}
|
||||
sc.SetState(escSeq.outerState);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (sc.state == SCE_DART_DEFAULT) {
|
||||
if (sc.ch == '/' && (sc.chNext == '/' || sc.chNext == '*')) {
|
||||
visibleCharsBefore = visibleChars;
|
||||
const int chNext = sc.chNext;
|
||||
sc.SetState((chNext == '/') ? SCE_DART_COMMENTLINE : SCE_DART_COMMENTBLOCK);
|
||||
sc.Forward(2);
|
||||
if (sc.ch == chNext && sc.chNext != chNext) {
|
||||
sc.ChangeState((chNext == '/') ? SCE_DART_COMMENTLINEDOC : SCE_DART_COMMENTBLOCKDOC);
|
||||
}
|
||||
if (chNext == '/') {
|
||||
if (visibleChars == 0) {
|
||||
lineStateLineType = DartLineStateMaskLineComment;
|
||||
}
|
||||
} else {
|
||||
commentLevel = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (sc.ch == '"') {
|
||||
if (sc.MatchNext('"', '"')) {
|
||||
sc.SetState(SCE_DART_TRIPLE_STRING_DQ);
|
||||
sc.Advance(2);
|
||||
} else {
|
||||
sc.SetState(SCE_DART_STRING_DQ);
|
||||
}
|
||||
} else if (sc.ch == '\'') {
|
||||
if (sc.MatchNext('\'', '\'')) {
|
||||
sc.SetState(SCE_DART_TRIPLE_STRING_SQ);
|
||||
sc.Advance(2);
|
||||
} else {
|
||||
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)) {
|
||||
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 (IsDeclarableOperator(sc.chNext)) {
|
||||
sc.SetState(SCE_DART_SYMBOL_OPERATOR);
|
||||
}
|
||||
} else if (IsIdentifierStartEx(sc.ch)) {
|
||||
chBefore = chPrevNonWhite;
|
||||
if (chPrevNonWhite != '.') {
|
||||
chBeforeIdentifier = chPrevNonWhite;
|
||||
}
|
||||
sc.SetState(SCE_DART_IDENTIFIER);
|
||||
} else if (isoperator(sc.ch)) {
|
||||
sc.SetState(SCE_DART_OPERATOR);
|
||||
if (!nestedState.empty()) {
|
||||
if (sc.ch == '{') {
|
||||
nestedState.push_back(SCE_DART_DEFAULT);
|
||||
} else if (sc.ch == '}') {
|
||||
const int outerState = TakeAndPop(nestedState);
|
||||
if (outerState != SCE_DART_DEFAULT) {
|
||||
sc.ChangeState(SCE_DART_OPERATOR2);
|
||||
}
|
||||
sc.ForwardSetState(outerState);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isspacechar(sc.ch)) {
|
||||
visibleChars++;
|
||||
if (!IsSpaceEquiv(sc.state)) {
|
||||
chPrevNonWhite = sc.ch;
|
||||
}
|
||||
}
|
||||
if (sc.atLineEnd) {
|
||||
int lineState = (commentLevel << 2) | lineStateLineType;
|
||||
if (!nestedState.empty()) {
|
||||
lineState |= PackLineState(nestedState) << 8;
|
||||
}
|
||||
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 & DartLineStateMaskLineComment),
|
||||
packageImport((lineState >> 1) & 1) {
|
||||
}
|
||||
};
|
||||
|
||||
constexpr bool IsMultilineStringStyle(int style) noexcept {
|
||||
return style == SCE_DART_TRIPLE_STRING_SQ
|
||||
|| style == SCE_DART_TRIPLE_STRING_DQ
|
||||
|| style == SCE_DART_OPERATOR2
|
||||
|| style == SCE_DART_VARIABLE2
|
||||
|| style == SCE_DART_ESCAPECHAR;
|
||||
}
|
||||
|
||||
void FoldDartDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, LexerWordList, 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_DART_OPERATOR, SCE_DART_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_DART_COMMENTBLOCKDOC:
|
||||
case SCE_DART_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_DART_TRIPLE_RAWSTRING_SQ:
|
||||
case SCE_DART_TRIPLE_RAWSTRING_DQ:
|
||||
if (style != stylePrev) {
|
||||
levelNext++;
|
||||
} else if (style != styleNext) {
|
||||
levelNext--;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_DART_TRIPLE_STRING_SQ:
|
||||
case SCE_DART_TRIPLE_STRING_DQ:
|
||||
if (!IsMultilineStringStyle(stylePrev)) {
|
||||
levelNext++;
|
||||
} else if (!IsMultilineStringStyle(styleNext)) {
|
||||
levelNext--;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_DART_OPERATOR:
|
||||
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));
|
||||
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_DART_OPERATOR, SCE_DART_TASKMARKER);
|
||||
if (bracePos) {
|
||||
levelNext++;
|
||||
startPos = bracePos + 1; // skip the brace
|
||||
style = SCE_DART_OPERATOR;
|
||||
chNext = styler[startPos];
|
||||
styleNext = styler.StyleAt(startPos);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
lineStartNext = sci::min(lineStartNext, endPos);
|
||||
levelCurrent = levelNext;
|
||||
foldPrev = foldCurrent;
|
||||
foldCurrent = foldNext;
|
||||
visibleChars = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LexerModule lmDart(SCLEX_DART, ColouriseDartDoc, "dart", FoldDartDoc);
|
||||
731
lexilla/lexers_x/orig/zufuliu/LexJavaScript.cxx
Normal file
731
lexilla/lexers_x/orig/zufuliu/LexJavaScript.cxx
Normal file
@ -0,0 +1,731 @@
|
||||
// This file is part of Notepad2.
|
||||
// See License.txt for details about distribution and modification.
|
||||
//! Lexer for JavaScript, JScript, TypeScript, ActionScript.
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#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"
|
||||
#include "DocUtils.h"
|
||||
|
||||
using namespace Lexilla;
|
||||
|
||||
namespace {
|
||||
|
||||
// https://tc39.es/ecma262/#prod-StringLiteral
|
||||
struct EscapeSequence {
|
||||
int outerState = SCE_JS_DEFAULT;
|
||||
int digitsLeft = 0;
|
||||
bool brace = false;
|
||||
|
||||
// highlight any character as escape sequence.
|
||||
void resetEscapeState(int state, int chNext) noexcept {
|
||||
outerState = state;
|
||||
digitsLeft = (chNext == 'x')? 3 : ((chNext == 'u') ? 5 : 1);
|
||||
}
|
||||
bool atEscapeEnd(int ch) noexcept {
|
||||
--digitsLeft;
|
||||
return digitsLeft <= 0 || !IsHexDigit(ch);
|
||||
}
|
||||
};
|
||||
|
||||
enum {
|
||||
JsLineStateMaskLineComment = 1, // line comment
|
||||
JsLineStateMaskImport = (1 << 1), // import
|
||||
|
||||
JsLineStateInsideJsxExpression = 1 << 3,
|
||||
JsLineStateLineContinuation = 1 << 4,
|
||||
};
|
||||
|
||||
//KeywordIndex++Autogenerated -- start of section automatically generated
|
||||
enum {
|
||||
KeywordIndex_Keyword = 0,
|
||||
KeywordIndex_FutureReservedWord = 1,
|
||||
KeywordIndex_Type = 1,
|
||||
KeywordIndex_Directive = 2,
|
||||
KeywordIndex_Class = 3,
|
||||
KeywordIndex_Interface = 4,
|
||||
KeywordIndex_Enumeration = 5,
|
||||
KeywordIndex_Constant = 6,
|
||||
KeywordIndex_Decorator = 7,
|
||||
KeywordIndex_Metadata = 7,
|
||||
};
|
||||
//KeywordIndex--Autogenerated -- end of section automatically generated
|
||||
|
||||
enum class KeywordType {
|
||||
None = SCE_JS_DEFAULT,
|
||||
Class = SCE_JS_CLASS,
|
||||
Interface = SCE_JS_INTERFACE,
|
||||
Enum = SCE_JS_ENUM,
|
||||
Function = SCE_JS_FUNCTION_DEFINITION,
|
||||
Label = SCE_JS_LABEL,
|
||||
};
|
||||
|
||||
enum class DocTagState {
|
||||
None,
|
||||
At, /// @param x
|
||||
InlineAt, /// {@link https://tsdoc.org/}
|
||||
XmlOpen, /// <reference path="" />
|
||||
XmlClose, /// </param>, No this (C# like) style
|
||||
};
|
||||
|
||||
static_assert(DefaultNestedStateBaseStyle + 1 == SCE_JS_STRING_BT);
|
||||
static_assert(DefaultNestedStateBaseStyle + 2 == SCE_JSX_TEXT);
|
||||
|
||||
inline bool IsJsIdentifierStartNext(const StyleContext &sc) noexcept {
|
||||
return IsJsIdentifierStart(sc.chNext) || (sc.chNext == '\\' && sc.GetRelative(2) == 'u');
|
||||
}
|
||||
|
||||
constexpr bool IsSpaceEquiv(int state) noexcept {
|
||||
return state <= SCE_JS_TASKMARKER;
|
||||
}
|
||||
|
||||
constexpr bool FollowExpression(int chPrevNonWhite, int stylePrevNonWhite) noexcept {
|
||||
return chPrevNonWhite == ')' || chPrevNonWhite == ']'
|
||||
|| stylePrevNonWhite == SCE_JS_OPERATOR_PF
|
||||
|| IsJsIdentifierChar(chPrevNonWhite);
|
||||
}
|
||||
|
||||
constexpr bool IsRegexStart(int chPrevNonWhite, int stylePrevNonWhite) noexcept {
|
||||
return stylePrevNonWhite == SCE_JS_WORD || !FollowExpression(chPrevNonWhite, stylePrevNonWhite);
|
||||
}
|
||||
|
||||
inline bool IsJsxTagStart(const StyleContext &sc, int chPrevNonWhite, int stylePrevNonWhite) noexcept {
|
||||
// https://facebook.github.io/jsx/
|
||||
// https://reactjs.org/docs/jsx-in-depth.html
|
||||
return IsRegexStart(chPrevNonWhite, stylePrevNonWhite)
|
||||
&& (IsJsIdentifierStartNext(sc) || sc.chNext == '>' || sc.chNext == '{');
|
||||
}
|
||||
|
||||
void ColouriseJsDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, LexerWordList keywordLists, Accessor &styler) {
|
||||
int lineStateLineType = 0;
|
||||
int lineContinuation = 0;
|
||||
bool insideRegexRange = false; // inside regex character range []
|
||||
|
||||
KeywordType kwType = KeywordType::None;
|
||||
int chBeforeIdentifier = 0;
|
||||
|
||||
std::vector<int> nestedState; // string interpolation "${}"
|
||||
bool insideJsxTag = false;
|
||||
int jsxTagLevel = 0;
|
||||
std::vector<int> jsxTagLevels;// nested JSX tag in expression
|
||||
|
||||
// JSX syntax conflicts with TypeScript type assert.
|
||||
// https://www.typescriptlang.org/docs/handbook/jsx.html
|
||||
const bool enableJsx = styler.GetPropertyBool("lexer.lang", false);
|
||||
|
||||
int visibleChars = 0;
|
||||
int visibleCharsBefore = 0;
|
||||
int operatorBefore = 0;
|
||||
int chPrevNonWhite = 0;
|
||||
int stylePrevNonWhite = SCE_JS_DEFAULT;
|
||||
DocTagState docTagState = DocTagState::None;
|
||||
EscapeSequence escSeq;
|
||||
|
||||
if (enableJsx && startPos != 0) {
|
||||
// backtrack to the line starts JSX for better coloring on typing.
|
||||
BacktrackToStart(styler, JsLineStateInsideJsxExpression, startPos, lengthDoc, initStyle);
|
||||
}
|
||||
|
||||
StyleContext sc(startPos, lengthDoc, initStyle, styler);
|
||||
if (sc.currentLine > 0) {
|
||||
int lineState = styler.GetLineState(sc.currentLine - 1);
|
||||
/*
|
||||
2: lineStateLineType
|
||||
1: JsLineStateInsideJsxExpression
|
||||
1: lineContinuation
|
||||
3: nestedState count
|
||||
3*4: nestedState
|
||||
*/
|
||||
lineContinuation = lineState & JsLineStateLineContinuation;
|
||||
lineState >>= 8;
|
||||
if (lineState) {
|
||||
UnpackLineState(lineState, nestedState);
|
||||
}
|
||||
}
|
||||
if (startPos == 0) {
|
||||
if (sc.Match('#', '!')) {
|
||||
// Shell Shebang at beginning of file
|
||||
sc.SetState(SCE_JS_COMMENTLINE);
|
||||
sc.Forward();
|
||||
lineStateLineType = JsLineStateMaskLineComment;
|
||||
}
|
||||
} else if (IsSpaceEquiv(initStyle)) {
|
||||
// look back for better regex colouring
|
||||
LookbackNonWhite(styler, startPos, SCE_JS_TASKMARKER, chPrevNonWhite, stylePrevNonWhite);
|
||||
}
|
||||
|
||||
while (sc.More()) {
|
||||
switch (sc.state) {
|
||||
case SCE_JS_OPERATOR:
|
||||
case SCE_JS_OPERATOR2:
|
||||
case SCE_JS_OPERATOR_PF:
|
||||
sc.SetState(SCE_JS_DEFAULT);
|
||||
break;
|
||||
|
||||
case SCE_JS_NUMBER:
|
||||
if (!IsDecimalNumberEx(sc.chPrev, sc.ch, sc.chNext)) {
|
||||
sc.SetState(SCE_JS_DEFAULT);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_JS_IDENTIFIER:
|
||||
case SCE_JSX_TAG:
|
||||
case SCE_JSX_ATTRIBUTE:
|
||||
case SCE_JSX_ATTRIBUTE_AT:
|
||||
case SCE_JS_DECORATOR:
|
||||
if ((sc.ch == '.' && !(sc.state == SCE_JS_IDENTIFIER || sc.state == SCE_JSX_ATTRIBUTE_AT))
|
||||
|| (sc.ch == ':' && (sc.state == SCE_JSX_TAG || sc.state == SCE_JSX_ATTRIBUTE))) {
|
||||
const int state = sc.state;
|
||||
sc.SetState(SCE_JS_OPERATOR2);
|
||||
sc.ForwardSetState(state);
|
||||
}
|
||||
if (sc.Match('\\', 'u') || (sc.ch == '-' && (sc.state == SCE_JSX_TAG || sc.state == SCE_JSX_ATTRIBUTE))) {
|
||||
sc.Forward();
|
||||
} else if (!IsJsIdentifierChar(sc.ch)) {
|
||||
if (sc.state == SCE_JS_IDENTIFIER) {
|
||||
char s[128];
|
||||
sc.GetCurrent(s, sizeof(s));
|
||||
if (keywordLists[KeywordIndex_Directive].InList(s)) {
|
||||
sc.ChangeState(SCE_JS_DIRECTIVE);
|
||||
if (StrEqualsAny(s, "import", "require")) {
|
||||
lineStateLineType = JsLineStateMaskImport;
|
||||
}
|
||||
} else if (keywordLists[KeywordIndex_Keyword].InList(s)) {
|
||||
sc.ChangeState(SCE_JS_WORD);
|
||||
if (StrEqualsAny(s, "class", "extends","new", "type", "as", "is")) {
|
||||
kwType = KeywordType::Class;
|
||||
} else if (StrEqual(s, "function")) {
|
||||
kwType = KeywordType::Function;
|
||||
} else if (StrEqualsAny(s, "interface", "implements")) {
|
||||
kwType = KeywordType::Interface;
|
||||
} else if (StrEqual(s, "enum")) {
|
||||
kwType = KeywordType::Enum;
|
||||
} else if (StrEqualsAny(s, "break", "continue")) {
|
||||
kwType = KeywordType::Label;
|
||||
}
|
||||
if (kwType != KeywordType::None) {
|
||||
const int chNext = sc.GetLineNextChar();
|
||||
if (!(IsJsIdentifierStart(chNext) || chNext == '\\')) {
|
||||
kwType = KeywordType::None;
|
||||
}
|
||||
}
|
||||
} else if (keywordLists[KeywordIndex_FutureReservedWord].InList(s)) {
|
||||
sc.ChangeState(SCE_JS_WORD2);
|
||||
} else if (keywordLists[KeywordIndex_Class].InList(s)) {
|
||||
sc.ChangeState(SCE_JS_CLASS);
|
||||
} else if (keywordLists[KeywordIndex_Interface].InList(s)) {
|
||||
sc.ChangeState(SCE_JS_INTERFACE);
|
||||
} else if (keywordLists[KeywordIndex_Enumeration].InList(s)) {
|
||||
sc.ChangeState(SCE_JS_ENUM);
|
||||
} else if (keywordLists[KeywordIndex_Constant].InList(s)) {
|
||||
sc.ChangeState(SCE_JS_CONSTANT);
|
||||
} else if (sc.ch == ':') {
|
||||
if (visibleChars == sc.LengthCurrent()) {
|
||||
const int chNext = sc.GetLineNextChar(true);
|
||||
if (IsJumpLabelNextChar(chNext)) {
|
||||
sc.ChangeState(SCE_JS_LABEL);
|
||||
}
|
||||
}
|
||||
} else if (sc.ch != '.') {
|
||||
if (kwType != KeywordType::None) {
|
||||
sc.ChangeState(static_cast<int>(kwType));
|
||||
} else {
|
||||
const int chNext = sc.GetDocNextChar(sc.ch == '?');
|
||||
if (chNext == '(') {
|
||||
sc.ChangeState(SCE_JS_FUNCTION);
|
||||
} else if (sc.Match('[', ']')
|
||||
|| (chBeforeIdentifier == '<' && (chNext == '>' || chNext == '<'))) {
|
||||
// type[]
|
||||
// type<type>
|
||||
// type<type?>
|
||||
// type<type<type>>
|
||||
sc.ChangeState(SCE_JS_CLASS);
|
||||
}
|
||||
}
|
||||
}
|
||||
stylePrevNonWhite = sc.state;
|
||||
if (sc.state != SCE_JS_WORD && sc.ch != '.') {
|
||||
kwType = KeywordType::None;
|
||||
}
|
||||
}
|
||||
sc.SetState((sc.state == SCE_JSX_TAG || sc.state == SCE_JSX_ATTRIBUTE) ? SCE_JSX_TEXT : SCE_JS_DEFAULT);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_JS_STRING_SQ:
|
||||
case SCE_JS_STRING_DQ:
|
||||
case SCE_JSX_STRING_SQ:
|
||||
case SCE_JSX_STRING_DQ:
|
||||
if (sc.atLineStart) {
|
||||
if (lineContinuation) {
|
||||
lineContinuation = 0;
|
||||
} else {
|
||||
sc.SetState((sc.state == SCE_JSX_STRING_SQ || sc.state == SCE_JSX_STRING_DQ) ? SCE_JSX_TEXT : SCE_JS_DEFAULT);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (sc.ch == '\\') {
|
||||
if (IsEOLChar(sc.chNext)) {
|
||||
lineContinuation = JsLineStateLineContinuation;
|
||||
} else {
|
||||
escSeq.resetEscapeState(sc.state, sc.chNext);
|
||||
sc.SetState(SCE_JS_ESCAPECHAR);
|
||||
sc.Forward();
|
||||
if (sc.Match('u', '{')) {
|
||||
escSeq.brace = true;
|
||||
escSeq.digitsLeft = 9; // Unicode code point
|
||||
sc.Forward();
|
||||
}
|
||||
}
|
||||
} else if ((sc.ch == '\'' && (sc.state == SCE_JS_STRING_SQ || sc.state == SCE_JSX_STRING_SQ))
|
||||
|| (sc.ch == '"' && (sc.state == SCE_JS_STRING_DQ || sc.state == SCE_JSX_STRING_DQ))) {
|
||||
sc.Forward();
|
||||
if (operatorBefore == ',' || operatorBefore == '{') {
|
||||
// json key
|
||||
const int chNext = sc.GetLineNextChar();
|
||||
if (chNext == ':') {
|
||||
sc.ChangeState(SCE_JS_KEY);
|
||||
}
|
||||
}
|
||||
sc.SetState((sc.state == SCE_JSX_STRING_SQ || sc.state == SCE_JSX_STRING_DQ) ? SCE_JSX_TEXT : SCE_JS_DEFAULT);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_JS_STRING_BT:
|
||||
if (sc.ch == '\\') {
|
||||
if (!IsEOLChar(sc.chNext)) {
|
||||
escSeq.resetEscapeState(sc.state, sc.chNext);
|
||||
sc.SetState(SCE_JS_ESCAPECHAR);
|
||||
sc.Forward();
|
||||
if (sc.Match('u', '{')) {
|
||||
escSeq.brace = true;
|
||||
escSeq.digitsLeft = 9; // Unicode code point
|
||||
sc.Forward();
|
||||
}
|
||||
}
|
||||
} else if (sc.Match('$', '{')) {
|
||||
nestedState.push_back(sc.state);
|
||||
sc.SetState(SCE_JS_OPERATOR2);
|
||||
sc.Forward();
|
||||
} else if (sc.ch == '`') {
|
||||
sc.ForwardSetState(SCE_JS_DEFAULT);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_JS_ESCAPECHAR:
|
||||
if (escSeq.atEscapeEnd(sc.ch)) {
|
||||
if (escSeq.brace && sc.ch == '}') {
|
||||
sc.Forward();
|
||||
}
|
||||
sc.SetState(escSeq.outerState);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_JS_REGEX:
|
||||
if (sc.atLineStart) {
|
||||
sc.SetState(SCE_JS_DEFAULT);
|
||||
} else if (sc.ch == '\\') {
|
||||
sc.Forward();
|
||||
} else if (sc.ch == '[' || sc.ch == ']') {
|
||||
insideRegexRange = sc.ch == '[';
|
||||
} else if (sc.ch == '/' && !insideRegexRange) {
|
||||
sc.Forward();
|
||||
// regex flags
|
||||
while (IsLowerCase(sc.ch)) {
|
||||
sc.Forward();
|
||||
}
|
||||
sc.SetState(SCE_JS_DEFAULT);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_JS_COMMENTLINE:
|
||||
case SCE_JS_COMMENTLINEDOC:
|
||||
case SCE_JS_COMMENTBLOCK:
|
||||
case SCE_JS_COMMENTBLOCKDOC:
|
||||
if (sc.state == SCE_JS_COMMENTLINE || sc.state == SCE_JS_COMMENTLINEDOC) {
|
||||
if (sc.atLineStart) {
|
||||
sc.SetState(SCE_JS_DEFAULT);
|
||||
break;
|
||||
}
|
||||
} else if (sc.Match('*', '/')) {
|
||||
sc.Forward();
|
||||
sc.ForwardSetState(SCE_JS_DEFAULT);
|
||||
break;
|
||||
}
|
||||
switch (docTagState) {
|
||||
case DocTagState::At:
|
||||
docTagState = DocTagState::None;
|
||||
break;
|
||||
case DocTagState::InlineAt:
|
||||
if (sc.ch == '}') {
|
||||
docTagState = DocTagState::None;
|
||||
sc.SetState(SCE_JS_COMMENTTAGAT);
|
||||
sc.ForwardSetState(SCE_JS_COMMENTBLOCKDOC);
|
||||
}
|
||||
break;
|
||||
case DocTagState::XmlOpen:
|
||||
case DocTagState::XmlClose:
|
||||
if (sc.Match('/', '>') || sc.ch == '>') {
|
||||
docTagState = DocTagState::None;
|
||||
sc.SetState(SCE_JS_COMMENTTAGXML);
|
||||
sc.Forward((sc.ch == '/') ? 2 : 1);
|
||||
sc.SetState(SCE_JS_COMMENTLINEDOC);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (docTagState == DocTagState::None) {
|
||||
if (sc.ch == '@' && IsLowerCase(sc.chNext) && IsCommentTagPrev(sc.chPrev)) {
|
||||
docTagState = DocTagState::At;
|
||||
escSeq.outerState = sc.state;
|
||||
sc.SetState(SCE_JS_COMMENTTAGAT);
|
||||
} else if (sc.state == SCE_JS_COMMENTBLOCKDOC && sc.Match('{', '@') && IsLowerCase(sc.GetRelative(2))) {
|
||||
docTagState = DocTagState::InlineAt;
|
||||
escSeq.outerState = sc.state;
|
||||
sc.SetState(SCE_JS_COMMENTTAGAT);
|
||||
sc.Forward();
|
||||
} else if (sc.state == SCE_JS_COMMENTLINEDOC && sc.ch == '<') {
|
||||
if (IsLowerCase(sc.chNext)) {
|
||||
docTagState = DocTagState::XmlOpen;
|
||||
escSeq.outerState = sc.state;
|
||||
sc.SetState(SCE_JS_COMMENTTAGXML);
|
||||
} else if (sc.chNext == '/' && IsLowerCase(sc.GetRelative(2))) {
|
||||
docTagState = DocTagState::XmlClose;
|
||||
escSeq.outerState = sc.state;
|
||||
sc.SetState(SCE_JS_COMMENTTAGXML);
|
||||
sc.Forward();
|
||||
}
|
||||
} else if (HighlightTaskMarker(sc, visibleChars, visibleCharsBefore, SCE_JS_TASKMARKER)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_JS_COMMENTTAGAT:
|
||||
case SCE_JS_COMMENTTAGXML:
|
||||
if (!(IsIdentifierChar(sc.ch) || sc.ch == '-')) {
|
||||
sc.SetState(escSeq.outerState);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_JSX_TEXT:
|
||||
if (sc.ch == '>' || sc.Match('/', '>')) {
|
||||
insideJsxTag = false;
|
||||
sc.SetState(SCE_JSX_TAG);
|
||||
if (sc.ch == '/') {
|
||||
// self closing <tag />
|
||||
--jsxTagLevel;
|
||||
sc.Forward();
|
||||
}
|
||||
sc.Forward();
|
||||
if (jsxTagLevel == 0) {
|
||||
sc.SetState(SCE_JS_DEFAULT);
|
||||
} else {
|
||||
sc.SetState(SCE_JSX_TEXT);
|
||||
continue;
|
||||
}
|
||||
} else if (sc.ch == '=' && insideJsxTag) {
|
||||
sc.SetState(SCE_JS_OPERATOR2);
|
||||
sc.ForwardSetState(SCE_JSX_TEXT);
|
||||
continue;
|
||||
} else if ((sc.ch == '\'' || sc.ch == '\"') && insideJsxTag) {
|
||||
operatorBefore = 0;
|
||||
sc.SetState((sc.ch == '\'') ? SCE_JSX_STRING_SQ : SCE_JSX_STRING_DQ);
|
||||
} else if (insideJsxTag && (IsJsIdentifierStart(sc.ch) || sc.Match('\\', 'u'))) {
|
||||
sc.SetState(SCE_JSX_ATTRIBUTE);
|
||||
} else if (sc.ch == '{') {
|
||||
jsxTagLevels.push_back(jsxTagLevel);
|
||||
nestedState.push_back(sc.state);
|
||||
sc.SetState(SCE_JS_OPERATOR2);
|
||||
jsxTagLevel = 0;
|
||||
} else if (sc.Match('<', '/')) {
|
||||
--jsxTagLevel;
|
||||
insideJsxTag = false;
|
||||
sc.SetState(SCE_JSX_TAG);
|
||||
sc.Forward();
|
||||
} else if (sc.ch == '<') {
|
||||
++jsxTagLevel;
|
||||
insideJsxTag = true;
|
||||
sc.SetState(SCE_JSX_TAG);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (sc.state == SCE_JS_DEFAULT) {
|
||||
if (sc.ch == '/') {
|
||||
if (sc.chNext == '/' || sc.chNext == '*') {
|
||||
docTagState = DocTagState::None;
|
||||
visibleCharsBefore = visibleChars;
|
||||
const int chNext = sc.chNext;
|
||||
sc.SetState((chNext == '/') ? SCE_JS_COMMENTLINE : SCE_JS_COMMENTBLOCK);
|
||||
sc.Forward(2);
|
||||
if (sc.ch == '!' || (sc.ch == chNext && sc.chNext != chNext)) {
|
||||
sc.ChangeState((chNext == '/') ? SCE_JS_COMMENTLINEDOC : SCE_JS_COMMENTBLOCKDOC);
|
||||
}
|
||||
if (chNext == '/') {
|
||||
if (visibleChars == 0) {
|
||||
lineStateLineType = JsLineStateMaskLineComment;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!IsEOLChar(sc.chNext) && IsRegexStart(chPrevNonWhite, stylePrevNonWhite)) {
|
||||
insideRegexRange = false;
|
||||
sc.SetState(SCE_JS_REGEX);
|
||||
} else {
|
||||
sc.SetState(SCE_JS_OPERATOR);
|
||||
}
|
||||
}
|
||||
else if (sc.ch == '\'' || sc.ch == '\"') {
|
||||
operatorBefore = (stylePrevNonWhite == SCE_JS_OPERATOR) ? chPrevNonWhite : 0;
|
||||
sc.SetState((sc.ch == '\'') ? SCE_JS_STRING_SQ : SCE_JS_STRING_DQ);
|
||||
} else if (sc.ch == '`') {
|
||||
sc.SetState(SCE_JS_STRING_BT);
|
||||
} else if (IsNumberStartEx(sc.chPrev, sc.ch, sc.chNext)) {
|
||||
sc.SetState(SCE_JS_NUMBER);
|
||||
} else if (sc.ch == '@' && IsJsIdentifierStartNext(sc)) {
|
||||
sc.SetState((sc.chPrev == '.') ? SCE_JSX_ATTRIBUTE_AT : SCE_JS_DECORATOR);
|
||||
} else if (IsJsIdentifierStart(sc.ch) || sc.Match('\\', 'u')) {
|
||||
if (sc.chPrev != '.') {
|
||||
chBeforeIdentifier = sc.chPrev;
|
||||
}
|
||||
sc.SetState(SCE_JS_IDENTIFIER);
|
||||
}
|
||||
else if (sc.ch == '+' || sc.ch == '-') {
|
||||
if (sc.ch == sc.chNext) {
|
||||
// highlight ++ and -- as different style to simplify regex detection.
|
||||
sc.SetState(SCE_JS_OPERATOR_PF);
|
||||
sc.Forward();
|
||||
} else {
|
||||
sc.SetState(SCE_JS_OPERATOR);
|
||||
}
|
||||
} else if (sc.ch == '<' && enableJsx) {
|
||||
// <tag></tag>
|
||||
if (sc.chNext == '/') {
|
||||
insideJsxTag = false;
|
||||
--jsxTagLevel;
|
||||
sc.SetState(SCE_JSX_TAG);
|
||||
sc.Forward();
|
||||
} else if (IsJsxTagStart(sc, chPrevNonWhite, stylePrevNonWhite)) {
|
||||
insideJsxTag = true;
|
||||
++jsxTagLevel;
|
||||
sc.SetState(SCE_JSX_TAG);
|
||||
} else {
|
||||
sc.SetState(SCE_JS_OPERATOR);
|
||||
}
|
||||
} else if (isoperator(sc.ch)) {
|
||||
sc.SetState(SCE_JS_OPERATOR);
|
||||
if (!nestedState.empty()) {
|
||||
if (sc.ch == '{') {
|
||||
nestedState.push_back(SCE_JS_DEFAULT);
|
||||
if (enableJsx) {
|
||||
jsxTagLevels.push_back(jsxTagLevel);
|
||||
jsxTagLevel = 0;
|
||||
}
|
||||
} else if (sc.ch == '}') {
|
||||
if (enableJsx) {
|
||||
jsxTagLevel = TryTakeAndPop(jsxTagLevels);
|
||||
}
|
||||
const int outerState = TakeAndPop(nestedState);
|
||||
if (outerState != SCE_JS_DEFAULT) {
|
||||
sc.ChangeState(SCE_JS_OPERATOR2);
|
||||
}
|
||||
sc.ForwardSetState(outerState);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isspacechar(sc.ch)) {
|
||||
visibleChars++;
|
||||
if (!IsSpaceEquiv(sc.state)) {
|
||||
chPrevNonWhite = sc.ch;
|
||||
stylePrevNonWhite = sc.state;
|
||||
}
|
||||
}
|
||||
if (sc.atLineEnd) {
|
||||
int lineState = lineContinuation | lineStateLineType;
|
||||
if (enableJsx && !(jsxTagLevel == 0 && jsxTagLevels.empty())) {
|
||||
lineState |= JsLineStateInsideJsxExpression;
|
||||
}
|
||||
if (!nestedState.empty()) {
|
||||
lineState |= PackLineState(nestedState) << 8;
|
||||
}
|
||||
styler.SetLineState(sc.currentLine, lineState);
|
||||
lineStateLineType = 0;
|
||||
visibleChars = 0;
|
||||
visibleCharsBefore = 0;
|
||||
kwType = KeywordType::None;
|
||||
docTagState = DocTagState::None;
|
||||
}
|
||||
sc.Forward();
|
||||
}
|
||||
|
||||
sc.Complete();
|
||||
}
|
||||
|
||||
struct FoldLineState {
|
||||
int lineComment;
|
||||
int packageImport;
|
||||
int lineContinuation;
|
||||
constexpr explicit FoldLineState(int lineState) noexcept:
|
||||
lineComment(lineState & JsLineStateMaskLineComment),
|
||||
packageImport((lineState >> 1) & 1),
|
||||
lineContinuation((lineState >> 4) & 1) {
|
||||
}
|
||||
};
|
||||
|
||||
constexpr bool IsStreamCommentStyle(int style) noexcept {
|
||||
return style == SCE_JS_COMMENTBLOCK
|
||||
|| style == SCE_JS_COMMENTBLOCKDOC
|
||||
|| style == SCE_JS_COMMENTTAGAT
|
||||
|| style == SCE_JS_COMMENTTAGXML
|
||||
|| style == SCE_JS_TASKMARKER;
|
||||
}
|
||||
|
||||
constexpr bool IsMultilineStringStyle(int style) noexcept {
|
||||
return style == SCE_JS_STRING_BT
|
||||
|| style == SCE_JS_OPERATOR2
|
||||
|| style == SCE_JS_ESCAPECHAR;
|
||||
}
|
||||
|
||||
void FoldJsDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, LexerWordList, 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_JS_OPERATOR, SCE_JS_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_JS_COMMENTBLOCK:
|
||||
case SCE_JS_COMMENTBLOCKDOC:
|
||||
if (!IsStreamCommentStyle(stylePrev)) {
|
||||
levelNext++;
|
||||
} else if (!IsStreamCommentStyle(styleNext)) {
|
||||
levelNext--;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_JS_STRING_BT:
|
||||
if (!IsMultilineStringStyle(stylePrev)) {
|
||||
levelNext++;
|
||||
} else if (!IsMultilineStringStyle(styleNext)) {
|
||||
levelNext--;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_JS_OPERATOR:
|
||||
if (ch == '{' || ch == '[' || ch == '(') {
|
||||
levelNext++;
|
||||
} else if (ch == '}' || ch == ']' || ch == ')') {
|
||||
levelNext--;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_JSX_TAG:
|
||||
if (ch == '<') {
|
||||
if (chNext == '/') {
|
||||
levelNext--;
|
||||
startPos++;
|
||||
chNext = styler[startPos];
|
||||
styleNext = styler.StyleAt(startPos);
|
||||
} else {
|
||||
levelNext++;
|
||||
}
|
||||
} else if (ch == '/' && chNext == '>') {
|
||||
levelNext--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (visibleChars == 0 && !IsSpaceEquiv(style)) {
|
||||
++visibleChars;
|
||||
}
|
||||
if (startPos == lineStartNext) {
|
||||
const FoldLineState foldNext(styler.GetLineState(lineCurrent + 1));
|
||||
if (foldCurrent.lineComment) {
|
||||
levelNext += foldNext.lineComment - foldPrev.lineComment;
|
||||
} else if (foldCurrent.packageImport) {
|
||||
levelNext += foldNext.packageImport - foldPrev.packageImport;
|
||||
} else if (foldCurrent.lineContinuation | foldPrev.lineContinuation) {
|
||||
levelNext += foldCurrent.lineContinuation - foldPrev.lineContinuation;
|
||||
} else if (visibleChars) {
|
||||
const Sci_PositionU bracePos = CheckBraceOnNextLine(styler, lineCurrent, SCE_JS_OPERATOR, SCE_JS_TASKMARKER);
|
||||
if (bracePos) {
|
||||
levelNext++;
|
||||
startPos = bracePos + 1; // skip the brace
|
||||
style = SCE_JS_OPERATOR;
|
||||
chNext = styler[startPos];
|
||||
styleNext = styler.StyleAt(startPos);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
lineStartNext = sci::min(lineStartNext, endPos);
|
||||
levelCurrent = levelNext;
|
||||
foldPrev = foldCurrent;
|
||||
foldCurrent = foldNext;
|
||||
visibleChars = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LexerModule lmJavaScript(SCLEX_JAVASCRIPT, ColouriseJsDoc, "js", FoldJsDoc);
|
||||
505
lexilla/lexers_x/orig/zufuliu/LexKotlin.cxx
Normal file
505
lexilla/lexers_x/orig/zufuliu/LexKotlin.cxx
Normal file
@ -0,0 +1,505 @@
|
||||
// This file is part of Notepad2.
|
||||
// See License.txt for details about distribution and modification.
|
||||
//! Lexer for Kotlin.
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#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_KOTLIN_DEFAULT;
|
||||
int digitsLeft = 0;
|
||||
|
||||
// highlight any character as escape sequence.
|
||||
bool resetEscapeState(int state, int chNext) noexcept {
|
||||
if (IsEOLChar(chNext)) {
|
||||
return false;
|
||||
}
|
||||
outerState = state;
|
||||
digitsLeft = (chNext == 'u') ? 5 : 1;
|
||||
return true;
|
||||
}
|
||||
bool atEscapeEnd(int ch) noexcept {
|
||||
--digitsLeft;
|
||||
return digitsLeft <= 0 || !IsHexDigit(ch);
|
||||
}
|
||||
};
|
||||
|
||||
enum {
|
||||
KotlinLineStateMaskLineComment = 1, // line comment
|
||||
KotlinLineStateMaskImport = 1 << 1, // import
|
||||
};
|
||||
|
||||
//KeywordIndex++Autogenerated -- start of section automatically generated
|
||||
enum {
|
||||
KeywordIndex_Keyword = 0,
|
||||
KeywordIndex_Class = 1,
|
||||
KeywordIndex_Interface = 2,
|
||||
KeywordIndex_Enumeration = 3,
|
||||
};
|
||||
//KeywordIndex--Autogenerated -- end of section automatically generated
|
||||
|
||||
enum class KeywordType {
|
||||
None = SCE_KOTLIN_DEFAULT,
|
||||
Annotation = SCE_KOTLIN_ANNOTATION,
|
||||
Class = SCE_KOTLIN_CLASS,
|
||||
Interface = SCE_KOTLIN_INTERFACE,
|
||||
Enum = SCE_KOTLIN_ENUM,
|
||||
Label = SCE_KOTLIN_LABEL,
|
||||
Return = 0x40,
|
||||
};
|
||||
|
||||
static_assert(DefaultNestedStateBaseStyle + 1 == SCE_KOTLIN_STRING);
|
||||
static_assert(DefaultNestedStateBaseStyle + 2 == SCE_KOTLIN_RAWSTRING);
|
||||
|
||||
constexpr bool IsSpaceEquiv(int state) noexcept {
|
||||
return state <= SCE_KOTLIN_TASKMARKER;
|
||||
}
|
||||
|
||||
void ColouriseKotlinDoc(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;
|
||||
|
||||
std::vector<int> nestedState; // string interpolation "${}"
|
||||
|
||||
int visibleChars = 0;
|
||||
int chBefore = 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
|
||||
3: nestedState count
|
||||
3*4: nestedState
|
||||
*/
|
||||
commentLevel = (lineState >> 2) & 0x3f;
|
||||
lineState >>= 8;
|
||||
if (lineState) {
|
||||
UnpackLineState(lineState, nestedState);
|
||||
}
|
||||
} else if (startPos == 0 && sc.Match('#', '!')) {
|
||||
// Shell Shebang at beginning of file
|
||||
sc.SetState(SCE_KOTLIN_COMMENTLINE);
|
||||
sc.Forward();
|
||||
lineStateLineType = KotlinLineStateMaskLineComment;
|
||||
}
|
||||
|
||||
while (sc.More()) {
|
||||
switch (sc.state) {
|
||||
case SCE_KOTLIN_OPERATOR:
|
||||
case SCE_KOTLIN_OPERATOR2:
|
||||
sc.SetState(SCE_KOTLIN_DEFAULT);
|
||||
break;
|
||||
|
||||
case SCE_KOTLIN_NUMBER:
|
||||
if (!IsDecimalNumber(sc.chPrev, sc.ch, sc.chNext)) {
|
||||
sc.SetState(SCE_KOTLIN_DEFAULT);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_KOTLIN_VARIABLE:
|
||||
case SCE_KOTLIN_LABEL:
|
||||
case SCE_KOTLIN_IDENTIFIER:
|
||||
case SCE_KOTLIN_ANNOTATION:
|
||||
if (!IsIdentifierCharEx(sc.ch)) {
|
||||
switch (sc.state) {
|
||||
case SCE_KOTLIN_VARIABLE:
|
||||
sc.SetState(escSeq.outerState);
|
||||
continue;
|
||||
|
||||
case SCE_KOTLIN_ANNOTATION:
|
||||
if (sc.ch == '.' || sc.ch == ':') {
|
||||
sc.SetState(SCE_KOTLIN_OPERATOR);
|
||||
sc.ForwardSetState(SCE_KOTLIN_ANNOTATION);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_KOTLIN_IDENTIFIER: {
|
||||
char s[128];
|
||||
sc.GetCurrent(s, sizeof(s));
|
||||
if (keywordLists[KeywordIndex_Keyword].InList(s)) {
|
||||
sc.ChangeState(SCE_KOTLIN_WORD);
|
||||
if (StrEqual(s, "import")) {
|
||||
if (visibleChars == sc.LengthCurrent()) {
|
||||
lineStateLineType = KotlinLineStateMaskImport;
|
||||
}
|
||||
} else if (StrEqualsAny(s, "break", "continue", "return", "this", "super")) {
|
||||
kwType = KeywordType::Label;
|
||||
} else if (StrEqualsAny(s, "class", "typealias")) {
|
||||
if (!(kwType == KeywordType::Annotation || kwType == KeywordType::Enum)) {
|
||||
kwType = KeywordType::Class;
|
||||
}
|
||||
} else if (StrEqual(s, "enum")) {
|
||||
kwType = KeywordType::Enum;
|
||||
} else if (StrEqual(s, "annotation")) {
|
||||
kwType = KeywordType::Annotation;
|
||||
} else if (StrEqual(s, "interface")) {
|
||||
kwType = KeywordType::Interface;
|
||||
} else if (StrEqual(s, "return")) {
|
||||
kwType = KeywordType::Return;
|
||||
}
|
||||
if (kwType > KeywordType::None && kwType < KeywordType::Return) {
|
||||
const int chNext = sc.GetDocNextChar();
|
||||
if (!((kwType == KeywordType::Label) ? (chNext == '@') : IsIdentifierStartEx(chNext))) {
|
||||
kwType = KeywordType::None;
|
||||
}
|
||||
}
|
||||
} else if (sc.ch == '@') {
|
||||
sc.ChangeState(SCE_KOTLIN_LABEL);
|
||||
sc.Forward();
|
||||
} else if (keywordLists[KeywordIndex_Class].InList(s)) {
|
||||
sc.ChangeState(SCE_KOTLIN_CLASS);
|
||||
} else if (keywordLists[KeywordIndex_Interface].InList(s)) {
|
||||
sc.ChangeState(SCE_KOTLIN_INTERFACE);
|
||||
} else if (keywordLists[KeywordIndex_Enumeration].InList(s)) {
|
||||
sc.ChangeState(SCE_KOTLIN_ENUM);
|
||||
} else if (sc.ch != '.') {
|
||||
if (kwType > KeywordType::None && kwType < KeywordType::Return) {
|
||||
sc.ChangeState(static_cast<int>(kwType));
|
||||
} else {
|
||||
const int chNext = sc.GetDocNextChar(sc.ch == '?');
|
||||
if (chNext == '(') {
|
||||
// type function()
|
||||
// type[] function()
|
||||
// type<type> function()
|
||||
if (kwType != KeywordType::Return && (IsIdentifierCharEx(chBefore) || chBefore == ']')) {
|
||||
sc.ChangeState(SCE_KOTLIN_FUNCTION_DEFINITION);
|
||||
} else {
|
||||
sc.ChangeState(SCE_KOTLIN_FUNCTION);
|
||||
}
|
||||
} else if (sc.Match(':', ':')
|
||||
|| (chBeforeIdentifier == '<' && (chNext == '>' || chNext == '<'))) {
|
||||
// type::class
|
||||
// type<type>
|
||||
// type<type?>
|
||||
// type<type<type>>
|
||||
sc.ChangeState(SCE_KOTLIN_CLASS);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sc.state != SCE_KOTLIN_WORD && sc.ch != '.') {
|
||||
kwType = KeywordType::None;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
sc.SetState(SCE_KOTLIN_DEFAULT);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_KOTLIN_COMMENTLINE:
|
||||
case SCE_KOTLIN_COMMENTLINEDOC:
|
||||
if (sc.atLineStart) {
|
||||
sc.SetState(SCE_KOTLIN_DEFAULT);
|
||||
} else {
|
||||
HighlightTaskMarker(sc, visibleChars, visibleCharsBefore, SCE_KOTLIN_TASKMARKER);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_KOTLIN_COMMENTBLOCK:
|
||||
case SCE_KOTLIN_COMMENTBLOCKDOC:
|
||||
if (sc.state == SCE_KOTLIN_COMMENTBLOCKDOC && sc.ch == '@' && IsLowerCase(sc.chNext) && IsCommentTagPrev(sc.chPrev)) {
|
||||
sc.SetState(SCE_KOTLIN_COMMENTDOCWORD);
|
||||
} else if (sc.Match('*', '/')) {
|
||||
sc.Forward();
|
||||
--commentLevel;
|
||||
if (commentLevel == 0) {
|
||||
sc.ForwardSetState(SCE_KOTLIN_DEFAULT);
|
||||
}
|
||||
} else if (sc.Match('/', '*')) {
|
||||
sc.Forward();
|
||||
++commentLevel;
|
||||
} else if (HighlightTaskMarker(sc, visibleChars, visibleCharsBefore, SCE_KOTLIN_TASKMARKER)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_KOTLIN_COMMENTDOCWORD:
|
||||
if (!IsLowerCase(sc.ch)) {
|
||||
sc.SetState(SCE_KOTLIN_COMMENTBLOCKDOC);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_KOTLIN_STRING:
|
||||
case SCE_KOTLIN_RAWSTRING:
|
||||
if (sc.state == SCE_KOTLIN_STRING && sc.atLineStart) {
|
||||
sc.SetState(SCE_KOTLIN_DEFAULT);
|
||||
} else if (sc.state == SCE_KOTLIN_STRING && sc.ch == '\\') {
|
||||
if (escSeq.resetEscapeState(sc.state, sc.chNext)) {
|
||||
sc.SetState(SCE_KOTLIN_ESCAPECHAR);
|
||||
sc.Forward();
|
||||
}
|
||||
} else if (sc.ch == '$') {
|
||||
if (sc.chNext == '{') {
|
||||
nestedState.push_back(sc.state);
|
||||
sc.SetState(SCE_KOTLIN_OPERATOR2);
|
||||
sc.Forward();
|
||||
} else if (IsIdentifierStartEx(sc.chNext)) {
|
||||
escSeq.outerState = sc.state;
|
||||
sc.SetState(SCE_KOTLIN_VARIABLE);
|
||||
}
|
||||
} else if (sc.ch == '\"' && (sc.state == SCE_KOTLIN_STRING || sc.MatchNext('"', '"'))) {
|
||||
if (sc.state == SCE_KOTLIN_RAWSTRING) {
|
||||
sc.Advance(2);
|
||||
}
|
||||
sc.ForwardSetState(SCE_KOTLIN_DEFAULT);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_KOTLIN_CHARACTER:
|
||||
if (sc.atLineStart) {
|
||||
sc.SetState(SCE_KOTLIN_DEFAULT);
|
||||
} else if (sc.ch == '\\') {
|
||||
if (escSeq.resetEscapeState(sc.state, sc.chNext)) {
|
||||
sc.SetState(SCE_KOTLIN_ESCAPECHAR);
|
||||
sc.Forward();
|
||||
}
|
||||
} else if (sc.ch == '\'') {
|
||||
sc.ForwardSetState(SCE_KOTLIN_DEFAULT);
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_KOTLIN_ESCAPECHAR:
|
||||
if (escSeq.atEscapeEnd(sc.ch)) {
|
||||
sc.SetState(escSeq.outerState);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_KOTLIN_BACKTICKS:
|
||||
if (sc.atLineStart) {
|
||||
sc.SetState(SCE_KOTLIN_DEFAULT);
|
||||
} else if (sc.ch == '`') {
|
||||
sc.ForwardSetState(SCE_KOTLIN_DEFAULT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (sc.state == SCE_KOTLIN_DEFAULT) {
|
||||
if (sc.ch == '/' && (sc.chNext == '/' || sc.chNext == '*')) {
|
||||
visibleCharsBefore = visibleChars;
|
||||
const int chNext = sc.chNext;
|
||||
sc.SetState((chNext == '/') ? SCE_KOTLIN_COMMENTLINE : SCE_KOTLIN_COMMENTBLOCK);
|
||||
sc.Forward(2);
|
||||
if (sc.ch == '!' || (sc.ch == chNext && sc.chNext != chNext)) {
|
||||
sc.ChangeState((chNext == '/') ? SCE_KOTLIN_COMMENTLINEDOC : SCE_KOTLIN_COMMENTBLOCKDOC);
|
||||
}
|
||||
if (chNext == '/') {
|
||||
if (visibleChars == 0) {
|
||||
lineStateLineType = KotlinLineStateMaskLineComment;
|
||||
}
|
||||
} else {
|
||||
commentLevel = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (sc.ch == '\"') {
|
||||
if (sc.MatchNext('"', '"')) {
|
||||
sc.SetState(SCE_KOTLIN_RAWSTRING);
|
||||
sc.Advance(2);
|
||||
} else {
|
||||
sc.SetState(SCE_KOTLIN_STRING);
|
||||
}
|
||||
} else if (sc.ch == '\'') {
|
||||
sc.SetState(SCE_KOTLIN_CHARACTER);
|
||||
} else if (IsNumberStart(sc.ch, sc.chNext)) {
|
||||
sc.SetState(SCE_KOTLIN_NUMBER);
|
||||
} else if (sc.ch == '@' && IsIdentifierStartEx(sc.chNext)) {
|
||||
sc.SetState((kwType == KeywordType::Label) ? SCE_KOTLIN_LABEL : SCE_KOTLIN_ANNOTATION);
|
||||
kwType = KeywordType::None;
|
||||
} else if (sc.ch == '`') {
|
||||
sc.SetState(SCE_KOTLIN_BACKTICKS);
|
||||
} else if (IsIdentifierStartEx(sc.ch)) {
|
||||
chBefore = chPrevNonWhite;
|
||||
if (chPrevNonWhite != '.') {
|
||||
chBeforeIdentifier = chPrevNonWhite;
|
||||
}
|
||||
sc.SetState(SCE_KOTLIN_IDENTIFIER);
|
||||
} else if (isoperator(sc.ch)) {
|
||||
sc.SetState(SCE_KOTLIN_OPERATOR);
|
||||
if (!nestedState.empty()) {
|
||||
if (sc.ch == '{') {
|
||||
nestedState.push_back(SCE_KOTLIN_DEFAULT);
|
||||
} else if (sc.ch == '}') {
|
||||
const int outerState = TakeAndPop(nestedState);
|
||||
if (outerState != SCE_KOTLIN_DEFAULT) {
|
||||
sc.ChangeState(SCE_KOTLIN_OPERATOR2);
|
||||
}
|
||||
sc.ForwardSetState(outerState);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isspacechar(sc.ch)) {
|
||||
visibleChars++;
|
||||
if (!IsSpaceEquiv(sc.state)) {
|
||||
chPrevNonWhite = sc.ch;
|
||||
}
|
||||
}
|
||||
if (sc.atLineEnd) {
|
||||
int lineState = (commentLevel << 2) | lineStateLineType;
|
||||
if (!nestedState.empty()) {
|
||||
lineState |= PackLineState(nestedState) << 8;
|
||||
}
|
||||
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 & KotlinLineStateMaskLineComment),
|
||||
packageImport((lineState >> 1) & 1) {
|
||||
}
|
||||
};
|
||||
|
||||
constexpr bool IsMultilineStringStyle(int style) noexcept {
|
||||
return style == SCE_KOTLIN_RAWSTRING
|
||||
|| style == SCE_KOTLIN_OPERATOR2
|
||||
|| style == SCE_KOTLIN_ESCAPECHAR
|
||||
|| style == SCE_KOTLIN_VARIABLE;
|
||||
}
|
||||
|
||||
void FoldKotlinDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, LexerWordList, 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_KOTLIN_OPERATOR, SCE_KOTLIN_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_KOTLIN_COMMENTBLOCK:
|
||||
case SCE_KOTLIN_COMMENTBLOCKDOC: {
|
||||
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_KOTLIN_RAWSTRING:
|
||||
if (!IsMultilineStringStyle(stylePrev)) {
|
||||
levelNext++;
|
||||
} else if (!IsMultilineStringStyle(styleNext)) {
|
||||
levelNext--;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCE_KOTLIN_OPERATOR:
|
||||
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));
|
||||
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_KOTLIN_OPERATOR, SCE_KOTLIN_TASKMARKER);
|
||||
if (bracePos) {
|
||||
levelNext++;
|
||||
startPos = bracePos + 1; // skip the brace
|
||||
style = SCE_KOTLIN_OPERATOR;
|
||||
chNext = styler[startPos];
|
||||
styleNext = styler.StyleAt(startPos);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
lineStartNext = sci::min(lineStartNext, endPos);
|
||||
levelCurrent = levelNext;
|
||||
foldPrev = foldCurrent;
|
||||
foldCurrent = foldNext;
|
||||
visibleChars = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LexerModule lmKotlin(SCLEX_KOTLIN, ColouriseKotlinDoc, "kotlin", FoldKotlinDoc);
|
||||
@ -3919,7 +3919,7 @@ LRESULT MsgFileChangeNotify(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(wParam);
|
||||
UNREFERENCED_PARAMETER(lParam);
|
||||
|
||||
|
||||
SET_FCT_GUARD(TRUE);
|
||||
|
||||
InstallFileWatching(false); // terminate
|
||||
@ -3952,7 +3952,7 @@ LRESULT MsgFileChangeNotify(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
||||
Sci_ScrollSelectionToView();
|
||||
}
|
||||
|
||||
} else {
|
||||
} else { // file has been deleted
|
||||
|
||||
if (FileWatching.FileWatchingMode == FWM_MSGBOX) {
|
||||
if (IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONWARNING, NULL, IDS_MUI_FILECHANGENOTIFY2))) {
|
||||
@ -3964,6 +3964,7 @@ LRESULT MsgFileChangeNotify(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
||||
// FWM_INDICATORSILENT: nothing todo here
|
||||
SetSaveNeeded(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
InstallFileWatching(true);
|
||||
@ -12636,7 +12637,9 @@ void InstallFileWatching(const bool bInstall) {
|
||||
HPATHL hdir_pth = Path_Copy(Paths.CurrentFile);
|
||||
Path_RemoveFileSpec(hdir_pth);
|
||||
|
||||
bool const bFileDirExists = Path_IsNotEmpty(Paths.CurrentFile) && Path_IsExistingDirectory(hdir_pth); //~ && Path_IsExistingFile(Paths.CurrentFile);
|
||||
bool const bFileDirExists = Path_IsNotEmpty(Paths.CurrentFile) && Path_IsExistingDirectory(hdir_pth);
|
||||
bool const bFileExists = bFileDirExists && Path_IsExistingFile(Paths.CurrentFile);
|
||||
|
||||
bool const bExclusiveLock = (FileWatching.FileWatchingMode == FWM_EXCLUSIVELOCK);
|
||||
bool const bWatchFile = (FileWatching.FileWatchingMode != FWM_DONT_CARE) && !bExclusiveLock;
|
||||
|
||||
@ -12652,16 +12655,16 @@ void InstallFileWatching(const bool bInstall) {
|
||||
BackgroundWorker_Init(&(s_FileChgObsvrData.worker), NULL, NULL);
|
||||
}
|
||||
|
||||
bool const bTerminate = !bInstall || !bWatchFile || !bFileDirExists;
|
||||
bool const bTerminate = !bInstall || !bWatchFile || !bFileDirExists /*~||!bFileExists~*/;
|
||||
|
||||
// Terminate previous watching
|
||||
if (bTerminate) {
|
||||
KillTimer(Globals.hwndMain, ID_WATCHTIMER);
|
||||
BackgroundWorker_Cancel(&(s_FileChgObsvrData.worker));
|
||||
ResetFileObservationData(true);
|
||||
ResetFileObservationData(false); // (!) false
|
||||
}
|
||||
|
||||
if (bInstall) {
|
||||
if (bInstall && bFileExists) {
|
||||
|
||||
if (bWatchFile) {
|
||||
|
||||
@ -12684,7 +12687,8 @@ void InstallFileWatching(const bool bInstall) {
|
||||
KillTimer(Globals.hwndMain, ID_WATCHTIMER);
|
||||
}
|
||||
|
||||
} else if (bExclusiveLock) {
|
||||
}
|
||||
else if (bExclusiveLock) {
|
||||
|
||||
assert(!IS_VALID_HANDLE(_hCurrFileHandle) && "CurrFileHandle not properly closed!");
|
||||
|
||||
|
||||
@ -248,8 +248,8 @@ void Lexer_SetLexerSpecificProperties(const int lexerId) {
|
||||
break;
|
||||
|
||||
case SCLEX_JSON:
|
||||
SciCall_SetProperty("json.allow.comments", "1");
|
||||
SciCall_SetProperty("json.escape.sequence", "1");
|
||||
SciCall_SetProperty("lexer.json.allow.comments", "1");
|
||||
SciCall_SetProperty("lexer.json.escape.sequence", "1");
|
||||
break;
|
||||
|
||||
case SCLEX_PYTHON:
|
||||
|
||||
@ -13,7 +13,8 @@ No \\n's!",
|
||||
leadingDecimalPoint: 1234567, .8675309, andTrailing: 8675309.,
|
||||
positiveSign: +1,
|
||||
trailingComma: 'in objects', andIn: ['arrays',],
|
||||
escSeq: "\uAFFE",
|
||||
escSeq: "\uAEEE",
|
||||
escSeq2: "\uAFFE",
|
||||
"backwardsCompatible": "with JSON",
|
||||
Infinity: Infinity,
|
||||
positiveInfinity: +Infinity,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user