1
1
mirror of https://github.com/oxalica/nil.git synced 2024-11-25 18:41:40 +03:00

Fine tuning token selection at given position

This commit is contained in:
oxalica 2023-10-19 11:21:55 +08:00
parent 1b6b4534b3
commit 26c5d73015

View File

@ -128,34 +128,43 @@ macro_rules! match_ast {
}}; }};
} }
/// Pick the most meaningful token at given cursor offset. /// Pick the most likely interested token at given cursor offset.
pub fn best_token_at_offset(node: &SyntaxNode, offset: TextSize) -> Option<SyntaxToken> { pub fn best_token_at_offset(node: &SyntaxNode, offset: TextSize) -> Option<SyntaxToken> {
fn score(tok: SyntaxKind) -> u8 { fn score(tok: SyntaxKind) -> u8 {
match tok { match tok {
SyntaxKind::ERROR | SyntaxKind::SPACE => 0, SyntaxKind::ERROR | SyntaxKind::SPACE => 0,
SyntaxKind::COMMENT => 1, SyntaxKind::COMMENT => 1,
// Avoid returning sibling delimiters, which may be in another region.
// Sorted by the nesting level in AST.
// `{ ...;|b = ... }`
T![;] | T![,] => 2,
T![=] | T![:] | T![@] => 3,
T!['('] | T!['['] | T!['{'] | T!["${"] | T![')'] | T![']'] | T!['}'] => 4,
// The rest are mostly operators, including `.` and `?`.
k if k.is_punct() => 5,
// Literal parts.
T!['"'] | T!["''"] => 10,
SyntaxKind::PATH_START SyntaxKind::PATH_START
| SyntaxKind::PATH_END | SyntaxKind::PATH_END
| SyntaxKind::PATH_FRAGMENT | SyntaxKind::PATH_FRAGMENT
| SyntaxKind::STRING_FRAGMENT => 2, | SyntaxKind::STRING_FRAGMENT => 11,
SyntaxKind::STRING_ESCAPE => 3, SyntaxKind::STRING_ESCAPE => 12,
k if k.is_punct() => 4,
k if k.is_keyword() => 5, // Atoms.
k if k.is_keyword() => 13,
// IDENT, INT, and etc. // IDENT, INT, and etc.
_ => 6, _ => 14,
} }
} }
match node.token_at_offset(offset) { match node.token_at_offset(offset) {
TokenAtOffset::None => None, TokenAtOffset::None => None,
TokenAtOffset::Single(tok) => Some(tok), TokenAtOffset::Single(tok) => Some(tok),
TokenAtOffset::Between(lhs, rhs) => { // Slightly prefer RHS for equal scores.
// Slightly prefer RHS. TokenAtOffset::Between(lhs, rhs) if score(lhs.kind()) > score(rhs.kind()) => Some(lhs),
if score(lhs.kind()) > score(rhs.kind()) { TokenAtOffset::Between(_, rhs) => Some(rhs),
Some(lhs)
} else {
Some(rhs)
}
}
} }
} }