1
1
mirror of https://github.com/oxalica/nil.git synced 2024-11-22 19:49:20 +03:00

Escape invalid identifiers in completions

This commit is contained in:
oxalica 2023-03-29 16:24:15 +08:00
parent 932803b1de
commit f3eaa77002

View File

@ -5,7 +5,7 @@ use builtin::{BuiltinKind, ALL_BUILTINS};
use either::Either::{Left, Right}; use either::Either::{Left, Right};
use smol_str::SmolStr; use smol_str::SmolStr;
use syntax::ast::{self, AstNode, Attr}; use syntax::ast::{self, AstNode, Attr};
use syntax::semantic::AttrKind; use syntax::semantic::{escape_literal_attr, is_valid_ident, AttrKind};
use syntax::{best_token_at_offset, match_ast, SyntaxKind, SyntaxNode, TextRange, T}; use syntax::{best_token_at_offset, match_ast, SyntaxKind, SyntaxNode, TextRange, T};
use super::hover::TY_DETAILED_DISPLAY; use super::hover::TY_DETAILED_DISPLAY;
@ -228,6 +228,7 @@ fn complete_expr(
.ancestors(scope_id) .ancestors(scope_id)
.filter_map(|scope| scope.as_definitions()) .filter_map(|scope| scope.as_definitions())
.flatten() .flatten()
.filter(|(text, _)| is_valid_ident(text))
.map(|(text, &name)| CompletionItem { .map(|(text, &name)| CompletionItem {
label: text.clone(), label: text.clone(),
source_range, source_range,
@ -321,14 +322,17 @@ fn complete_attrpath(
// We should not report current incomplete definition. // We should not report current incomplete definition.
// This is covered by `no_incomplete_field`. // This is covered by `no_incomplete_field`.
.filter(|name| *name != current_input) .filter(|name| *name != current_input)
.map(|name| CompletionItem { .map(|name| {
label: name.clone(), let escaped_name = escape_literal_attr(&name);
source_range, CompletionItem {
replace: name, label: escaped_name.as_ref().into(),
kind: CompletionItemKind::LetBinding, source_range,
signature: None, replace: escaped_name.into(),
description: None, kind: CompletionItemKind::LetBinding,
documentation: None, signature: None,
description: None,
documentation: None,
}
}), }),
); );
} }
@ -373,10 +377,12 @@ fn complete_attrpath(
return builtin_to_completion(source_range, name); return builtin_to_completion(source_range, name);
} }
let escaped_name = escape_literal_attr(name);
Some(CompletionItem { Some(CompletionItem {
label: name.clone(), label: escaped_name.as_ref().into(),
source_range, source_range,
replace: name.clone(), replace: escaped_name.into(),
kind: match src { kind: match src {
AttrSource::Unknown => CompletionItemKind::Field, AttrSource::Unknown => CompletionItemKind::Field,
AttrSource::Name(name) => module[name].kind.into(), AttrSource::Name(name) => module[name].kind.into(),
@ -835,4 +841,19 @@ stdenv.mkDerivation {
"enable", "enable",
); );
} }
#[test]
fn escape_attr() {
check(
r#"{ "foo/bar" = 1; }.f$0"#,
r#""foo/bar""#,
expect![[r#"(Field) { "foo/bar" = 1; }."foo/bar""#]],
);
}
#[test]
fn no_invalid_ident() {
check_no(r#"let "a b" = 1; in a$0"#, "a b");
check_no(r#"let "a b" = 1; in a$0"#, r#""a b""#);
}
} }