feat: explicitly trigger suggest after completed import/include snippets (#984)

* feat: explicitly trigger suggest on completing import/include snippets

* fix: comment

* test: update snapshot
This commit is contained in:
Myriad-Dreamin 2024-12-11 14:40:57 +08:00 committed by GitHub
parent a86f7a494a
commit 5747dd6ba6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 87 additions and 40 deletions

View file

@ -145,13 +145,18 @@ impl Analysis {
AllocStats::report(self) 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. /// Get configured trigger parameter hints command.
pub fn trigger_parameter_hints(&self, context: bool) -> Option<&'static str> { pub fn trigger_parameter_hints(&self, context: bool) -> Option<&'static str> {
(self.completion_feat.trigger_parameter_hints && context) (self.completion_feat.trigger_parameter_hints && context)
.then_some("editor.action.triggerParameterHints") .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 /// > VS Code doesn't do that... Auto triggering suggestion only happens on
/// > typing (word starts or trigger characters). However, you can use /// > typing (word starts or trigger characters). However, you can use
@ -162,7 +167,7 @@ impl Analysis {
return None; 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. /// Get configured trigger on positional parameter hints command.

View file

@ -19,6 +19,12 @@ pub enum PostfixSnippetScope {
Content, 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)] #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, strum::EnumIter)]
pub enum SurroundingSyntax { pub enum SurroundingSyntax {
Regular, Regular,
@ -163,6 +169,8 @@ pub struct PrefixSnippet {
pub snippet: EcoString, pub snippet: EcoString,
/// The snippet description. /// The snippet description.
pub description: EcoString, pub description: EcoString,
/// The command to execute.
pub command: Option<CompletionCommand>,
/// Lazily expanded context. /// Lazily expanded context.
#[serde(skip)] #[serde(skip)]
pub expanded_context: OnceLock<HashSet<CompletionContextKey>>, pub expanded_context: OnceLock<HashSet<CompletionContextKey>>,
@ -235,6 +243,31 @@ impl From<&ConstPrefixSnippet> for Interned<PrefixSnippet> {
label_detail: None, label_detail: None,
snippet: snippet.snippet.into(), snippet: snippet.snippet.into(),
description: snippet.description.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<PrefixSnippet> {
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(), expanded_context: OnceLock::new(),
}) })
} }
@ -344,36 +377,6 @@ pub static DEFAULT_PREFIX_SNIPPET: LazyLock<Vec<Interned<PrefixSnippet>>> = Lazy
snippet: "return ${output}", snippet: "return ${output}",
description: "Returns early from a function.", 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 { ConstPrefixSnippet {
context: InterpretMode::Code, context: InterpretMode::Code,
label: "array literal", label: "array literal",
@ -502,7 +505,42 @@ pub static DEFAULT_PREFIX_SNIPPET: LazyLock<Vec<Interned<PrefixSnippet>>> = 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<Vec<PostfixSnippet>> = LazyLock::new(|| { pub static DEFAULT_POSTFIX_SNIPPET: LazyLock<Vec<PostfixSnippet>> = LazyLock::new(|| {

View file

@ -19,7 +19,8 @@ use super::{plain_docs_sentence, summarize_font_family};
use crate::adt::interner::Interned; use crate::adt::interner::Interned;
use crate::analysis::{analyze_labels, DynLabel, LocalContext, Ty}; use crate::analysis::{analyze_labels, DynLabel, LocalContext, Ty};
use crate::snippet::{ use crate::snippet::{
CompletionContextKey, PrefixSnippet, SurroundingSyntax, DEFAULT_PREFIX_SNIPPET, CompletionCommand, CompletionContextKey, PrefixSnippet, SurroundingSyntax,
DEFAULT_PREFIX_SNIPPET,
}; };
use crate::syntax::InterpretMode; use crate::syntax::InterpretMode;
@ -670,15 +671,18 @@ impl<'a> CompletionContext<'a> {
continue; 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 { self.completions.push(Completion {
kind: CompletionKind::Syntax, kind: CompletionKind::Syntax,
label: snippet.label.as_ref().into(), label: snippet.label.as_ref().into(),
apply: Some(snippet.snippet.as_ref().into()), apply: Some(snippet.snippet.as_ref().into()),
detail: Some(snippet.description.as_ref().into()), detail: Some(snippet.description.as_ref().into()),
command: self command,
.ctx
.analysis
.trigger_on_snippet(snippet.snippet.contains("${")),
..Completion::default() ..Completion::default()
}); });
} }

View file

@ -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:8cebcc89c1cbdaab64ad54fded330afb"); insta::assert_snapshot!(hash, @"siphash128_13:3305840819ce4ac8adbbc73890288188");
} }
{ {
@ -385,7 +385,7 @@ fn e2e() {
}); });
let hash = replay_log(&tinymist_binary, &root.join("vscode")); let hash = replay_log(&tinymist_binary, &root.join("vscode"));
insta::assert_snapshot!(hash, @"siphash128_13:6ee935b352766f1faebe86fac4cb77c1"); insta::assert_snapshot!(hash, @"siphash128_13:68d3c231276b454db893af55139d9cad");
} }
} }