Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added GDScript Lexer support for % and $ symbols consistent with Godot Engine #146

Closed
wants to merge 17 commits into from
Closed
1 change: 1 addition & 0 deletions include/LexicalStyles.iface
Original file line number Diff line number Diff line change
Expand Up @@ -2305,3 +2305,4 @@ val SCE_GD_COMMENTBLOCK=12
val SCE_GD_STRINGEOL=13
val SCE_GD_WORD2=14
val SCE_GD_ANNOTATION=15
val SCE_GD_NODEPATH=16
1 change: 1 addition & 0 deletions include/SciLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2053,6 +2053,7 @@
#define SCE_GD_STRINGEOL 13
#define SCE_GD_WORD2 14
#define SCE_GD_ANNOTATION 15
#define SCE_GD_NODEPATH 16
/* --Autogenerated -- end of section automatically generated from Scintilla.iface */

#endif
43 changes: 41 additions & 2 deletions lexers/LexGDScript.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ int GetGDStringState(Accessor &styler, Sci_Position i, Sci_PositionU *nextIndex)
}
}

int GetGDStringState(int ch) {
if (ch != '"' && ch != '\'')
return SCE_GD_DEFAULT;

if (ch == '"')
return SCE_GD_STRING;
else
return SCE_GD_CHARACTER;
}

