Skip to content

Commit c5ef368

Browse files
committed
Fix LSP semantic coloration bailing out sometimes
Step to reproduce: ``` xx := Window { TouchArea { clicked => { if (true) {} // note: because there is no else, the semantic colouring is bailing out now } } TouchArea { clicked => {} } } ``` This is caused by a bug in rowan::SyntaxToken::next_token that doesn't visit the next token if it has an empty node Unfortunately, the LSP has no tests, so I couldn't add one easily
1 parent 458c88c commit c5ef368

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

internal/compiler/parser.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,31 @@ impl SyntaxToken {
693693
pub fn parent(&self) -> SyntaxNode {
694694
SyntaxNode { node: self.token.parent().unwrap(), source_file: self.source_file.clone() }
695695
}
696+
pub fn next_token(&self) -> Option<SyntaxToken> {
697+
// Due to a bug (as of rowan 0.15.3), rowan::SyntaxToken::next_token doesn't work if a
698+
// sibling don't have tokens.
699+
// For example, if we have an expression like `if (true) {}` the
700+
// ConditionalExpression has an empty Expression/CodeBlock for the else part,
701+
// and next_token doesn't go into that.
702+
// So re-implement
703+
704+
let token = self
705+
.token
706+
.next_sibling_or_token()
707+
.and_then(|e| match e {
708+
rowan::NodeOrToken::Node(n) => n.first_token(),
709+
rowan::NodeOrToken::Token(t) => Some(t),
710+
})
711+
.or_else(|| {
712+
self.token.ancestors().find_map(|it| it.next_sibling_or_token()).and_then(|e| {
713+
match e {
714+
rowan::NodeOrToken::Node(n) => n.first_token(),
715+
rowan::NodeOrToken::Token(t) => Some(t),
716+
}
717+
})
718+
})?;
719+
Some(SyntaxToken { token, source_file: self.source_file.clone() })
720+
}
696721
}
697722

698723
impl std::fmt::Display for SyntaxToken {
@@ -745,6 +770,11 @@ impl SyntaxNode {
745770
pub fn parent(&self) -> Option<SyntaxNode> {
746771
self.node.parent().map(|node| SyntaxNode { node, source_file: self.source_file.clone() })
747772
}
773+
pub fn first_token(&self) -> Option<SyntaxToken> {
774+
self.node
775+
.first_token()
776+
.map(|token| SyntaxToken { token, source_file: self.source_file.clone() })
777+
}
748778
}
749779

750780
#[derive(Debug, Clone, derive_more::From)]

tools/lsp/semantic_tokens.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub fn get_semantic_tokens(
4444
SyntaxKind::StringLiteral => Some((self::STRING, 0)),
4545
SyntaxKind::NumberLiteral => Some((self::NUMBER, 0)),
4646
SyntaxKind::ColorLiteral => Some((self::NUMBER, 0)),
47-
SyntaxKind::Identifier => match token.parent()?.kind() {
47+
SyntaxKind::Identifier => match token.parent().kind() {
4848
SyntaxKind::Component => Some((self::KEYWORD, 0)),
4949
// the id of the element
5050
SyntaxKind::SubElement => Some((self::VARIABLE, 1 << self::DEFINITION)),
@@ -55,7 +55,7 @@ pub fn get_semantic_tokens(
5555
SyntaxKind::CallbackConnection => Some((self::FUNCTION, 0)),
5656
SyntaxKind::PropertyDeclaration => Some((self::KEYWORD, 0)),
5757
SyntaxKind::PropertyAnimation => Some((self::KEYWORD, 0)),
58-
SyntaxKind::QualifiedName => match token.parent()?.parent()?.kind() {
58+
SyntaxKind::QualifiedName => match token.parent().parent()?.kind() {
5959
SyntaxKind::Type => Some((self::TYPE, 0)),
6060
// the base type
6161
SyntaxKind::Element => Some((self::TYPE, 0)),
@@ -66,7 +66,7 @@ pub fn get_semantic_tokens(
6666
_ => None,
6767
},
6868
SyntaxKind::DeclaredIdentifier => {
69-
match token.parent()?.parent()?.kind() {
69+
match token.parent().parent()?.kind() {
7070
SyntaxKind::Component => Some((self::TYPE, 1 << self::DEFINITION)),
7171
SyntaxKind::RepeatedElement => {
7272
Some((self::PROPERTY, 1 << self::DEFINITION))
@@ -104,7 +104,7 @@ pub fn get_semantic_tokens(
104104
SyntaxKind::ExportIdentifier => {
105105
Some((
106106
self::TYPE,
107-
if token.parent()?.parent().map_or(false, |p| {
107+
if token.parent().parent().map_or(false, |p| {
108108
p.children().any(|n| n.kind() == SyntaxKind::ExportName)
109109
}) {
110110
0
@@ -118,7 +118,7 @@ pub fn get_semantic_tokens(
118118
SyntaxKind::ImportIdentifier => Some((self::KEYWORD, 0)),
119119
SyntaxKind::ExternalName => Some((
120120
self::TYPE,
121-
if token.parent()?.parent().map_or(false, |p| {
121+
if token.parent().parent().map_or(false, |p| {
122122
p.children().any(|n| n.kind() == SyntaxKind::InternalName)
123123
}) {
124124
0
@@ -141,7 +141,7 @@ pub fn get_semantic_tokens(
141141
| SyntaxKind::NotEqual
142142
| SyntaxKind::OrOr
143143
| SyntaxKind::AndAnd => Some((self::OPERATOR, 0)),
144-
SyntaxKind::LAngle | SyntaxKind::RAngle => (token.parent()?.kind()
144+
SyntaxKind::LAngle | SyntaxKind::RAngle => (token.parent().kind()
145145
== SyntaxKind::PropertyDeclaration)
146146
.then(|| (self::OPERATOR, 0)),
147147
SyntaxKind::Plus

0 commit comments

Comments
 (0)