diff options
| author | Said A. <47973576+Daaiid@users.noreply.github.com> | 2025-07-10 15:15:19 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-10 13:15:19 +0000 |
| commit | 70710deb2b813eacc79d57436f5bd4c15c215f2e (patch) | |
| tree | 2246cec18c94d3b52fd9f01e12848d9ea295431f | |
| parent | 275012d7c624be85173315286752888e20996072 (diff) | |
Deduplicate labels for code completion (#6516)
| -rw-r--r-- | crates/typst-ide/src/analyze.rs | 10 | ||||
| -rw-r--r-- | crates/typst-ide/src/complete.rs | 19 |
2 files changed, 27 insertions, 2 deletions
diff --git a/crates/typst-ide/src/analyze.rs b/crates/typst-ide/src/analyze.rs index 76739fec..e9fb8a7d 100644 --- a/crates/typst-ide/src/analyze.rs +++ b/crates/typst-ide/src/analyze.rs @@ -1,3 +1,5 @@ +use std::collections::HashSet; + use comemo::Track; use ecow::{eco_vec, EcoString, EcoVec}; use typst::foundations::{Label, Styles, Value}; @@ -66,14 +68,22 @@ pub fn analyze_import(world: &dyn IdeWorld, source: &LinkedNode) -> Option<Value /// - All labels and descriptions for them, if available /// - A split offset: All labels before this offset belong to nodes, all after /// belong to a bibliography. +/// +/// Note: When multiple labels in the document have the same identifier, +/// this only returns the first one. pub fn analyze_labels( document: &PagedDocument, ) -> (Vec<(Label, Option<EcoString>)>, usize) { let mut output = vec![]; + let mut seen_labels = HashSet::new(); // Labels in the document. for elem in document.introspector.all() { let Some(label) = elem.label() else { continue }; + if !seen_labels.insert(label) { + continue; + } + let details = elem .to_packed::<FigureElem>() .and_then(|figure| match figure.caption.as_option() { diff --git a/crates/typst-ide/src/complete.rs b/crates/typst-ide/src/complete.rs index bc5b3e10..0a560eb5 100644 --- a/crates/typst-ide/src/complete.rs +++ b/crates/typst-ide/src/complete.rs @@ -76,7 +76,7 @@ pub struct Completion { } /// A kind of item that can be completed. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum CompletionKind { /// A syntactical structure. @@ -1564,7 +1564,7 @@ mod tests { use typst::layout::PagedDocument; - use super::{autocomplete, Completion}; + use super::{autocomplete, Completion, CompletionKind}; use crate::tests::{FilePos, TestWorld, WorldLike}; /// Quote a string. @@ -1709,6 +1709,21 @@ mod tests { .must_exclude(["bib"]); } + #[test] + fn test_autocomplete_ref_identical_labels_returns_single_completion() { + let mut world = TestWorld::new("x<test> y<test>"); + let doc = typst::compile(&world).output.ok(); + + let end = world.main.text().len(); + world.main.edit(end..end, " @t"); + + let result = test_with_doc(&world, -1, doc.as_ref()); + let completions = result.completions(); + let label_count = + completions.iter().filter(|c| c.kind == CompletionKind::Label).count(); + assert_eq!(label_count, 1); + } + /// Test what kind of brackets we autocomplete for function calls depending /// on the function and existing parens. #[test] |
