mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-24 05:05:00 +00:00
feat: client-side control to whether issue completion callback (#744)
* feat: client-side control to whether issue completion callback * fix: bad changes
This commit is contained in:
parent
5dd1226cdc
commit
9c87fe2fb4
8 changed files with 87 additions and 15 deletions
|
@ -45,6 +45,12 @@ pub struct CompletionRequest {
|
||||||
pub position: LspPosition,
|
pub position: LspPosition,
|
||||||
/// Whether the completion is triggered explicitly.
|
/// Whether the completion is triggered explicitly.
|
||||||
pub explicit: bool,
|
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 {
|
impl StatefulRequest for CompletionRequest {
|
||||||
|
@ -131,7 +137,16 @@ impl StatefulRequest for CompletionRequest {
|
||||||
let is_incomplete = false;
|
let is_incomplete = false;
|
||||||
|
|
||||||
let mut items = completion_result.or_else(|| {
|
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
|
// Exclude it self from auto completion
|
||||||
// e.g. `#let x = (1.);`
|
// e.g. `#let x = (1.);`
|
||||||
|
@ -372,6 +387,9 @@ mod tests {
|
||||||
path: ctx.path_for_id(id).unwrap(),
|
path: ctx.path_for_id(id).unwrap(),
|
||||||
position: ctx.to_lsp_pos(s, &source),
|
position: ctx.to_lsp_pos(s, &source),
|
||||||
explicit: false,
|
explicit: false,
|
||||||
|
trigger_suggest: true,
|
||||||
|
trigger_parameter_hints: true,
|
||||||
|
trigger_named_completion: true,
|
||||||
};
|
};
|
||||||
results.push(request.request(ctx, doc.clone()).map(|resp| match resp {
|
results.push(request.request(ctx, doc.clone()).map(|resp| match resp {
|
||||||
CompletionResponse::List(l) => CompletionResponse::List(CompletionList {
|
CompletionResponse::List(l) => CompletionResponse::List(CompletionList {
|
||||||
|
|
|
@ -959,6 +959,9 @@ pub struct CompletionContext<'a, 'b> {
|
||||||
pub leaf: LinkedNode<'a>,
|
pub leaf: LinkedNode<'a>,
|
||||||
pub cursor: usize,
|
pub cursor: usize,
|
||||||
pub explicit: bool,
|
pub explicit: bool,
|
||||||
|
pub trigger_suggest: bool,
|
||||||
|
pub trigger_parameter_hints: bool,
|
||||||
|
pub trigger_named_completion: bool,
|
||||||
pub from: usize,
|
pub from: usize,
|
||||||
pub completions: Vec<Completion>,
|
pub completions: Vec<Completion>,
|
||||||
pub completions2: Vec<lsp_types::CompletionItem>,
|
pub completions2: Vec<lsp_types::CompletionItem>,
|
||||||
|
@ -970,12 +973,16 @@ pub struct CompletionContext<'a, 'b> {
|
||||||
|
|
||||||
impl<'a, 'w> CompletionContext<'a, 'w> {
|
impl<'a, 'w> CompletionContext<'a, 'w> {
|
||||||
/// Create a new autocompletion context.
|
/// Create a new autocompletion context.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ctx: &'a mut AnalysisContext<'w>,
|
ctx: &'a mut AnalysisContext<'w>,
|
||||||
document: Option<&'a Document>,
|
document: Option<&'a Document>,
|
||||||
source: &'a Source,
|
source: &'a Source,
|
||||||
cursor: usize,
|
cursor: usize,
|
||||||
explicit: bool,
|
explicit: bool,
|
||||||
|
trigger_suggest: bool,
|
||||||
|
trigger_parameter_hints: bool,
|
||||||
|
trigger_named_completion: bool,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let text = source.text();
|
let text = source.text();
|
||||||
let root = LinkedNode::new(source.root());
|
let root = LinkedNode::new(source.root());
|
||||||
|
@ -989,6 +996,9 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
|
||||||
root,
|
root,
|
||||||
leaf,
|
leaf,
|
||||||
cursor,
|
cursor,
|
||||||
|
trigger_suggest,
|
||||||
|
trigger_parameter_hints,
|
||||||
|
trigger_named_completion,
|
||||||
explicit,
|
explicit,
|
||||||
from: cursor,
|
from: cursor,
|
||||||
incomplete: true,
|
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
|
// 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
|
// starts or trigger characters). However, you can use editor.action.triggerSuggest as
|
||||||
// command on a suggestion to "manually" retrigger suggest after inserting one
|
// command on a suggestion to "manually" retrigger suggest after inserting one
|
||||||
//
|
command: (self.trigger_suggest && snippet.contains("${"))
|
||||||
// todo: only vscode and neovim (0.9.1) support this
|
|
||||||
command: snippet
|
|
||||||
.contains("${")
|
|
||||||
.then_some("editor.action.triggerSuggest"),
|
.then_some("editor.action.triggerSuggest"),
|
||||||
..Completion::default()
|
..Completion::default()
|
||||||
});
|
});
|
||||||
|
@ -1231,7 +1238,9 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
|
||||||
let mut command = None;
|
let mut command = None;
|
||||||
if parens && matches!(value, Value::Func(_)) {
|
if parens && matches!(value, Value::Func(_)) {
|
||||||
if let Value::Func(func) = value {
|
if let Value::Func(func) = value {
|
||||||
command = Some("editor.action.triggerParameterHints");
|
command = self
|
||||||
|
.trigger_parameter_hints
|
||||||
|
.then_some("editor.action.triggerParameterHints");
|
||||||
if func
|
if func
|
||||||
.params()
|
.params()
|
||||||
.is_some_and(|params| params.iter().all(|param| param.name == "self"))
|
.is_some_and(|params| params.iter().all(|param| param.name == "self"))
|
||||||
|
|
|
@ -308,8 +308,9 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
|
||||||
let base = Completion {
|
let base = Completion {
|
||||||
kind: kind.clone(),
|
kind: kind.clone(),
|
||||||
label_detail: ty_detail,
|
label_detail: ty_detail,
|
||||||
// todo: only vscode and neovim (0.9.1) support this
|
command: self
|
||||||
command: Some("editor.action.triggerParameterHints"),
|
.trigger_parameter_hints
|
||||||
|
.then_some("editor.action.triggerParameterHints"),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -648,7 +649,9 @@ pub fn param_completions<'a>(
|
||||||
apply: Some(eco_format!("{}: ${{}}", param.name)),
|
apply: Some(eco_format!("{}: ${{}}", param.name)),
|
||||||
detail: docs(),
|
detail: docs(),
|
||||||
label_detail: None,
|
label_detail: None,
|
||||||
command: Some("tinymist.triggerNamedCompletion"),
|
command: ctx
|
||||||
|
.trigger_named_completion
|
||||||
|
.then_some("tinymist.triggerNamedCompletion"),
|
||||||
..Completion::default()
|
..Completion::default()
|
||||||
};
|
};
|
||||||
match param.ty {
|
match param.ty {
|
||||||
|
@ -734,7 +737,9 @@ fn type_completion(
|
||||||
label: f.into(),
|
label: f.into(),
|
||||||
apply: Some(eco_format!("{}: ${{}}", f)),
|
apply: Some(eco_format!("{}: ${{}}", f)),
|
||||||
detail: docs.map(Into::into),
|
detail: docs.map(Into::into),
|
||||||
command: Some("tinymist.triggerNamedCompletion"),
|
command: ctx
|
||||||
|
.trigger_named_completion
|
||||||
|
.then_some("tinymist.triggerNamedCompletion"),
|
||||||
..Completion::default()
|
..Completion::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -301,6 +301,12 @@ pub struct Config {
|
||||||
pub formatter_mode: FormatterMode,
|
pub formatter_mode: FormatterMode,
|
||||||
/// Dynamic configuration for the experimental formatter.
|
/// Dynamic configuration for the experimental formatter.
|
||||||
pub formatter_print_width: Option<u32>,
|
pub formatter_print_width: Option<u32>,
|
||||||
|
/// 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 {
|
impl Config {
|
||||||
|
@ -349,12 +355,21 @@ impl Config {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// Errors if the update is invalid.
|
/// Errors if the update is invalid.
|
||||||
pub fn update_by_map(&mut self, update: &Map<String, JsonValue>) -> anyhow::Result<()> {
|
pub fn update_by_map(&mut self, update: &Map<String, JsonValue>) -> 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())
|
try_(|| SemanticTokensMode::deserialize(update.get("semanticTokens")?).ok())
|
||||||
.inspect(|v| self.semantic_tokens = *v);
|
.inspect(|v| self.semantic_tokens = *v);
|
||||||
try_(|| FormatterMode::deserialize(update.get("formatterMode")?).ok())
|
try_(|| FormatterMode::deserialize(update.get("formatterMode")?).ok())
|
||||||
.inspect(|v| self.formatter_mode = *v);
|
.inspect(|v| self.formatter_mode = *v);
|
||||||
try_(|| u32::deserialize(update.get("formatterPrintWidth")?).ok())
|
try_(|| u32::deserialize(update.get("formatterPrintWidth")?).ok())
|
||||||
.inspect(|v| self.formatter_print_width = Some(*v));
|
.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.update_by_map(update)?;
|
||||||
self.compile.validate()
|
self.compile.validate()
|
||||||
}
|
}
|
||||||
|
@ -479,9 +494,14 @@ impl CompileConfig {
|
||||||
|
|
||||||
/// Updates the configuration with a map.
|
/// Updates the configuration with a map.
|
||||||
pub fn update_by_map(&mut self, update: &Map<String, JsonValue>) -> anyhow::Result<()> {
|
pub fn update_by_map(&mut self, update: &Map<String, JsonValue>) -> anyhow::Result<()> {
|
||||||
self.output_path =
|
macro_rules! deser_or_default {
|
||||||
try_or_default(|| PathPattern::deserialize(update.get("outputPath")?).ok());
|
($key:expr, $ty:ty) => {
|
||||||
self.export_pdf = try_or_default(|| ExportMode::deserialize(update.get("exportPdf")?).ok());
|
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.root_path = try_(|| Some(update.get("rootPath")?.as_str()?.into()));
|
||||||
self.notify_status = match try_(|| update.get("compileStatus")?.as_str()) {
|
self.notify_status = match try_(|| update.get("compileStatus")?.as_str()) {
|
||||||
Some("enable") => true,
|
Some("enable") => true,
|
||||||
|
|
|
@ -750,8 +750,21 @@ impl LanguageState {
|
||||||
.context
|
.context
|
||||||
.map(|context| context.trigger_kind == CompletionTriggerKind::INVOKED)
|
.map(|context| context.trigger_kind == CompletionTriggerKind::INVOKED)
|
||||||
.unwrap_or(false);
|
.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(
|
fn signature_help(
|
||||||
|
|
|
@ -67,6 +67,10 @@ export async function doActivate(context: ExtensionContext): Promise<void> {
|
||||||
vscode.commands.executeCommand("setContext", "ext.tinymistActivated", true);
|
vscode.commands.executeCommand("setContext", "ext.tinymistActivated", true);
|
||||||
// Loads configuration
|
// Loads configuration
|
||||||
const config = loadTinymistConfig();
|
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
|
// Sets features
|
||||||
extensionState.features.preview = config.previewFeature === "enable";
|
extensionState.features.preview = config.previewFeature === "enable";
|
||||||
extensionState.features.devKit = isDevMode || config.devKit === "enable";
|
extensionState.features.devKit = isDevMode || config.devKit === "enable";
|
||||||
|
|
|
@ -374,7 +374,7 @@ fn e2e() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let hash = replay_log(&tinymist_binary, &root.join("neovim"));
|
let hash = replay_log(&tinymist_binary, &root.join("neovim"));
|
||||||
insta::assert_snapshot!(hash, @"siphash128_13:3032733ed0223012cd64233e662dcea2");
|
insta::assert_snapshot!(hash, @"siphash128_13:65fa45388648e656b1ec7cc30c48ad85");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -272,6 +272,9 @@
|
||||||
"noSystemFonts": null,
|
"noSystemFonts": null,
|
||||||
"typstExtraArgs": [],
|
"typstExtraArgs": [],
|
||||||
"trace": { "server": "off" },
|
"trace": { "server": "off" },
|
||||||
|
"triggerSuggest": true,
|
||||||
|
"triggerParameterHints": true,
|
||||||
|
"triggerNamedCompletion": true,
|
||||||
"experimentalFormatterMode": "disable"
|
"experimentalFormatterMode": "disable"
|
||||||
},
|
},
|
||||||
"trace": "off"
|
"trace": "off"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue