Skip to content

Commit 861a2fb

Browse files
committed
[Python] Improve soft keyword highlighting.
1 parent b50771a commit 861a2fb

File tree

4 files changed

+51
-26
lines changed

4 files changed

+51
-26
lines changed

scintilla/lexers/LexPython.cxx

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,34 @@ Sci_Position CheckBraceFormatSpecifier(const StyleContext &sc, LexAccessor &styl
373373
return pos - sc.currentPos;
374374
}
375375

376+
constexpr bool IsMatchExpressionStart(int ch, int chNext) noexcept {
377+
return IsADigit(ch) || (ch == '.' && IsADigit(chNext))
378+
|| (chNext != '=' && AnyOf(ch, '*', '+', '-', '~', '(', '[', '{'));
379+
}
380+
381+
bool IsSoftKeyword(const char *s, const StyleContext &sc, LexAccessor &styler) noexcept {
382+
// match expression
383+
// case pattern
384+
// type identifier
385+
int ch = sc.ch;
386+
int chNext = sc.chNext;
387+
if (IsWhiteSpace(sc.ch)) {
388+
Sci_PositionU pos = sc.currentPos + 1;
389+
while (pos < sc.lineStartNext) {
390+
const uint8_t chAfter = styler[pos++];
391+
if (!IsWhiteSpace(chAfter)) {
392+
if (IsIdentifierStartEx(chAfter)) {
393+
return true;
394+
}
395+
ch = chAfter;
396+
chNext = static_cast<uint8_t>(styler[pos]);
397+
break;
398+
}
399+
}
400+
}
401+
return s[0] != 't' && IsMatchExpressionStart(ch, chNext);
402+
}
403+
376404
constexpr bool IsDocCommentTag(int state, int chNext) noexcept {
377405
return IsPyString(state) && IsPyTripleQuotedString(state) && (chNext == 'p' || chNext == 't' || chNext == 'r');
378406
}
@@ -408,7 +436,6 @@ void ColourisePyDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyl
408436
int chPrevNonWhite = 0;
409437
int prevIndentCount = 0;
410438
int indentCount = 0;
411-
int parenCount = 0;
412439
int lineState = 0;
413440
bool prevLineContinuation = false;
414441
bool lineContinuation = false;
@@ -427,7 +454,6 @@ void ColourisePyDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyl
427454
if (sc.currentLine > 0) {
428455
prevLineContinuation = (styler.GetLineState(sc.currentLine - 2) & PyLineStateLineContinuation) != 0;
429456
lineState = styler.GetLineState(sc.currentLine - 1);
430-
parenCount = (lineState >> 8) & 0xff;
431457
prevIndentCount = lineState >> 16;
432458
lineContinuation = (lineState & PyLineStateLineContinuation) != 0;
433459
lineState = 0;
@@ -460,6 +486,10 @@ void ColourisePyDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyl
460486
kwType = KeywordType::Function;
461487
} else if (StrEqualsAny(s, "class", "raise", "except")) {
462488
kwType = KeywordType::Class;
489+
} else if (StrEqualsAny(s, "match", "case", "type")) {
490+
if (visibleChars != sc.LengthCurrent() || !IsSoftKeyword(s, sc, styler)) {
491+
sc.ChangeState(SCE_PY_IDENTIFIER);
492+
}
463493
}
464494
} else if (keywordLists[KeywordIndex_Type].InList(s)) {
465495
sc.ChangeState(SCE_PY_WORD2);
@@ -473,10 +503,13 @@ void ColourisePyDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyl
473503
sc.ChangeState(SCE_PY_OBJECT_FUNCTION);
474504
} else if (keywordLists[KeywordIndex_Class].InList(s)) {
475505
sc.ChangeState(SCE_PY_CLASS);
476-
} else if (kwType != KeywordType::None) {
477-
sc.ChangeState(static_cast<int>(kwType));
478-
} else if (sc.GetLineNextChar() == '(') {
479-
sc.ChangeState(SCE_PY_FUNCTION);
506+
}
507+
if (sc.state == SCE_PY_IDENTIFIER) {
508+
if (kwType != KeywordType::None) {
509+
sc.ChangeState(static_cast<int>(kwType));
510+
} else if (sc.GetLineNextChar() == '(') {
511+
sc.ChangeState(SCE_PY_FUNCTION);
512+
}
480513
}
481514
if (sc.state != SCE_PY_WORD) {
482515
kwType = KeywordType::None;
@@ -801,12 +834,8 @@ void ColourisePyDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyl
801834
}
802835
} else if (IsIdentifierStartEx(sc.ch)) {
803836
sc.SetState(SCE_PY_IDENTIFIER);
804-
} else if (sc.ch == '@') {
805-
if (!lineContinuation && visibleChars == 0 && parenCount == 0 && IsIdentifierStartEx(sc.chNext)) {
806-
sc.SetState(SCE_PY_DECORATOR);
807-
} else {
808-
sc.SetState(SCE_PY_OPERATOR);
809-
}
837+
} else if (sc.ch == '@' && visibleChars == 0 && IsIdentifierStartEx(sc.chNext)) {
838+
sc.SetState(SCE_PY_DECORATOR);
810839
} else if (IsAGraphic(sc.ch) && sc.ch != '\\') {
811840
kwType = KeywordType::None;
812841
const bool interpolating = !nestedState.empty();
@@ -815,8 +844,6 @@ void ColourisePyDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyl
815844
if (sc.ch == '{' || sc.ch == '[' || sc.ch == '(') {
816845
if (interpolating) {
817846
nestedState.back().parenCount += 1;
818-
} else {
819-
++parenCount;
820847
}
821848
} else if (sc.ch == '}' || sc.ch == ']' || sc.ch == ')') {
822849
if (interpolating) {
@@ -826,9 +853,6 @@ void ColourisePyDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyl
826853
--state.parenCount;
827854
}
828855
} else {
829-
if (parenCount > 0) {
830-
--parenCount;
831-
}
832856
if (visibleChars == 0) {
833857
lineState |= PyLineStateMaskCloseBrace;
834858
}
@@ -865,7 +889,7 @@ void ColourisePyDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyl
865889
++indentCount;
866890
}
867891
}
868-
lineState |= (indentCount << 16) | (parenCount << 8);
892+
lineState |= (indentCount << 16);
869893
prevIndentCount = indentCount;
870894
prevLineContinuation = lineContinuation;
871895
lineContinuation = false;

