mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-24 13:13:43 +00:00
fix: match identifier like nodes for completion (#747)
* fix: match identifier like nodes for completion * test: update snapshot
This commit is contained in:
parent
9385b95c81
commit
e8f5f6185a
7 changed files with 68 additions and 22 deletions
|
@ -4,11 +4,12 @@ use lsp_types::{
|
|||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::{Captures, Regex};
|
||||
use typst_shim::syntax::LinkedNodeExt;
|
||||
|
||||
use crate::{
|
||||
analysis::{BuiltinTy, InsTy, Ty},
|
||||
prelude::*,
|
||||
syntax::DerefTarget,
|
||||
syntax::{is_ident_like, DerefTarget},
|
||||
upstream::{autocomplete, complete_path, CompletionContext},
|
||||
StatefulRequest,
|
||||
};
|
||||
|
@ -96,13 +97,14 @@ impl StatefulRequest for CompletionRequest {
|
|||
}
|
||||
|
||||
// Do some completion specific to the deref target
|
||||
let mut match_ident = None;
|
||||
let mut ident_like = None;
|
||||
let mut completion_result = None;
|
||||
let is_callee = matches!(deref_target, Some(DerefTarget::Callee(..)));
|
||||
match deref_target {
|
||||
Some(DerefTarget::Callee(v) | DerefTarget::VarAccess(v)) => {
|
||||
if v.is::<ast::Ident>() {
|
||||
match_ident = Some(v);
|
||||
Some(DerefTarget::Callee(..) | DerefTarget::VarAccess(..)) => {
|
||||
let node = LinkedNode::new(source.root()).leaf_at_compat(cursor)?;
|
||||
if is_ident_like(&node) {
|
||||
ident_like = Some(node);
|
||||
}
|
||||
}
|
||||
Some(DerefTarget::ImportPath(v) | DerefTarget::IncludePath(v)) => {
|
||||
|
@ -169,9 +171,9 @@ impl StatefulRequest for CompletionRequest {
|
|||
let _ = ic;
|
||||
|
||||
let replace_range;
|
||||
if match_ident.as_ref().is_some_and(|i| i.offset() == offset) {
|
||||
let match_ident = match_ident.unwrap();
|
||||
let mut rng = match_ident.range();
|
||||
if ident_like.as_ref().is_some_and(|i| i.offset() == offset) {
|
||||
let ident_like = ident_like.unwrap();
|
||||
let mut rng = ident_like.range();
|
||||
let ident_prefix = source.text()[rng.start..cursor].to_string();
|
||||
|
||||
completions.retain(|c| {
|
||||
|
@ -191,7 +193,7 @@ impl StatefulRequest for CompletionRequest {
|
|||
});
|
||||
|
||||
// if modifying some arguments, we need to truncate and add a comma
|
||||
if !is_callee && cursor != rng.end && is_arg_like_context(&match_ident) {
|
||||
if !is_callee && cursor != rng.end && is_arg_like_context(&ident_like) {
|
||||
// extend comma
|
||||
for c in completions.iter_mut() {
|
||||
let apply = match &mut c.apply {
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
// contains: inset
|
||||
#set block(in /* range -2..-1 */)
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
source: crates/tinymist-query/src/completion.rs
|
||||
description: Completion on n (31..32)
|
||||
expression: "JsonRepr::new_pure(results)"
|
||||
input_file: crates/tinymist-query/src/fixtures/completion/keyword_ident.typ
|
||||
---
|
||||
[
|
||||
{
|
||||
"isIncomplete": false,
|
||||
"items": [
|
||||
{
|
||||
"kind": 5,
|
||||
"label": "inset",
|
||||
"sortText": "007",
|
||||
"textEdit": {
|
||||
"newText": "inset: ${1:}",
|
||||
"range": {
|
||||
"end": {
|
||||
"character": 13,
|
||||
"line": 1
|
||||
},
|
||||
"start": {
|
||||
"character": 11,
|
||||
"line": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -1,6 +1,7 @@
|
|||
pub use std::{
|
||||
collections::HashMap,
|
||||
iter,
|
||||
ops::Range,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
|
@ -26,7 +27,7 @@ pub use typst::foundations::Value;
|
|||
pub use typst::syntax::FileId as TypstFileId;
|
||||
pub use typst::syntax::{
|
||||
ast::{self, AstNode},
|
||||
LinkedNode, Source, Spanned, SyntaxKind,
|
||||
LinkedNode, Source, Spanned, SyntaxKind, SyntaxNode,
|
||||
};
|
||||
pub use typst::World;
|
||||
|
||||
|
|
|
@ -1,14 +1,7 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use ecow::EcoVec;
|
||||
use serde::Serialize;
|
||||
use typst::{
|
||||
foundations::{Func, ParamInfo},
|
||||
syntax::{
|
||||
ast::{self, AstNode},
|
||||
LinkedNode, SyntaxKind,
|
||||
},
|
||||
};
|
||||
use typst::foundations::{Func, ParamInfo};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn deref_expr(mut ancestor: LinkedNode) -> Option<LinkedNode> {
|
||||
while !ancestor.is::<ast::Expr>() {
|
||||
|
@ -87,6 +80,18 @@ fn is_mark(sk: SyntaxKind) -> bool {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn is_ident_like(node: &SyntaxNode) -> bool {
|
||||
use SyntaxKind::*;
|
||||
let k = node.kind();
|
||||
matches!(k, Ident | MathIdent | Underscore)
|
||||
|| (matches!(k, Error) && can_be_ident(node))
|
||||
|| k.is_keyword()
|
||||
}
|
||||
|
||||
fn can_be_ident(node: &SyntaxNode) -> bool {
|
||||
typst::syntax::is_ident(node.text())
|
||||
}
|
||||
|
||||
/// A mode in which a text document is interpreted.
|
||||
#[derive(Debug, Clone, Copy, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
|
|
@ -14,7 +14,7 @@ use typst::visualize::Color;
|
|||
use super::{Completion, CompletionContext, CompletionKind};
|
||||
use crate::adt::interner::Interned;
|
||||
use crate::analysis::{resolve_call_target, BuiltinTy, PathPreference, Ty};
|
||||
use crate::syntax::{param_index_at_leaf, CheckTarget};
|
||||
use crate::syntax::{is_ident_like, param_index_at_leaf, CheckTarget};
|
||||
use crate::upstream::complete::complete_code;
|
||||
use crate::upstream::plain_docs_sentence;
|
||||
|
||||
|
@ -1083,6 +1083,11 @@ pub(crate) fn complete_type(ctx: &mut CompletionContext) -> Option<()> {
|
|||
.literal_type_of_node(ctx.leaf.clone())
|
||||
.filter(|ty| !matches!(ty, Ty::Any))?;
|
||||
|
||||
// adjust the completion position
|
||||
if is_ident_like(&ctx.leaf) {
|
||||
ctx.from = ctx.leaf.offset();
|
||||
}
|
||||
|
||||
log::debug!("complete_type: ty {:?} -> {ty:#?}", ctx.leaf);
|
||||
|
||||
type_completion(ctx, &ty, None);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue