fix: complete import items on spaces, colons, and commas (#962)

* fix: import item complete

* fix: cursor better than start

* fix: strengthen snapshot

* fix: cases on empty import list

* feat: matches on comma in import list

* test: simplify testcases and update snapshots

---------

Co-authored-by: Myriad-Dreamin <camiyoru@gmail.com>
This commit is contained in:
Yifan Song 2024-12-08 04:54:33 +01:00 committed by GitHub
parent 9dd14d0232
commit 0464af6acf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 190 additions and 9 deletions

View file

@ -3,4 +3,5 @@
-----
/// contains: base,aa
#import "base.typ": /* range -1..1 */
#import "base.typ": /* range 0..1 */

View file

@ -0,0 +1,7 @@
/// path: base.typ
#let aa() = 1;
-----
/// contains: base,aa
#import "base.typ": /* range -1..1 */

View file

@ -0,0 +1,9 @@
/// path: base.typ
#let aa() = 1;
#let bcd() = 2;
-----
/// contains: base,aa,bcd
#import "base.typ": aa,/* range 0..1 */

View file

@ -0,0 +1,9 @@
/// path: base.typ
#let aa() = 1;
#let bcd() = 2;
-----
/// contains: base,aa,bcd
#import "base.typ": aa,
/* range -1..1 */

View file

@ -1,15 +1,11 @@
---
source: crates/tinymist-query/src/completion.rs
description: Completion on / (41..43)
description: Completion on / (42..43)
expression: "JsonRepr::new_pure(results)"
input_file: crates/tinymist-query/src/fixtures/completion/import_item.typ
snapshot_kind: text
---
[
{
"isIncomplete": false,
"items": []
},
{
"isIncomplete": false,
"items": [

View file

@ -0,0 +1,53 @@
---
source: crates/tinymist-query/src/completion.rs
description: Completion on / (41..43)
expression: "JsonRepr::new_pure(results)"
input_file: crates/tinymist-query/src/fixtures/completion/import_item_immediately_colon.typ
snapshot_kind: text
---
[
{
"isIncomplete": false,
"items": [
{
"kind": 3,
"label": "aa",
"textEdit": {
"newText": "aa",
"range": {
"end": {
"character": 19,
"line": 1
},
"start": {
"character": 19,
"line": 1
}
}
}
}
]
},
{
"isIncomplete": false,
"items": [
{
"kind": 3,
"label": "aa",
"textEdit": {
"newText": "aa",
"range": {
"end": {
"character": 20,
"line": 1
},
"start": {
"character": 20,
"line": 1
}
}
}
}
]
}
]

View file

@ -0,0 +1,31 @@
---
source: crates/tinymist-query/src/completion.rs
description: Completion on / (49..50)
expression: "JsonRepr::new_pure(results)"
input_file: crates/tinymist-query/src/fixtures/completion/import_item_immediately_comma.typ
snapshot_kind: text
---
[
{
"isIncomplete": false,
"items": [
{
"kind": 3,
"label": "bcd",
"textEdit": {
"newText": " bcd",
"range": {
"end": {
"character": 23,
"line": 1
},
"start": {
"character": 23,
"line": 1
}
}
}
}
]
}
]

View file

@ -0,0 +1,35 @@
---
source: crates/tinymist-query/src/completion.rs
description: "Completion on \n/ (49..51)"
expression: "JsonRepr::new_pure(results)"
input_file: crates/tinymist-query/src/fixtures/completion/import_item_mul_cross_line.typ
snapshot_kind: text
---
[
{
"isIncomplete": false,
"items": [
{
"kind": 3,
"label": "bcd",
"textEdit": {
"newText": " bcd",
"range": {
"end": {
"character": 23,
"line": 1
},
"start": {
"character": 23,
"line": 1
}
}
}
}
]
},
{
"isIncomplete": false,
"items": []
}
]

View file

@ -529,14 +529,37 @@ fn complete_imports(ctx: &mut CompletionContext) -> bool {
}
}
// On the colon marker of an import list:
// "#import "path.typ":|"
if_chain! {
if matches!(ctx.leaf.kind(), SyntaxKind::Colon);
if let Some(parent) = ctx.leaf.clone().parent();
if let Some(ast::Expr::Import(import)) = parent.get().cast();
if !matches!(import.imports(), Some(ast::Imports::Wildcard));
if let Some(source) = parent.children().find(|child| child.is::<ast::Expr>());
then {
let items = match import.imports() {
Some(ast::Imports::Items(items)) => items,
_ => Default::default(),
};
ctx.from = ctx.cursor;
import_item_completions(ctx, items, vec![], &source);
if items.iter().next().is_some() {
ctx.enrich("", ", ");
}
return true;
}
}
// Behind an import list:
// "#import "path.typ": |",
// "#import "path.typ": a, b, |".
if_chain! {
if let Some(prev) = ctx.leaf.prev_sibling();
if let Some(ast::Expr::Import(import)) = prev.get().cast();
if ctx.leaf.range().end <= prev.range().end ||
!ctx.text[prev.offset()..ctx.leaf.range().end].contains('\n');
if !ctx.text[prev.offset()..ctx.cursor].contains('\n');
if let Some(ast::Imports::Items(items)) = import.imports();
if let Some(source) = prev.children().find(|child| child.is::<ast::Expr>());
then {
@ -546,8 +569,25 @@ fn complete_imports(ctx: &mut CompletionContext) -> bool {
}
}
// Behind a comma in an import list:
// "#import "path.typ": this,|".
if_chain! {
if matches!(ctx.leaf.kind(), SyntaxKind::Comma);
if let Some(parent) = ctx.leaf.clone().parent();
if parent.kind() == SyntaxKind::ImportItems;
if let Some(grand) = parent.parent();
if let Some(ast::Expr::Import(import)) = grand.get().cast();
if let Some(ast::Imports::Items(items)) = import.imports();
if let Some(source) = grand.children().find(|child| child.is::<ast::Expr>());
then {
import_item_completions(ctx, items, vec![], &source);
ctx.enrich(" ", "");
return true;
}
}
// Behind a half-started identifier in an import list:
// "#import "path.typ": th|",
// "#import "path.typ": th|".
if_chain! {
if matches!(ctx.leaf.kind(), SyntaxKind::Ident | SyntaxKind::Dot);
if let Some(path_ctx) = ctx.leaf.clone().parent();