Skip to content

Commit

Permalink
Support Java 21 string template.
Browse files Browse the repository at this point in the history
  • Loading branch information
zufuliu committed Jan 8, 2024
1 parent 8894350 commit 70f91c9
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 71 deletions.
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Latest development builds (artifacts in Release configuration for each compiler
* INI Configuration File
* [Inno Setup](tools/lang/InnoSetup.iss), up to Inno Setup 6.2.
* [Boost Jam](tools/lang/Jamfile.jam), up to Jam 4.4.
* [Java](tools/lang/Java.java), up to Java 20. [Screenshots](https://github.com/zufuliu/notepad2/wiki/Screenshots#java)
* [Java](tools/lang/Java.java), up to Java 21. [Screenshots](https://github.com/zufuliu/notepad2/wiki/Screenshots#java)
* [BeanShell](https://github.com/beanshell/beanshell)
* [JavaScript](tools/lang/JavaScript.js), up to ECMAScript 2023 with [JSX](https://facebook.github.io/jsx/) and [Web APIs](https://developer.mozilla.org/en-US/docs/Web/API).
* [JSON](https://www.json.org) and [JSON5](https://json5.org/) Document
Expand Down
45 changes: 24 additions & 21 deletions scintilla/include/SciLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -1560,27 +1560,30 @@
#define SCE_JAVA_COMMENTTAGAT 5
#define SCE_JAVA_COMMENTTAGHTML 6
#define SCE_JAVA_TASKMARKER 7
#define SCE_JAVA_NUMBER 8
#define SCE_JAVA_OPERATOR 9
#define SCE_JAVA_CHARACTER 10
#define SCE_JAVA_STRING 11
#define SCE_JAVA_TRIPLE_STRING 12
#define SCE_JAVA_ESCAPECHAR 13
#define SCE_JAVA_FORMAT_SPECIFIER 14
#define SCE_JAVA_PLACEHOLDER 15
#define SCE_JAVA_ANNOTATION 16
#define SCE_JAVA_IDENTIFIER 17
#define SCE_JAVA_WORD 18
#define SCE_JAVA_RECORD 19
#define SCE_JAVA_WORD2 20
#define SCE_JAVA_DIRECTIVE 21
#define SCE_JAVA_CLASS 22
#define SCE_JAVA_INTERFACE 23
#define SCE_JAVA_ENUM 24
#define SCE_JAVA_FUNCTION 25
#define SCE_JAVA_CONSTANT 26
#define SCE_JAVA_FUNCTION_DEFINITION 27
#define SCE_JAVA_LABEL 28
#define SCE_JAVA_OPERATOR 8
#define SCE_JAVA_OPERATOR2 9
#define SCE_JAVA_STRING 10
#define SCE_JAVA_TEMPLATE 11
#define SCE_JAVA_TRIPLE_TEMPLATE 12
#define SCE_JAVA_TRIPLE_STRING 13
#define SCE_JAVA_ESCAPECHAR 14
#define SCE_JAVA_FORMAT_SPECIFIER 15
#define SCE_JAVA_PLACEHOLDER 16
#define SCE_JAVA_CHARACTER 17
#define SCE_JAVA_NUMBER 18
#define SCE_JAVA_ANNOTATION 19
#define SCE_JAVA_IDENTIFIER 20
#define SCE_JAVA_WORD 21
#define SCE_JAVA_RECORD 22
#define SCE_JAVA_WORD2 23
#define SCE_JAVA_DIRECTIVE 24
#define SCE_JAVA_CLASS 25
#define SCE_JAVA_INTERFACE 26
#define SCE_JAVA_ENUM 27
#define SCE_JAVA_FUNCTION 28
#define SCE_JAVA_CONSTANT 29
#define SCE_JAVA_FUNCTION_DEFINITION 30
#define SCE_JAVA_LABEL 31
#define SCE_HAXE_DEFAULT 0
#define SCE_HAXE_COMMENTLINE 1
#define SCE_HAXE_COMMENTLINEDOC 2
Expand Down
57 changes: 30 additions & 27 deletions scintilla/include/SciLexer.iface
Original file line number Diff line number Diff line change
Expand Up @@ -2855,33 +2855,36 @@ val SCE_JS_KEY=
val SCE_JS_LABEL=
# Lexical states for SCLEX_JAVA
lex Java=SCLEX_JAVA SCE_JAVA_
val SCE_JAVA_DEFAULT=0
val SCE_JAVA_COMMENTLINE=1
val SCE_JAVA_COMMENTLINEDOC=2
val SCE_JAVA_COMMENTBLOCK=3
val SCE_JAVA_COMMENTBLOCKDOC=4
val SCE_JAVA_COMMENTTAGAT=5
val SCE_JAVA_COMMENTTAGHTML=6
val SCE_JAVA_TASKMARKER=7
val SCE_JAVA_NUMBER=8
val SCE_JAVA_OPERATOR=9
val SCE_JAVA_CHARACTER=10
val SCE_JAVA_STRING=11
val SCE_JAVA_TRIPLE_STRING=12
val SCE_JAVA_ESCAPECHAR=13
val SCE_JAVA_FORMAT_SPECIFIER=14
val SCE_JAVA_PLACEHOLDER=15
val SCE_JAVA_ANNOTATION=16
val SCE_JAVA_IDENTIFIER=17
val SCE_JAVA_WORD=18
val SCE_JAVA_RECORD=19
val SCE_JAVA_WORD2=20
val SCE_JAVA_DIRECTIVE=21
val SCE_JAVA_CLASS=22
val SCE_JAVA_INTERFACE=23
val SCE_JAVA_ENUM=24
val SCE_JAVA_FUNCTION=25
val SCE_JAVA_CONSTANT=26
val SCE_JAVA_DEFAULT=
val SCE_JAVA_COMMENTLINE=
val SCE_JAVA_COMMENTLINEDOC=
val SCE_JAVA_COMMENTBLOCK=
val SCE_JAVA_COMMENTBLOCKDOC=
val SCE_JAVA_COMMENTTAGAT=
val SCE_JAVA_COMMENTTAGHTML=
val SCE_JAVA_TASKMARKER=
val SCE_JAVA_OPERATOR=
val SCE_JAVA_CHARACTER=
val SCE_JAVA_STRING=
val SCE_JAVA_TEMPLATE=
val SCE_JAVA_TRIPLE_TEMPLATE=
val SCE_JAVA_TRIPLE_STRING=
val SCE_JAVA_ESCAPECHAR=
val SCE_JAVA_FORMAT_SPECIFIER=
val SCE_JAVA_PLACEHOLDER=
val SCE_JAVA_OPERATOR2=
val SCE_JAVA_NUMBER=
val SCE_JAVA_ANNOTATION=
val SCE_JAVA_IDENTIFIER=
val SCE_JAVA_WORD=
val SCE_JAVA_RECORD=
val SCE_JAVA_WORD2=
val SCE_JAVA_DIRECTIVE=
val SCE_JAVA_CLASS=
val SCE_JAVA_INTERFACE=
val SCE_JAVA_ENUM=
val SCE_JAVA_FUNCTION=
val SCE_JAVA_CONSTANT=
val SCE_JAVA_FUNCTION_DEFINITION=
val SCE_JAVA_LABEL=
# Lexical states for SCLEX_HAXE
Expand Down
61 changes: 52 additions & 9 deletions scintilla/lexers/LexJava.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <string>
#include <string_view>
#include <vector>

#include "ILexer.h"
#include "Scintilla.h"
Expand All @@ -19,6 +20,7 @@
#include "CharacterSet.h"
#include "StringUtils.h"
#include "LexerModule.h"
#include "LexerUtils.h"

using namespace Lexilla;

Expand Down Expand Up @@ -89,12 +91,15 @@ enum class KeywordType {
While,
};

static_assert(DefaultNestedStateBaseStyle + 1 == SCE_JAVA_TEMPLATE);
static_assert(DefaultNestedStateBaseStyle + 2 == SCE_JAVA_TRIPLE_TEMPLATE);

constexpr bool IsSpaceEquiv(int state) noexcept {
return state <= SCE_JAVA_TASKMARKER;
}

// for java.util.Formatter
// https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/util/Formatter.html
// https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Formatter.html

constexpr bool IsFormatSpecifier(char ch) noexcept {
return AnyOf(ch, 'a', 'A',
Expand Down Expand Up @@ -186,6 +191,7 @@ void ColouriseJavaDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initSt

KeywordType kwType = KeywordType::None;
int chBeforeIdentifier = 0;
std::vector<int> nestedState; // string template STR."\{}"

int visibleChars = 0;
int chBefore = 0;
Expand All @@ -195,6 +201,18 @@ void ColouriseJavaDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initSt
EscapeSequence escSeq;

StyleContext sc(startPos, lengthDoc, initStyle, styler);
if (sc.currentLine > 0) {
int lineState = styler.GetLineState(sc.currentLine - 1);
/*
2: lineStateLineType
3: nestedState count
3*4: nestedState
*/
lineState >>= 8;
if (lineState) {
UnpackLineState(lineState, nestedState);
}
}
if (startPos == 0) {
if (sc.Match('#', '!')) {
// Shell Shebang at beginning of file
Expand All @@ -209,6 +227,7 @@ void ColouriseJavaDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initSt
while (sc.More()) {
switch (sc.state) {
case SCE_JAVA_OPERATOR:
case SCE_JAVA_OPERATOR2:
sc.SetState(SCE_JAVA_DEFAULT);
break;

Expand Down Expand Up @@ -409,11 +428,17 @@ void ColouriseJavaDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initSt

case SCE_JAVA_CHARACTER:
case SCE_JAVA_STRING:
case SCE_JAVA_TEMPLATE:
case SCE_JAVA_TRIPLE_TEMPLATE:
case SCE_JAVA_TRIPLE_STRING:
if (sc.atLineStart && sc.state != SCE_JAVA_TRIPLE_STRING) {
if (sc.atLineStart && sc.state <= SCE_JAVA_TEMPLATE) {
sc.SetState(SCE_JAVA_DEFAULT);
} else if (sc.ch == '\\') {
if (escSeq.resetEscapeState(sc.state, sc.chNext)) {
if (sc.chNext == '{' && AnyOf(sc.state, SCE_JAVA_TEMPLATE, SCE_JAVA_TRIPLE_TEMPLATE)) {
nestedState.push_back(sc.state);
sc.SetState(SCE_JAVA_OPERATOR2);
sc.Forward();
} else if (escSeq.resetEscapeState(sc.state, sc.chNext)) {
sc.SetState(SCE_JAVA_ESCAPECHAR);
sc.Forward();
}
Expand All @@ -434,8 +459,8 @@ void ColouriseJavaDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initSt
escSeq.outerState = sc.state;
sc.SetState(SCE_JAVA_PLACEHOLDER);
}
} else if (sc.ch == '"' && (sc.state == SCE_JAVA_STRING || sc.MatchNext('"', '"'))) {
if (sc.state == SCE_JAVA_TRIPLE_STRING) {
} else if (sc.ch == '"' && (sc.state <= SCE_JAVA_TEMPLATE || sc.MatchNext('"', '"'))) {
if (sc.state > SCE_JAVA_TEMPLATE) {
sc.Advance(2);
}
sc.ForwardSetState(SCE_JAVA_DEFAULT);
Expand All @@ -456,7 +481,7 @@ void ColouriseJavaDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initSt

case SCE_JAVA_PLACEHOLDER:
// for java.text.MessageFormat, only simplest form: {num}
// https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/text/MessageFormat.html
// https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/text/MessageFormat.html
if (!IsADigit(sc.ch)) {
if (sc.ch != '}') {
sc.Rewind();
Expand Down Expand Up @@ -488,10 +513,10 @@ void ColouriseJavaDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initSt
} else if (sc.ch == '\"') {
insideUrl = false;
if (sc.MatchNext('"', '"')) {
sc.SetState(SCE_JAVA_TRIPLE_STRING);
sc.SetState((sc.chPrev == '.') ? SCE_JAVA_TRIPLE_TEMPLATE : SCE_JAVA_TRIPLE_STRING);
sc.Advance(2);
} else {
sc.SetState(SCE_JAVA_STRING);
sc.SetState((sc.chPrev == '.') ? SCE_JAVA_TEMPLATE : SCE_JAVA_STRING);
}
} else if (sc.ch == '\'') {
sc.SetState(SCE_JAVA_CHARACTER);
Expand All @@ -507,6 +532,18 @@ void ColouriseJavaDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initSt
sc.SetState(SCE_JAVA_ANNOTATION);
} else if (IsAGraphic(sc.ch) && sc.ch != '\\') {
sc.SetState(SCE_JAVA_OPERATOR);
if (!nestedState.empty()) {
if (sc.ch == '{') {
nestedState.push_back(SCE_JAVA_DEFAULT);
} else if (sc.ch == '}') {
const int outerState = TakeAndPop(nestedState);
if (outerState != SCE_JAVA_DEFAULT) {
sc.ChangeState(SCE_JAVA_OPERATOR2);
}
sc.ForwardSetState(outerState);
continue;
}
}
}
}

Expand All @@ -517,6 +554,9 @@ void ColouriseJavaDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initSt
}
}
if (sc.atLineEnd) {
if (!nestedState.empty()) {
lineStateLineType |= PackLineState(nestedState) << 8;
}
styler.SetLineState(sc.currentLine, lineStateLineType);
lineStateLineType = 0;
visibleChars = 0;
Expand Down Expand Up @@ -549,12 +589,14 @@ constexpr bool IsStreamCommentStyle(int style) noexcept {

constexpr bool IsMultilineStringStyle(int style) noexcept {
return style == SCE_JAVA_TRIPLE_STRING
|| style == SCE_JAVA_TRIPLE_TEMPLATE
|| style == SCE_JAVA_OPERATOR2
|| style == SCE_JAVA_ESCAPECHAR
|| style == SCE_JAVA_FORMAT_SPECIFIER
|| style == SCE_JAVA_PLACEHOLDER;
}

void FoldJavaDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, LexerWordList, Accessor &styler) {
void FoldJavaDoc(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);
Expand Down Expand Up @@ -593,6 +635,7 @@ void FoldJavaDoc(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle,
break;

case SCE_JAVA_TRIPLE_STRING:
case SCE_JAVA_TRIPLE_TEMPLATE:
if (!IsMultilineStringStyle(stylePrev)) {
levelNext++;
} else if (!IsMultilineStringStyle(styleNext)) {
Expand Down
2 changes: 1 addition & 1 deletion src/EditLexers/stlGradle.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ static KEYWORDLIST Keywords_Gradle = {{
"false final finally for goto if implements import in instanceof interface it native new non-sealed null owner "
"package parcelable permits println private protected public record return "
"sealed static strictfp super switch synchronized this threadsafe throw throws trait transient true try var volatile "
"while yield "
"when while yield "

, // 1 types
"boolean byte char double float int long short void "
Expand Down
2 changes: 1 addition & 1 deletion src/EditLexers/stlGroovy.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ static KEYWORDLIST Keywords_Groovy = {{
"false final finally for goto if implements import in instanceof interface it native new non-sealed null owner "
"package parcelable permits println private protected public record return "
"sealed static strictfp super switch synchronized this threadsafe throw throws trait transient true try var volatile "
"while yield "
"when while yield "

, // 1 types
"boolean byte char double float int long short void "
Expand Down
10 changes: 5 additions & 5 deletions src/EditLexers/stlJava.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ static KEYWORDLIST Keywords_Java = {{
"abstract assert break case catch class const continue default do else enum extends false final finally for goto "
"if implements import instanceof interface native new non-sealed null "
"package parcelable permits private protected public record return sealed static strictfp super switch synchronized "
"this throw throws transient true try var volatile while yield "
"this throw throws transient true try var volatile when while yield "

, // 1 types
"boolean byte char double float int long short void "
Expand Down Expand Up @@ -103,14 +103,14 @@ static EDITSTYLE Styles_Java[] = {
{ MULTI_STYLE(SCE_JAVA_COMMENTLINEDOC, SCE_JAVA_COMMENTBLOCKDOC, 0, 0), NP2StyleX_DocComment, L"fore:#408040" },
{ MULTI_STYLE(SCE_JAVA_COMMENTTAGAT, SCE_JAVA_COMMENTTAGHTML, 0, 0), NP2StyleX_DocCommentTag, L"fore:#408080" },
{ SCE_JAVA_TASKMARKER, NP2StyleX_TaskMarker, L"bold; fore:#408080" },
{ MULTI_STYLE(SCE_JAVA_CHARACTER, SCE_JAVA_STRING, 0, 0), NP2StyleX_String, L"fore:#008000" },
{ SCE_JAVA_TRIPLE_STRING, NP2StyleX_TextBlock, L"fore:#F08000" },
{ MULTI_STYLE(SCE_JAVA_CHARACTER, SCE_JAVA_STRING, SCE_JAVA_TEMPLATE, 0), NP2StyleX_String, L"fore:#008000" },
{ MULTI_STYLE(SCE_JAVA_TRIPLE_STRING, SCE_JAVA_TRIPLE_TEMPLATE, 0, 0), NP2StyleX_TextBlock, L"fore:#F08000" },
{ SCE_JAVA_ESCAPECHAR, NP2StyleX_EscapeSequence, L"fore:#0080C0" },
{ SCE_JAVA_FORMAT_SPECIFIER, NP2StyleX_FormatSpecifier, L"fore:#7C5AF3" },
{ SCE_JAVA_PLACEHOLDER, NP2StyleX_Placeholder, L"fore:#8080FF" },
{ SCE_JAVA_LABEL, NP2StyleX_Label, L"back:#FFC040" },
{ SCE_JAVA_NUMBER, NP2StyleX_Number, L"fore:#FF0000" },
{ SCE_JAVA_OPERATOR, NP2StyleX_Operator, L"fore:#B000B0" },
{ MULTI_STYLE(SCE_JAVA_OPERATOR, SCE_JAVA_OPERATOR2, 0, 0), NP2StyleX_Operator, L"fore:#B000B0" },
};

EDITLEXER lexJava = {
Expand All @@ -124,7 +124,7 @@ EDITLEXER lexJava = {
'\\', SCE_JAVA_ESCAPECHAR, SCE_JAVA_FORMAT_SPECIFIER,
0,
SCE_JAVA_CHARACTER, 0,
SCE_JAVA_OPERATOR, 0
SCE_JAVA_OPERATOR, SCE_JAVA_OPERATOR2
, KeywordAttr32(0, KeywordAttr_PreSorted) // keywords
| KeywordAttr32(1, KeywordAttr_PreSorted) // types
| KeywordAttr32(2, KeywordAttr_PreSorted) // directive
Expand Down
2 changes: 1 addition & 1 deletion tools/LexerConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ class KeywordAttr(IntFlag):
'character_style': ['SCE_JAVA_CHARACTER'],
'angle_bracket_generic': True,
'generic_type_style': ['SCE_JAVA_CLASS', 'SCE_JAVA_INTERFACE', 'SCE_JAVA_ENUM'],
'operator_style': ['SCE_JAVA_OPERATOR'],
'operator_style': ['SCE_JAVA_OPERATOR', 'SCE_JAVA_OPERATOR2'],
'extra_word_char': '$:',
#'ignore_word_style': ['SCE_JAVA_WORD', 'SCE_JAVA_WORD2', 'SCE_JAVA_DIRECTIVE'],
'string_style_range': ['SCE_JAVA_CHARACTER', 'SCE_JAVA_PLACEHOLDER'],
Expand Down
Loading

0 comments on commit 70f91c9

Please sign in to comment.