diff --git a/crates/tinymist-query/src/analysis/global.rs b/crates/tinymist-query/src/analysis/global.rs index a6484327..8b6fe180 100644 --- a/crates/tinymist-query/src/analysis/global.rs +++ b/crates/tinymist-query/src/analysis/global.rs @@ -145,13 +145,18 @@ impl Analysis { AllocStats::report(self) } + /// Get configured trigger suggest command. + pub fn trigger_suggest(&self, context: bool) -> Option<&'static str> { + (self.completion_feat.trigger_suggest && context).then_some("editor.action.triggerSuggest") + } + /// Get configured trigger parameter hints command. pub fn trigger_parameter_hints(&self, context: bool) -> Option<&'static str> { (self.completion_feat.trigger_parameter_hints && context) .then_some("editor.action.triggerParameterHints") } - /// Get configured trigger after snippet command. + /// Get configured trigger suggest after snippet command. /// /// > VS Code doesn't do that... Auto triggering suggestion only happens on /// > typing (word starts or trigger characters). However, you can use @@ -162,7 +167,7 @@ impl Analysis { return None; } - (self.completion_feat.trigger_suggest && context).then_some("editor.action.triggerSuggest") + self.trigger_suggest(context) } /// Get configured trigger on positional parameter hints command. diff --git a/crates/tinymist-query/src/completion/snippet.rs b/crates/tinymist-query/src/completion/snippet.rs index 280fd38b..acedac14 100644 --- a/crates/tinymist-query/src/completion/snippet.rs +++ b/crates/tinymist-query/src/completion/snippet.rs @@ -19,6 +19,12 @@ pub enum PostfixSnippetScope { Content, } +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +#[serde(rename_all = "camelCase")] +pub enum CompletionCommand { + TriggerSuggest, +} + #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, strum::EnumIter)] pub enum SurroundingSyntax { Regular, @@ -163,6 +169,8 @@ pub struct PrefixSnippet { pub snippet: EcoString, /// The snippet description. pub description: EcoString, + /// The command to execute. + pub command: Option, /// Lazily expanded context. #[serde(skip)] pub expanded_context: OnceLock>, @@ -235,6 +243,31 @@ impl From<&ConstPrefixSnippet> for Interned { label_detail: None, snippet: snippet.snippet.into(), description: snippet.description.into(), + command: None, + expanded_context: OnceLock::new(), + }) + } +} + +struct ConstPrefixSnippetWithSuggest { + context: InterpretMode, + label: &'static str, + snippet: &'static str, + description: &'static str, +} + +impl From<&ConstPrefixSnippetWithSuggest> for Interned { + fn from(snippet: &ConstPrefixSnippetWithSuggest) -> Self { + Interned::new(PrefixSnippet { + context: eco_vec![CompletionContext { + mode: ContextSelector::Positive(Some(snippet.context)), + syntax: ContextSelector::Positive(None), + }], + label: snippet.label.into(), + label_detail: None, + snippet: snippet.snippet.into(), + description: snippet.description.into(), + command: Some(CompletionCommand::TriggerSuggest), expanded_context: OnceLock::new(), }) } @@ -344,36 +377,6 @@ pub static DEFAULT_PREFIX_SNIPPET: LazyLock>> = Lazy snippet: "return ${output}", description: "Returns early from a function.", }, - ConstPrefixSnippet { - context: InterpretMode::Code, - label: "import module", - snippet: "import \"${}\"", - description: "Imports module from another file.", - }, - ConstPrefixSnippet { - context: InterpretMode::Code, - label: "import module by expression", - snippet: "import ${}", - description: "Imports items by expression.", - }, - ConstPrefixSnippet { - context: InterpretMode::Code, - label: "import package", - snippet: "import \"@${}\": ${items}", - description: "Imports variables from another file.", - }, - ConstPrefixSnippet { - context: InterpretMode::Code, - label: "include (file)", - snippet: "include \"${file}.typ\"", - description: "Includes content from another file.", - }, - ConstPrefixSnippet { - context: InterpretMode::Code, - label: "include (package)", - snippet: "include \"@${}\"", - description: "Includes content from another file.", - }, ConstPrefixSnippet { context: InterpretMode::Code, label: "array literal", @@ -502,7 +505,42 @@ pub static DEFAULT_PREFIX_SNIPPET: LazyLock>> = Lazy }, ]; - SNIPPETS.iter().map(From::from).collect() + const SNIPPET_SUGGEST: &[ConstPrefixSnippetWithSuggest] = &[ + ConstPrefixSnippetWithSuggest { + context: InterpretMode::Code, + label: "import module", + snippet: "import \"${}\"", + description: "Imports module from another file.", + }, + ConstPrefixSnippetWithSuggest { + context: InterpretMode::Code, + label: "import module by expression", + snippet: "import ${}", + description: "Imports items by expression.", + }, + ConstPrefixSnippetWithSuggest { + context: InterpretMode::Code, + label: "import (package)", + snippet: "import \"@${}\"", + description: "Imports variables from another file.", + }, + ConstPrefixSnippetWithSuggest { + context: InterpretMode::Code, + label: "include (file)", + snippet: "include \"${}\"", + description: "Includes content from another file.", + }, + ConstPrefixSnippetWithSuggest { + context: InterpretMode::Code, + label: "include (package)", + snippet: "include \"@${}\"", + description: "Includes content from another file.", + }, + ]; + + let snippets = SNIPPETS.iter().map(From::from); + let snippets2 = SNIPPET_SUGGEST.iter().map(From::from); + snippets.chain(snippets2).collect() }); pub static DEFAULT_POSTFIX_SNIPPET: LazyLock> = LazyLock::new(|| { diff --git a/crates/tinymist-query/src/upstream/complete.rs b/crates/tinymist-query/src/upstream/complete.rs index 2cec9ac5..bb0a561b 100644 --- a/crates/tinymist-query/src/upstream/complete.rs +++ b/crates/tinymist-query/src/upstream/complete.rs @@ -19,7 +19,8 @@ use super::{plain_docs_sentence, summarize_font_family}; use crate::adt::interner::Interned; use crate::analysis::{analyze_labels, DynLabel, LocalContext, Ty}; use crate::snippet::{ - CompletionContextKey, PrefixSnippet, SurroundingSyntax, DEFAULT_PREFIX_SNIPPET, + CompletionCommand, CompletionContextKey, PrefixSnippet, SurroundingSyntax, + DEFAULT_PREFIX_SNIPPET, }; use crate::syntax::InterpretMode; @@ -670,15 +671,18 @@ impl<'a> CompletionContext<'a> { continue; } + let analysis = &self.ctx.analysis; + let command = match snippet.command { + Some(CompletionCommand::TriggerSuggest) => analysis.trigger_suggest(true), + None => analysis.trigger_on_snippet(snippet.snippet.contains("${")), + }; + self.completions.push(Completion { kind: CompletionKind::Syntax, label: snippet.label.as_ref().into(), apply: Some(snippet.snippet.as_ref().into()), detail: Some(snippet.description.as_ref().into()), - command: self - .ctx - .analysis - .trigger_on_snippet(snippet.snippet.contains("${")), + command, ..Completion::default() }); } diff --git a/tests/e2e/main.rs b/tests/e2e/main.rs index 06c7368f..964a3e94 100644 --- a/tests/e2e/main.rs +++ b/tests/e2e/main.rs @@ -374,7 +374,7 @@ fn e2e() { }); let hash = replay_log(&tinymist_binary, &root.join("neovim")); - insta::assert_snapshot!(hash, @"siphash128_13:8cebcc89c1cbdaab64ad54fded330afb"); + insta::assert_snapshot!(hash, @"siphash128_13:3305840819ce4ac8adbbc73890288188"); } { @@ -385,7 +385,7 @@ fn e2e() { }); let hash = replay_log(&tinymist_binary, &root.join("vscode")); - insta::assert_snapshot!(hash, @"siphash128_13:6ee935b352766f1faebe86fac4cb77c1"); + insta::assert_snapshot!(hash, @"siphash128_13:68d3c231276b454db893af55139d9cad"); } }