inline bool IsAWordChar(int ch, bool unicodeIdentifiers) {
if (IsASCII(ch))
return (IsAlphaNumeric(ch) || ch == '.' || ch == '_');
Expand All @@ -104,6 +114,16 @@ inline bool IsAWordChar(int ch, bool unicodeIdentifiers) {
return IsXidContinue(ch);
}

inline bool IsANodePathChar(int ch, bool unicodeIdentifiers) {
if (IsASCII(ch))
return (IsAlphaNumeric(ch) || ch == '_' || ch == '/' || ch =='%');

if (!unicodeIdentifiers)
return false;

return IsXidContinue(ch);
}

inline bool IsAWordStart(int ch, bool unicodeIdentifiers) {
if (IsASCII(ch))
return (IsUpperOrLowerCase(ch) || ch == '_');
Expand Down Expand Up @@ -209,6 +229,7 @@ LexicalClass lexicalClasses[] = {
13, "SCE_GD_STRINGEOL", "error literal string", "End of line where string is not closed",
14, "SCE_GD_WORD2", "identifier", "Highlighted identifiers",
15, "SCE_GD_ANNOTATION", "annotation", "Annotations",
16, "SCE_GD_NODEPATH", "path", "Node path",
};

}
Expand Down Expand Up @@ -390,7 +411,9 @@ void SCI_METHOD LexerGDScript::Lex(Sci_PositionU startPos, Sci_Position length,
bool indentGood = true;
Sci_Position startIndicator = sc.currentPos;
bool inContinuedString = false;

bool percentIsNodePath = false;
int nodePathStringState = SCE_GD_DEFAULT;

for (; sc.More(); sc.Forward()) {

if (sc.atLineStart) {
Expand All @@ -412,6 +435,7 @@ void SCI_METHOD LexerGDScript::Lex(Sci_PositionU startPos, Sci_Position length,
}

if (sc.atLineEnd) {
percentIsNodePath = false;
ProcessLineEnd(sc, inContinuedString);
lineCurrent++;
if (!sc.More())
Expand Down Expand Up @@ -479,6 +503,18 @@ void SCI_METHOD LexerGDScript::Lex(Sci_PositionU startPos, Sci_Position length,
if (!IsAWordStart(sc.ch, options.unicodeIdentifiers)) {
sc.SetState(SCE_GD_DEFAULT);
}
} else if (sc.state == SCE_GD_NODEPATH) {
if (nodePathStringState != SCE_GD_DEFAULT) {
if (sc.ch == GetGDStringQuoteChar(nodePathStringState) ) {
nodePathStringState = SCE_GD_DEFAULT;
}
} else {
if (IsGDStringStart(sc.ch)) {
nodePathStringState = GetGDStringState(sc.ch);
} else if (!IsANodePathChar(sc.ch, options.unicodeIdentifiers)) {
sc.SetState(SCE_GD_DEFAULT);
}
}
} else if (IsGDSingleQuoteStringState(sc.state)) {
if (sc.ch == '\\') {
if ((sc.chNext == '\r') && (sc.GetRelative(2) == '\n')) {
Expand Down Expand Up @@ -541,14 +577,17 @@ void SCI_METHOD LexerGDScript::Lex(Sci_PositionU startPos, Sci_Position length,
base_n_number = true;
sc.SetState(SCE_GD_NUMBER);
} else {
sc.SetState(SCE_GD_NUMBER);
sc.ForwardSetState(SCE_GD_IDENTIFIER);
}
} else {
base_n_number = false;
sc.SetState(SCE_GD_NUMBER);
}
} else if ((sc.ch == '$') || (sc.ch == '%' && (percentIsNodePath || IsFirstNonWhitespace(sc.currentPos, styler)))) {
percentIsNodePath = false;
sc.SetState(SCE_GD_NODEPATH);
} else if (isoperator(sc.ch) || sc.ch == '`') {
percentIsNodePath = !((sc.ch == ')') || (sc.ch == ']') || (sc.ch == '}'));
sc.SetState(SCE_GD_OPERATOR);
} else if (sc.ch == '#') {
sc.SetState(sc.chNext == '#' ? SCE_GD_COMMENTBLOCK : SCE_GD_COMMENTLINE);
Expand Down
4 changes: 4 additions & 0 deletions test/examples/gdscript/AllStyles.gd
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,7 @@ var hilight = 2
@onready
var a = 3
@onready var b = 3

# node-identifier=16
%node
$node
4 changes: 4 additions & 0 deletions test/examples/gdscript/AllStyles.gd.folded
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,8 @@
0 400 0 @onready
0 400 0 var a = 3
0 400 0 @onready var b = 3
1 400 0
0 400 0 # node-identifier=16
0 400 0 %node
0 400 0 $node
1 400 0
4 changes: 4 additions & 0 deletions test/examples/gdscript/AllStyles.gd.styled
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,7 @@
{15}@onready{0}
{5}var{0} {11}a{0} {10}={0} {2}3{0}
{15}@onready{0} {5}var{0} {11}b{0} {10}={0} {2}3{0}

{1}# node-identifier=16{0}
{16}%node{0}
{16}$node{0}
33 changes: 33 additions & 0 deletions test/examples/gdscript/NodePath.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# nodepath

$Node

%Node

%node/"n o d e"/%'n o d e'

%"No de"


$/root/ThisNode/%Node % %test

$MainMenuPanel/%Options % %test

%Options % %test

$Node % %test


get_node("%Options") % %test

$"Nod se" % %test

$/test/"No % de"/test % %test

%node/"n o d e"/'n o d e' % %"No De"

"%010d" % 12345

1 % 1

a % b
34 changes: 34 additions & 0 deletions test/examples/gdscript/NodePath.gd.folded
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
0 400 0 # nodepath
1 400 0
0 400 0 $Node
1 400 0
0 400 0 %Node
1 400 0
0 400 0 %node/"n o d e"/%'n o d e'
1 400 0
0 400 0 %"No de"
1 400 0
1 400 0
0 400 0 $/root/ThisNode/%Node % %test
1 400 0
0 400 0 $MainMenuPanel/%Options % %test
1 400 0
0 400 0 %Options % %test
1 400 0
0 400 0 $Node % %test
1 400 0
1 400 0
0 400 0 get_node("%Options") % %test
1 400 0
0 400 0 $"Nod se" % %test
1 400 0
0 400 0 $/test/"No % de"/test % %test
1 400 0
0 400 0 %node/"n o d e"/'n o d e' % %"No De"
1 400 0
0 400 0 "%010d" % 12345
1 400 0
0 400 0 1 % 1
1 400 0
0 400 0 a % b
1 400 0
33 changes: 33 additions & 0 deletions test/examples/gdscript/NodePath.gd.styled
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{1}# nodepath{0}

{16}$Node{0}

{16}%Node{0}

{16}%node/"n o d e"/%'n o d e'{0}

{16}%"No de"{0}


{16}$/root/ThisNode/%Node{0} {10}%{0} {16}%test{0}

{16}$MainMenuPanel/%Options{0} {10}%{0} {16}%test{0}

{16}%Options{0} {10}%{0} {16}%test{0}

{16}$Node{0} {10}%{0} {16}%test{0}


{11}get_node{10}({3}"%Options"{10}){0} {10}%{0} {16}%test{0}

{16}$"Nod se"{0} {10}%{0} {16}%test{0}

{16}$/test/"No % de"/test{0} {10}%{0} {16}%test{0}

{16}%node/"n o d e"/'n o d e'{0} {10}%{0} {16}%"No De"{0}

{3}"%010d"{0} {10}%{0} {2}12345{0}

{2}1{0} {10}%{0} {2}1{0}

{11}a{0} {10}%{0} {11}b{0}