mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-08-03 09:52:27 +00:00
feat: auto complete parameters after completing a function (#150)
* feat: auto complete parameters after completing a function * dev: update snapshot * dev: update completion snapshot
This commit is contained in:
parent
d71dd38b98
commit
bd610b2323
9 changed files with 69 additions and 24 deletions
|
@ -250,6 +250,7 @@ fn complete_path(
|
||||||
kind: CompletionKind::Folder,
|
kind: CompletionKind::Folder,
|
||||||
apply: None,
|
apply: None,
|
||||||
detail: None,
|
detail: None,
|
||||||
|
command: None,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
module_completions.push(Completion {
|
module_completions.push(Completion {
|
||||||
|
@ -257,6 +258,7 @@ fn complete_path(
|
||||||
kind: CompletionKind::Module,
|
kind: CompletionKind::Module,
|
||||||
apply: None,
|
apply: None,
|
||||||
detail: None,
|
detail: None,
|
||||||
|
command: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/base.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aa",
|
"label": "aa",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aa",
|
"newText": "aa(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 4,
|
"character": 4,
|
||||||
|
@ -131,7 +131,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/base.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aab",
|
"label": "aab",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aab",
|
"newText": "aab(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 4,
|
"character": 4,
|
||||||
|
@ -148,7 +148,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/base.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aabc",
|
"label": "aabc",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aabc",
|
"newText": "aabc(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 4,
|
"character": 4,
|
||||||
|
@ -165,7 +165,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/base.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aac",
|
"label": "aac",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aac",
|
"newText": "aac(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 4,
|
"character": 4,
|
||||||
|
@ -255,7 +255,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/base.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aabc",
|
"label": "aabc",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aabc",
|
"newText": "aabc(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 4,
|
"character": 4,
|
||||||
|
@ -272,7 +272,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/base.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aac",
|
"label": "aac",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aac",
|
"newText": "aac(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 4,
|
"character": 4,
|
||||||
|
|
|
@ -114,7 +114,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_params.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aa",
|
"label": "aa",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aa",
|
"newText": "aa(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 5,
|
"character": 5,
|
||||||
|
|
|
@ -114,7 +114,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/item_shadow.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aa",
|
"label": "aa",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aa",
|
"newText": "aa(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 4,
|
"character": 4,
|
||||||
|
@ -131,7 +131,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/item_shadow.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aac",
|
"label": "aac",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aac",
|
"newText": "aac(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 4,
|
"character": 4,
|
||||||
|
@ -221,7 +221,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/item_shadow.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aac",
|
"label": "aac",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aac",
|
"newText": "aac(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 4,
|
"character": 4,
|
||||||
|
|
|
@ -114,7 +114,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/let.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aa",
|
"label": "aa",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aa",
|
"newText": "aa(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 4,
|
"character": 4,
|
||||||
|
@ -165,7 +165,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/let.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aac",
|
"label": "aac",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aac",
|
"newText": "aac(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 4,
|
"character": 4,
|
||||||
|
@ -272,7 +272,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/let.typ
|
||||||
"kind": 3,
|
"kind": 3,
|
||||||
"label": "aac",
|
"label": "aac",
|
||||||
"textEdit": {
|
"textEdit": {
|
||||||
"newText": "aac",
|
"newText": "aac(${1:})",
|
||||||
"range": {
|
"range": {
|
||||||
"end": {
|
"end": {
|
||||||
"character": 4,
|
"character": 4,
|
||||||
|
|
|
@ -211,7 +211,7 @@ pub mod typst_to_lsp {
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use lsp_types::{
|
use lsp_types::{
|
||||||
CompletionTextEdit, Documentation, InsertTextFormat, LanguageString, MarkedString,
|
Command, CompletionTextEdit, Documentation, InsertTextFormat, LanguageString, MarkedString,
|
||||||
MarkupContent, MarkupKind, TextEdit,
|
MarkupContent, MarkupKind, TextEdit,
|
||||||
};
|
};
|
||||||
use regex::{Captures, Regex};
|
use regex::{Captures, Regex};
|
||||||
|
@ -312,6 +312,10 @@ pub mod typst_to_lsp {
|
||||||
detail: typst_completion.detail.as_ref().map(String::from),
|
detail: typst_completion.detail.as_ref().map(String::from),
|
||||||
text_edit: Some(text_edit),
|
text_edit: Some(text_edit),
|
||||||
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
|
command: typst_completion.command.as_ref().map(|c| Command {
|
||||||
|
command: c.to_string(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,10 +60,12 @@ pub struct Completion {
|
||||||
pub apply: Option<EcoString>,
|
pub apply: Option<EcoString>,
|
||||||
/// An optional short description, at most one sentence.
|
/// An optional short description, at most one sentence.
|
||||||
pub detail: Option<EcoString>,
|
pub detail: Option<EcoString>,
|
||||||
|
/// An optional command to run when the completion is selected.
|
||||||
|
pub command: Option<&'static str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A kind of item that can be completed.
|
/// A kind of item that can be completed.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub enum CompletionKind {
|
pub enum CompletionKind {
|
||||||
/// A syntactical structure.
|
/// A syntactical structure.
|
||||||
|
@ -394,6 +396,7 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value, styles:
|
||||||
eco_format!("{method}()${{}}")
|
eco_format!("{method}()${{}}")
|
||||||
}),
|
}),
|
||||||
detail: None,
|
detail: None,
|
||||||
|
command: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,6 +423,7 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value, styles:
|
||||||
label: modifier.into(),
|
label: modifier.into(),
|
||||||
apply: None,
|
apply: None,
|
||||||
detail: None,
|
detail: None,
|
||||||
|
command: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -454,6 +458,7 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value, styles:
|
||||||
label: name.clone(),
|
label: name.clone(),
|
||||||
apply: None,
|
apply: None,
|
||||||
detail: None,
|
detail: None,
|
||||||
|
command: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -987,6 +992,12 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
|
||||||
label: label.into(),
|
label: label.into(),
|
||||||
apply: Some(snippet.into()),
|
apply: Some(snippet.into()),
|
||||||
detail: Some(docs.into()),
|
detail: Some(docs.into()),
|
||||||
|
// 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: Some("editor.action.triggerSuggest"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1041,6 +1052,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
|
||||||
label: name.into(),
|
label: name.into(),
|
||||||
apply: Some(tags[0].into()),
|
apply: Some(tags[0].into()),
|
||||||
detail: Some(repr::separated_list(&tags, " or ").into()),
|
detail: Some(repr::separated_list(&tags, " or ").into()),
|
||||||
|
command: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1079,6 +1091,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
|
||||||
}),
|
}),
|
||||||
label: label.as_str().into(),
|
label: label.as_str().into(),
|
||||||
detail,
|
detail,
|
||||||
|
command: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1105,8 +1118,10 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut apply = None;
|
let mut apply = 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.triggerSuggest");
|
||||||
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"))
|
||||||
|
@ -1134,6 +1149,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
|
||||||
label,
|
label,
|
||||||
apply,
|
apply,
|
||||||
detail,
|
detail,
|
||||||
|
command,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1209,6 +1225,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
|
||||||
label: ty.long_name().into(),
|
label: ty.long_name().into(),
|
||||||
apply: Some(eco_format!("${{{ty}}}")),
|
apply: Some(eco_format!("${{{ty}}}")),
|
||||||
detail: Some(eco_format!("A value of type {ty}.")),
|
detail: Some(eco_format!("A value of type {ty}.")),
|
||||||
|
command: None,
|
||||||
});
|
});
|
||||||
self.scope_completions_(false, |value| value.ty() == *ty);
|
self.scope_completions_(false, |value| value.ty() == *ty);
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,12 +134,26 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
|
||||||
|
|
||||||
for (name, kind) in defined {
|
for (name, kind) in defined {
|
||||||
if !name.is_empty() {
|
if !name.is_empty() {
|
||||||
self.completions.push(Completion {
|
if kind == CompletionKind::Func {
|
||||||
kind,
|
// todo: check arguments, if empty, jump to after the parens
|
||||||
label: name,
|
let apply = eco_format!("{}(${{}})", name);
|
||||||
apply: None,
|
self.completions.push(Completion {
|
||||||
detail: None,
|
kind,
|
||||||
});
|
label: name,
|
||||||
|
apply: Some(apply),
|
||||||
|
detail: None,
|
||||||
|
// todo: only vscode and neovim (0.9.1) support this
|
||||||
|
command: Some("editor.action.triggerSuggest"),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.completions.push(Completion {
|
||||||
|
kind,
|
||||||
|
label: name,
|
||||||
|
apply: None,
|
||||||
|
detail: None,
|
||||||
|
command: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,6 +204,13 @@ pub fn param_completions<'a>(
|
||||||
label: param.name.clone().into(),
|
label: param.name.clone().into(),
|
||||||
apply: Some(eco_format!("{}: ${{}}", param.name)),
|
apply: Some(eco_format!("{}: ${{}}", param.name)),
|
||||||
detail: Some(plain_docs_sentence(¶m.docs)),
|
detail: Some(plain_docs_sentence(¶m.docs)),
|
||||||
|
// todo: only vscode and neovim (0.9.1) support this
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
command: Some("editor.action.triggerSuggest"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,12 +251,13 @@ pub fn named_param_value_completions<'a>(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(expr) = ¶m.type_repr {
|
if let Some(expr) = ¶m.expr {
|
||||||
ctx.completions.push(Completion {
|
ctx.completions.push(Completion {
|
||||||
kind: CompletionKind::Constant,
|
kind: CompletionKind::Constant,
|
||||||
label: expr.clone(),
|
label: expr.clone(),
|
||||||
apply: None,
|
apply: None,
|
||||||
detail: Some(plain_docs_sentence(¶m.docs)),
|
detail: Some(plain_docs_sentence(¶m.docs)),
|
||||||
|
command: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -375,7 +375,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:db5f6b70fa2cff5f0a58b4d11de387f9");
|
insta::assert_snapshot!(hash, @"siphash128_13:3a5dda1ab162b4cb843916a23f05ac0");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -386,7 +386,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:a4bb5a2f5705857f8fbd7f8f71ac86c9");
|
insta::assert_snapshot!(hash, @"siphash128_13:75e8e25d2b63fc959c024b5a509466d7");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue