From 9c87fe2fb4dd467845f1d3cc94a392000e44e677 Mon Sep 17 00:00:00 2001 From: Myriad-Dreamin <35292584+Myriad-Dreamin@users.noreply.github.com> Date: Tue, 29 Oct 2024 13:00:57 +0800 Subject: [PATCH] feat: client-side control to whether issue completion callback (#744) * feat: client-side control to whether issue completion callback * fix: bad changes --- crates/tinymist-query/src/completion.rs | 20 +++++++++++++- .../tinymist-query/src/upstream/complete.rs | 19 ++++++++++---- .../src/upstream/complete/ext.rs | 13 +++++++--- crates/tinymist/src/init.rs | 26 ++++++++++++++++--- crates/tinymist/src/server.rs | 15 ++++++++++- editors/vscode/src/extension.ts | 4 +++ tests/e2e/main.rs | 2 +- .../initialization/vscode-1.87.2.json | 3 +++ 8 files changed, 87 insertions(+), 15 deletions(-) diff --git a/crates/tinymist-query/src/completion.rs b/crates/tinymist-query/src/completion.rs index bad3209e..a42cc29f 100644 --- a/crates/tinymist-query/src/completion.rs +++ b/crates/tinymist-query/src/completion.rs @@ -45,6 +45,12 @@ pub struct CompletionRequest { pub position: LspPosition, /// Whether the completion is triggered explicitly. pub explicit: bool, + /// Whether to trigger suggest completion, a.k.a. auto-completion. + pub trigger_suggest: bool, + /// Whether to trigger named parameter completion. + pub trigger_named_completion: bool, + /// Whether to trigger parameter hint, a.k.a. signature help. + pub trigger_parameter_hints: bool, } impl StatefulRequest for CompletionRequest { @@ -131,7 +137,16 @@ impl StatefulRequest for CompletionRequest { let is_incomplete = false; let mut items = completion_result.or_else(|| { - let mut cc_ctx = CompletionContext::new(ctx, doc, &source, cursor, explicit)?; + let mut cc_ctx = CompletionContext::new( + ctx, + doc, + &source, + cursor, + explicit, + self.trigger_suggest, + self.trigger_parameter_hints, + self.trigger_named_completion, + )?; // Exclude it self from auto completion // e.g. `#let x = (1.);` @@ -372,6 +387,9 @@ mod tests { path: ctx.path_for_id(id).unwrap(), position: ctx.to_lsp_pos(s, &source), explicit: false, + trigger_suggest: true, + trigger_parameter_hints: true, + trigger_named_completion: true, }; results.push(request.request(ctx, doc.clone()).map(|resp| match resp { CompletionResponse::List(l) => CompletionResponse::List(CompletionList { diff --git a/crates/tinymist-query/src/upstream/complete.rs b/crates/tinymist-query/src/upstream/complete.rs index bc7522cc..09601e86 100644 --- a/crates/tinymist-query/src/upstream/complete.rs +++ b/crates/tinymist-query/src/upstream/complete.rs @@ -959,6 +959,9 @@ pub struct CompletionContext<'a, 'b> { pub leaf: LinkedNode<'a>, pub cursor: usize, pub explicit: bool, + pub trigger_suggest: bool, + pub trigger_parameter_hints: bool, + pub trigger_named_completion: bool, pub from: usize, pub completions: Vec, pub completions2: Vec, @@ -970,12 +973,16 @@ pub struct CompletionContext<'a, 'b> { impl<'a, 'w> CompletionContext<'a, 'w> { /// Create a new autocompletion context. + #[allow(clippy::too_many_arguments)] pub fn new( ctx: &'a mut AnalysisContext<'w>, document: Option<&'a Document>, source: &'a Source, cursor: usize, explicit: bool, + trigger_suggest: bool, + trigger_parameter_hints: bool, + trigger_named_completion: bool, ) -> Option { let text = source.text(); let root = LinkedNode::new(source.root()); @@ -989,6 +996,9 @@ impl<'a, 'w> CompletionContext<'a, 'w> { root, leaf, cursor, + trigger_suggest, + trigger_parameter_hints, + trigger_named_completion, explicit, from: cursor, incomplete: true, @@ -1032,10 +1042,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> { // VS Code doesn't do that... Auto triggering suggestion only happens on typing (word // starts or trigger characters). However, you can use editor.action.triggerSuggest as // command on a suggestion to "manually" retrigger suggest after inserting one - // - // todo: only vscode and neovim (0.9.1) support this - command: snippet - .contains("${") + command: (self.trigger_suggest && snippet.contains("${")) .then_some("editor.action.triggerSuggest"), ..Completion::default() }); @@ -1231,7 +1238,9 @@ impl<'a, 'w> CompletionContext<'a, 'w> { let mut command = None; if parens && matches!(value, Value::Func(_)) { if let Value::Func(func) = value { - command = Some("editor.action.triggerParameterHints"); + command = self + .trigger_parameter_hints + .then_some("editor.action.triggerParameterHints"); if func .params() .is_some_and(|params| params.iter().all(|param| param.name == "self")) diff --git a/crates/tinymist-query/src/upstream/complete/ext.rs b/crates/tinymist-query/src/upstream/complete/ext.rs index f6cb1c41..18d95c1e 100644 --- a/crates/tinymist-query/src/upstream/complete/ext.rs +++ b/crates/tinymist-query/src/upstream/complete/ext.rs @@ -308,8 +308,9 @@ impl<'a, 'w> CompletionContext<'a, 'w> { let base = Completion { kind: kind.clone(), label_detail: ty_detail, - // todo: only vscode and neovim (0.9.1) support this - command: Some("editor.action.triggerParameterHints"), + command: self + .trigger_parameter_hints + .then_some("editor.action.triggerParameterHints"), ..Default::default() }; @@ -648,7 +649,9 @@ pub fn param_completions<'a>( apply: Some(eco_format!("{}: ${{}}", param.name)), detail: docs(), label_detail: None, - command: Some("tinymist.triggerNamedCompletion"), + command: ctx + .trigger_named_completion + .then_some("tinymist.triggerNamedCompletion"), ..Completion::default() }; match param.ty { @@ -734,7 +737,9 @@ fn type_completion( label: f.into(), apply: Some(eco_format!("{}: ${{}}", f)), detail: docs.map(Into::into), - command: Some("tinymist.triggerNamedCompletion"), + command: ctx + .trigger_named_completion + .then_some("tinymist.triggerNamedCompletion"), ..Completion::default() }); } diff --git a/crates/tinymist/src/init.rs b/crates/tinymist/src/init.rs index 38b3f359..1904c06c 100644 --- a/crates/tinymist/src/init.rs +++ b/crates/tinymist/src/init.rs @@ -301,6 +301,12 @@ pub struct Config { pub formatter_mode: FormatterMode, /// Dynamic configuration for the experimental formatter. pub formatter_print_width: Option, + /// Whether to trigger suggest completion, a.k.a. auto-completion. + pub trigger_suggest: bool, + /// Whether to trigger named parameter completion. + pub trigger_named_completion: bool, + /// Whether to trigger parameter hint, a.k.a. signature help. + pub trigger_parameter_hints: bool, } impl Config { @@ -349,12 +355,21 @@ impl Config { /// # Errors /// Errors if the update is invalid. pub fn update_by_map(&mut self, update: &Map) -> anyhow::Result<()> { + macro_rules! deser_or_default { + ($key:expr, $ty:ty) => { + try_or_default(|| <$ty>::deserialize(update.get($key)?).ok()) + }; + } + try_(|| SemanticTokensMode::deserialize(update.get("semanticTokens")?).ok()) .inspect(|v| self.semantic_tokens = *v); try_(|| FormatterMode::deserialize(update.get("formatterMode")?).ok()) .inspect(|v| self.formatter_mode = *v); try_(|| u32::deserialize(update.get("formatterPrintWidth")?).ok()) .inspect(|v| self.formatter_print_width = Some(*v)); + self.trigger_suggest = deser_or_default!("triggerSuggest", bool); + self.trigger_parameter_hints = deser_or_default!("triggerParameterHints", bool); + self.trigger_named_completion = deser_or_default!("triggerNamedCompletion", bool); self.compile.update_by_map(update)?; self.compile.validate() } @@ -479,9 +494,14 @@ impl CompileConfig { /// Updates the configuration with a map. pub fn update_by_map(&mut self, update: &Map) -> anyhow::Result<()> { - self.output_path = - try_or_default(|| PathPattern::deserialize(update.get("outputPath")?).ok()); - self.export_pdf = try_or_default(|| ExportMode::deserialize(update.get("exportPdf")?).ok()); + macro_rules! deser_or_default { + ($key:expr, $ty:ty) => { + try_or_default(|| <$ty>::deserialize(update.get($key)?).ok()) + }; + } + + self.output_path = deser_or_default!("outputPath", PathPattern); + self.export_pdf = deser_or_default!("exportPdf", ExportMode); self.root_path = try_(|| Some(update.get("rootPath")?.as_str()?.into())); self.notify_status = match try_(|| update.get("compileStatus")?.as_str()) { Some("enable") => true, diff --git a/crates/tinymist/src/server.rs b/crates/tinymist/src/server.rs index eb62c2a3..ad924c5f 100644 --- a/crates/tinymist/src/server.rs +++ b/crates/tinymist/src/server.rs @@ -750,8 +750,21 @@ impl LanguageState { .context .map(|context| context.trigger_kind == CompletionTriggerKind::INVOKED) .unwrap_or(false); + let trigger_suggest = self.config.trigger_suggest; + let trigger_parameter_hints = self.config.trigger_parameter_hints; + let trigger_named_completion = self.config.trigger_named_completion; - run_query!(req_id, self.Completion(path, position, explicit)) + run_query!( + req_id, + self.Completion( + path, + position, + explicit, + trigger_suggest, + trigger_parameter_hints, + trigger_named_completion + ) + ) } fn signature_help( diff --git a/editors/vscode/src/extension.ts b/editors/vscode/src/extension.ts index a7fead20..8710d7d7 100644 --- a/editors/vscode/src/extension.ts +++ b/editors/vscode/src/extension.ts @@ -67,6 +67,10 @@ export async function doActivate(context: ExtensionContext): Promise { vscode.commands.executeCommand("setContext", "ext.tinymistActivated", true); // Loads configuration const config = loadTinymistConfig(); + // Inform server that we support named completion callback at the client side + config.triggerSuggest = true; + config.triggerNamedCompletion = true; + config.triggerParameterHints = true; // Sets features extensionState.features.preview = config.previewFeature === "enable"; extensionState.features.devKit = isDevMode || config.devKit === "enable"; diff --git a/tests/e2e/main.rs b/tests/e2e/main.rs index 1af18484..7e1f71d6 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:3032733ed0223012cd64233e662dcea2"); + insta::assert_snapshot!(hash, @"siphash128_13:65fa45388648e656b1ec7cc30c48ad85"); } { diff --git a/tests/fixtures/initialization/vscode-1.87.2.json b/tests/fixtures/initialization/vscode-1.87.2.json index 40d9cc0f..90eb500f 100644 --- a/tests/fixtures/initialization/vscode-1.87.2.json +++ b/tests/fixtures/initialization/vscode-1.87.2.json @@ -272,6 +272,9 @@ "noSystemFonts": null, "typstExtraArgs": [], "trace": { "server": "off" }, + "triggerSuggest": true, + "triggerParameterHints": true, + "triggerNamedCompletion": true, "experimentalFormatterMode": "disable" }, "trace": "off"