@@ -157,9 +157,30 @@ constexpr bool stateTerminateScript(int state) noexcept {
157157 return !isStringState (state) && !(state >= js_style (SCE_JS_COMMENTBLOCK ) && state <= js_style (SCE_JS_TASKMARKER ));
158158}
159159
160+ struct EscapeSequence {
161+ int outerState = SCE_H_DEFAULT ;
162+ int digitsLeft = 0 ;
163+
164+ // highlight any character as escape sequence.
165+ void resetEscapeState (int state, int chNext) noexcept {
166+ outerState = state;
167+ digitsLeft = 1 ;
168+ if (chNext == ' x' ) {
169+ digitsLeft = 3 ;
170+ } else if (chNext == ' u' ) {
171+ digitsLeft = 5 ;
172+ }
173+ }
174+ bool atEscapeEnd (int ch) noexcept {
175+ --digitsLeft;
176+ return digitsLeft <= 0 || !IsHexDigit (ch);
177+ }
178+ };
179+
160180struct HtmlLexer {
161181 int chBefore = 0 ;
162182 KeywordType kwType = KeywordType::None;
183+ EscapeSequence escSeq;
163184};
164185
165186SCI_noinline
@@ -1017,16 +1038,17 @@ void ColouriseHyperTextDoc(Sci_PositionU startPos, Sci_Position length, int init
10171038 state = js_style (SCE_JS_DEFAULT );
10181039 }
10191040 break ;
1020- case js_style (SCE_JS_IDENTIFIER ):
10211041 case js_style (SCE_JS_NUMBER ):
1022- if (!(IsJsIdentifierChar (ch) || (state == js_style (SCE_JS_NUMBER ) && IsNumberContinueEx (chPrev, ch, chNext)))) {
1023- if (state == js_style (SCE_JS_NUMBER )) {
1024- styler.ColorTo (i, state);
1025- state = js_style (SCE_JS_DEFAULT );
1026- } else {
1027- state = js_style (SCE_JS_DEFAULT );
1028- stylePrevNonWhite = classifyWordHTJS (i, ch, chNext, lexer, keywordLists, styler);
1029- }
1042+ case SCE_HB_NUMBER :
1043+ if (!(IsIdentifierChar (ch) || IsNumberContinueEx (chPrev, ch, chNext))) {
1044+ styler.ColorTo (i, state);
1045+ state = lexer.escSeq .outerState ;
1046+ }
1047+ break ;
1048+ case js_style (SCE_JS_IDENTIFIER ):
1049+ if (!IsJsIdentifierChar (ch)) {
1050+ state = js_style (SCE_JS_DEFAULT );
1051+ stylePrevNonWhite = classifyWordHTJS (i, ch, chNext, lexer, keywordLists, styler);
10301052 }
10311053 break ;
10321054 case js_style (SCE_JS_COMMENTBLOCK ):
@@ -1048,7 +1070,10 @@ void ColouriseHyperTextDoc(Sci_PositionU startPos, Sci_Position length, int init
10481070 case js_style (SCE_JS_STRING_SQ ):
10491071 case js_style (SCE_JS_TEMPLATELITERAL ):
10501072 if (ch == ' \\ ' ) {
1051- if (IsAGraphic (chNext)) {
1073+ if (chNext >= ' ' ) {
1074+ styler.ColorTo (i, state);
1075+ lexer.escSeq .resetEscapeState (state, chNext);
1076+ state = js_style (SCE_JS_ESCAPECHAR );
10521077 i++;
10531078 }
10541079 } else if (ch == ((state == js_style (SCE_JS_STRING_DQ )) ? ' \" ' : ((state == js_style (SCE_JS_STRING_SQ )) ? ' \' ' : ' `' ))) {
@@ -1072,6 +1097,14 @@ void ColouriseHyperTextDoc(Sci_PositionU startPos, Sci_Position length, int init
10721097 state = js_style (SCE_JS_DEFAULT );
10731098 }
10741099 break ;
1100+ case js_style (SCE_JS_ESCAPECHAR ):
1101+ if (lexer.escSeq .atEscapeEnd (ch)) {
1102+ styler.ColorTo (i, state);
1103+ state = lexer.escSeq .outerState ;
1104+ i -= 1 ;
1105+ continue ;
1106+ }
1107+ break ;
10751108 case js_style (SCE_JS_REGEX ):
10761109 if (ch == ' \r ' || ch == ' \n ' || (ch == ' /' && !insideRegexCharacterClass)) {
10771110 if (ch == ' /' ) {
@@ -1103,14 +1136,8 @@ void ColouriseHyperTextDoc(Sci_PositionU startPos, Sci_Position length, int init
11031136 }
11041137 break ;
11051138 case SCE_HB_IDENTIFIER :
1106- case SCE_HB_NUMBER :
1107- if (!(IsIdentifierCharEx (ch) || (state == SCE_HB_NUMBER && IsNumberContinue (chPrev, ch, chNext)))) {
1108- if (state == SCE_HB_NUMBER ) {
1109- styler.ColorTo (i, state);
1110- state = SCE_HB_DEFAULT ;
1111- } else {
1112- state = classifyWordHTVB (i, keywordLists, styler);
1113- }
1139+ if (!IsIdentifierCharEx (ch)) {
1140+ state = classifyWordHTVB (i, keywordLists, styler);
11141141 }
11151142 break ;
11161143 case SCE_HB_STRING :
@@ -1147,6 +1174,7 @@ void ColouriseHyperTextDoc(Sci_PositionU startPos, Sci_Position length, int init
11471174 } else if (ch == ' `' ) {
11481175 state = js_style (SCE_JS_TEMPLATELITERAL );
11491176 } else if (IsNumberStart (ch, chNext)) {
1177+ lexer.escSeq .outerState = js_style (SCE_JS_DEFAULT );
11501178 state = js_style (SCE_JS_NUMBER );
11511179 } else if (IsJsIdentifierStart (ch)) {
11521180 lexer.chBefore = chPrevNonWhite;
@@ -1183,6 +1211,7 @@ void ColouriseHyperTextDoc(Sci_PositionU startPos, Sci_Position length, int init
11831211 } else if (ch == ' \' ' ) {
11841212 state = SCE_HB_COMMENTLINE ;
11851213 } else if (IsNumberStart (ch, chNext)) {
1214+ lexer.escSeq .outerState = SCE_HB_DEFAULT ;
11861215 state = SCE_HB_NUMBER ;
11871216 } else if (IsIdentifierStartEx (ch)) {
11881217 state = SCE_HB_IDENTIFIER ;
0 commit comments