scintilla/lexlib/LexAccessor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ Sci_Position LexLineSkipSpaceTab(LexAccessor &styler, Sci_Line line) noexcept;
322322
inline Sci_Position LexSkipSpaceTab(LexAccessor &styler, Sci_Position startPos, Sci_Position endPos) noexcept {
323323
for (; startPos < endPos; startPos++) {
324324
const char ch = styler.SafeGetCharAt(startPos);
325-
if (!(ch == ' ' || ch == '\t')) {
325+
if (ch != ' ' && ch != '\t') {
326326
break;
327327
}
328328
}

src/EditLexers/stlPython.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ static KEYWORDLIST Keywords_Python = {{
8888
"URLError UUID UnboundLocalError Underflow "
8989
"UnicodeDecodeError UnicodeEncodeError UnicodeError UnicodeTranslateError UnicodeWarning UnsupportedOperation "
9090
"UserDict UserList UserString UserWarning "
91-
"ValueError ValuesView Warning WindowsPath ZeroDivisionError array catch_warnings date datetime defaultdict deque error "
91+
"ValueError ValuesView Warning WindowsPath ZeroDivisionError array catch_warnings date datetime defaultdict deque "
9292
"partialmethod sched_param singledispatchmethod stat_result struct_time terminal_size time timedelta timezone tzinfo "
9393

9494
, // 7 decorator
@@ -136,7 +136,7 @@ static KEYWORDLIST Keywords_Python = {{
136136
"done( drain( dropwhile( dst( dump( dumps( dup( dup2( "
137137
"east_asian_width( elements( emit( empty( "
138138
"enable_callback_tracebacks( enable_load_extension( encode( end( endswith( enter_async_context( enter_context( "
139-
"erf( erfc( escape( eventfd( eventfd_read( eventfd_write( exc_info( excepthook( exception( "
139+
"erf( erfc( error( escape( eventfd( eventfd_read( eventfd_write( exc_info( excepthook( exception( "
140140
"execl( execle( execlp( execlpe( execute( executemany( executescript( execv( execve( execvp( execvpe( exists( "
141141
"exp( exp2( expand( expandtabs( expanduser( expandvars( expired( expm1( expovariate( "
142142
"extend( extendleft( extract( extract_stack( extract_tb( "
@@ -315,7 +315,7 @@ static KEYWORDLIST Keywords_Python = {{
315315
"color column compact compare conflict_handler const context copy_function count counts creationflags ctx cum_weights "
316316
"cwd "
317317
"days debug default defaults delete deterministic device dict_factory dir_fd dirs_exist_ok dont_inherit doseq dst_dir_fd "
318-
"effective_ids enable ensure_ascii enter_result env epilog exclusive exist_ok exit_on_error extra extra_groups "
318+
"effective_ids enable ensure_ascii enter_result env epilog error exclusive exist_ok exit_on_error extra extra_groups "
319319
"factory fallback family fdel fget file_actions file_encoding fillvalue firstline fix_imports flush fmt "
320320
"foldspaces follow_symlinks followlinks formatter_class fromfile_prefix_chars fromlist frozen fset "
321321
"globals group hash help hint host hours "

tools/lang/Python.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ def del
2727
yield
2828

2929
# soft keywords
30-
case match
31-
type
30+
match match
31+
case case
32+
type type
3233
# https://docs.python.org/2.7/reference/lexical_analysis.html#identifiers
3334
exec print
3435

@@ -821,7 +822,7 @@ class TextWrapper(**kwargs):
821822
# Binary Data Services
822823
# https://docs.python.org/3/library/binary.html
823824
struct
824-
exception error(msg)
825+
# exception error(msg)
825826
pack(format, v1, v2, ...)
826827
pack_into(format, buffer, offset, v1, v2, ...)
827828
unpack(format, buffer)
@@ -1834,7 +1835,7 @@ class PrepareProtocol
18341835
# Generic Operating System Services
18351836
# https://docs.python.org/3/library/allos.html
18361837
os
1837-
exception error
1838+
# exception error
18381839
name
18391840
# Process Parameters
18401841
ctermid()

0 commit comments

Comments
 (0)