diff --git a/crates/tinymist-query/src/analysis/ty/post_check.rs b/crates/tinymist-query/src/analysis/ty/post_check.rs index 5343d589..a25b3cd5 100644 --- a/crates/tinymist-query/src/analysis/ty/post_check.rs +++ b/crates/tinymist-query/src/analysis/ty/post_check.rs @@ -197,6 +197,8 @@ impl<'a, 'w> PostTypeCheckWorker<'a, 'w> { log::debug!("post check paren target: {container_ty:?}::{is_before:?}"); let mut resp = SignatureReceiver::default(); + // todo: this is legal, but it makes it sometimes complete itself. + // e.g. completing `""` on `let x = ("|")` resp.bounds.lbs.push(container_ty.clone()); let target = ParamTarget::positional_from_before(true); diff --git a/crates/tinymist-query/src/completion.rs b/crates/tinymist-query/src/completion.rs index 4f85ffdb..c7fda9e4 100644 --- a/crates/tinymist-query/src/completion.rs +++ b/crates/tinymist-query/src/completion.rs @@ -6,7 +6,7 @@ use once_cell::sync::Lazy; use regex::{Captures, Regex}; use crate::{ - analysis::{BuiltinTy, Ty}, + analysis::{BuiltinTy, InsTy, Ty}, prelude::*, syntax::DerefTarget, upstream::{autocomplete, complete_path, CompletionContext}, @@ -132,7 +132,19 @@ impl StatefulRequest for CompletionRequest { let is_incomplete = false; let mut items = completion_result.or_else(|| { - let cc_ctx = CompletionContext::new(ctx, doc, &source, cursor, explicit)?; + let mut cc_ctx = CompletionContext::new(ctx, doc, &source, cursor, explicit)?; + + // Exclude it self from auto completion + // e.g. `#let x = (1.);` + let self_ty = cc_ctx.leaf.cast::().and_then(|exp| { + let v = cc_ctx.ctx.mini_eval(exp)?; + Some(Ty::Value(InsTy::new(v))) + }); + + if let Some(self_ty) = self_ty { + cc_ctx.seen_types.insert(self_ty); + }; + let (offset, ic, mut completions, completions_items2) = autocomplete(cc_ctx)?; if !completions_items2.is_empty() { completion_items_rest = Some(completions_items2); diff --git a/crates/tinymist-query/src/fixtures/completion/paren_string.typ b/crates/tinymist-query/src/fixtures/completion/paren_string.typ new file mode 100644 index 00000000..b994c9ee --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/paren_string.typ @@ -0,0 +1,2 @@ + +#let font-any = /* range after 3..4 */ (""); diff --git a/crates/tinymist-query/src/fixtures/completion/snaps/test@paren_string.typ.snap b/crates/tinymist-query/src/fixtures/completion/snaps/test@paren_string.typ.snap new file mode 100644 index 00000000..dd178e57 --- /dev/null +++ b/crates/tinymist-query/src/fixtures/completion/snaps/test@paren_string.typ.snap @@ -0,0 +1,12 @@ +--- +source: crates/tinymist-query/src/completion.rs +description: "Completion on \" (41..42)" +expression: "JsonRepr::new_pure(results)" +input_file: crates/tinymist-query/src/fixtures/completion/paren_string.typ +--- +[ + { + "isIncomplete": false, + "items": [] + } +] diff --git a/crates/tinymist-query/src/upstream/complete.rs b/crates/tinymist-query/src/upstream/complete.rs index 6af2ed5f..8278d279 100644 --- a/crates/tinymist-query/src/upstream/complete.rs +++ b/crates/tinymist-query/src/upstream/complete.rs @@ -18,7 +18,7 @@ use unscanny::Scanner; use super::{plain_docs_sentence, summarize_font_family}; use crate::adt::interner::Interned; -use crate::analysis::{analyze_expr, analyze_import, analyze_labels, DynLabel}; +use crate::analysis::{analyze_expr, analyze_import, analyze_labels, DynLabel, Ty}; use crate::AnalysisContext; mod ext; @@ -964,6 +964,7 @@ pub struct CompletionContext<'a, 'w> { pub completions2: Vec, pub incomplete: bool, pub seen_casts: HashSet, + pub seen_types: HashSet, pub seen_fields: HashSet>, } @@ -994,6 +995,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> { completions: vec![], completions2: vec![], seen_casts: HashSet::new(), + seen_types: HashSet::new(), seen_fields: HashSet::new(), }) } diff --git a/crates/tinymist-query/src/upstream/complete/ext.rs b/crates/tinymist-query/src/upstream/complete/ext.rs index 78ca1a8f..aa338b86 100644 --- a/crates/tinymist-query/src/upstream/complete/ext.rs +++ b/crates/tinymist-query/src/upstream/complete/ext.rs @@ -692,8 +692,10 @@ fn type_completion( docs: Option<&str>, ) -> Option<()> { // Prevent duplicate completions from appearing. - if !ctx.seen_casts.insert(typst::util::hash128(&infer_type)) { - return Some(()); + if let Some(infer_type) = infer_type { + if !ctx.seen_types.insert(infer_type.clone()) { + return Some(()); + } } log::info!("type_completion: {:?}", infer_type);