feat: append rest code completion result after param completed (#208)

* feat: append rest code completion result after param completed

* dev: update snapshot
This commit is contained in:
Myriad-Dreamin 2024-04-20 16:04:18 +08:00 committed by GitHub
parent f79a83e616
commit e54d74812e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 9762 additions and 37 deletions

View file

@ -11,6 +11,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args2.typ
{
"kind": 6,
"label": "class",
"sortText": "000",
"textEdit": {
"newText": " class: ${1:}",
"range": {
@ -28,6 +29,7 @@ input_file: crates/tinymist-query/src/fixtures/completion/func_args2.typ
{
"kind": 6,
"label": "font",
"sortText": "001",
"textEdit": {
"newText": " font: ${1:}",
"range": {

View file

@ -312,6 +312,7 @@ pub mod typst_to_lsp {
label: typst_completion.label.to_string(),
kind: Some(completion_kind(typst_completion.kind.clone())),
detail: typst_completion.detail.as_ref().map(String::from),
sort_text: typst_completion.sort_text.as_ref().map(String::from),
label_details: typst_completion.label_detail.as_ref().map(|e| {
CompletionItemLabelDetails {
detail: None,

View file

@ -54,7 +54,7 @@ pub fn autocomplete(
}
/// An autocompletion option.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Completion {
/// The kind of item this completes to.
pub kind: CompletionKind,
@ -62,6 +62,8 @@ pub struct Completion {
pub label: EcoString,
/// The label the completion is shown with.
pub label_detail: Option<EcoString>,
/// The label the completion is shown with.
pub sort_text: Option<EcoString>,
/// The completed version of the input, possibly described with snippet
/// syntax like `${lhs} + ${rhs}`.
///
@ -74,7 +76,7 @@ pub struct Completion {
}
/// A kind of item that can be completed.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "kebab-case")]
pub enum CompletionKind {
/// A syntactical structure.
@ -88,6 +90,7 @@ pub enum CompletionKind {
/// A field.
Field,
/// A constant.
#[default]
Constant,
/// A symbol.
Symbol(char),
@ -408,9 +411,7 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value, styles:
} else {
eco_format!("{method}()${{}}")
}),
detail: None,
label_detail: None,
command: None,
..Completion::default()
})
}
@ -435,10 +436,7 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value, styles:
ctx.completions.push(Completion {
kind: CompletionKind::Symbol(modified.get()),
label: modifier.into(),
apply: None,
detail: None,
label_detail: None,
command: None,
..Completion::default()
});
}
}
@ -471,10 +469,7 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value, styles:
ctx.completions.push(Completion {
kind: CompletionKind::Func,
label: name.clone(),
apply: None,
detail: None,
label_detail: None,
command: None,
..Completion::default()
})
}
}
@ -1034,6 +1029,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
//
// todo: only vscode and neovim (0.9.1) support this
command: Some("editor.action.triggerSuggest"),
..Completion::default()
});
}
@ -1088,8 +1084,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
label: name.into(),
apply: Some(tags[0].into()),
detail: Some(repr::separated_list(&tags, " or ").into()),
label_detail: None,
command: None,
..Completion::default()
});
}
}
@ -1128,8 +1123,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
}),
label: label.as_str().into(),
detail,
label_detail: None,
command: None,
..Completion::default()
});
}
}
@ -1189,6 +1183,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
detail,
label_detail: None,
command,
..Completion::default()
});
}
@ -1264,8 +1259,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
label: ty.long_name().into(),
apply: Some(eco_format!("${{{ty}}}")),
detail: Some(eco_format!("A value of type {ty}.")),
label_detail: None,
command: None,
..Completion::default()
});
self.scope_completions(false, |value| value.ty() == *ty);
}

View file

@ -17,6 +17,7 @@ use crate::analysis::{
FLOW_RADIUS_DICT, FLOW_STROKE_DICT,
};
use crate::syntax::{get_non_strict_def_target, param_index_at_leaf, DefTarget};
use crate::upstream::complete::complete_code;
use crate::upstream::plain_docs_sentence;
use crate::{prelude::*, typst_to_lsp::completion_kind, LspCompletion};
@ -157,20 +158,18 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
kind: kind.clone(),
label: eco_format!("{}.with", name),
apply: Some(apply),
detail: None,
label_detail: None,
// todo: only vscode and neovim (0.9.1) support this
command: Some("editor.action.triggerSuggest"),
..Default::default()
});
let apply = eco_format!("{}.where(${{}})", name);
self.completions.push(Completion {
kind: kind.clone(),
label: eco_format!("{}.where", name),
apply: Some(apply),
detail: None,
label_detail: None,
// todo: only vscode and neovim (0.9.1) support this
command: Some("editor.action.triggerSuggest"),
..Default::default()
});
// todo: check arguments, if empty, jump to after the parens
let apply = eco_format!("{}(${{}})", name);
@ -178,19 +177,15 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
kind: kind.clone(),
label: name,
apply: Some(apply),
detail: None,
label_detail: None,
// todo: only vscode and neovim (0.9.1) support this
command: Some("editor.action.triggerSuggest"),
..Completion::default()
});
} else {
self.completions.push(Completion {
kind,
label: name,
apply: None,
detail: None,
label_detail: None,
command: None,
..Completion::default()
});
}
}
@ -198,6 +193,58 @@ impl<'a, 'w> CompletionContext<'a, 'w> {
}
}
fn sort_and_explicit_code_completion(ctx: &mut CompletionContext) {
let mut completions = std::mem::take(&mut ctx.completions);
let explict = ctx.explicit;
ctx.explicit = true;
complete_code(ctx);
ctx.explicit = explict;
log::info!(
"sort_and_explicit_code_completion: {:#?} {:#?}",
completions,
ctx.completions
);
completions.sort_by(|a, b| {
a.sort_text
.as_ref()
.cmp(&b.sort_text.as_ref())
.then_with(|| a.label.cmp(&b.label))
});
ctx.completions.sort_by(|a, b| {
a.sort_text
.as_ref()
.cmp(&b.sort_text.as_ref())
.then_with(|| a.label.cmp(&b.label))
});
// todo: this is a bit messy, we can refactor for improving maintainability
// The messy code will finally gone, but to help us go over the mess stage, I
// drop some comment here.
//
// currently, there are only path completions in ctx.completions2
// and type/named param/positional param completions in completions
// and all rest less relevant completions inctx.completions
for (i, compl) in ctx.completions2.iter_mut().enumerate() {
compl.sort_text = Some(format!("{i:03}"));
}
let sort_base = ctx.completions2.len();
for (i, compl) in (completions.iter_mut().chain(ctx.completions.iter_mut())).enumerate() {
compl.sort_text = Some(eco_format!("{i:03}", i = i + sort_base));
}
log::info!(
"sort_and_explicit_code_completion after: {:#?} {:#?}",
completions,
ctx.completions
);
ctx.completions.append(&mut completions);
log::debug!("sort_and_explicit_code_completion: {:?}", ctx.completions);
}
/// Add completions for the parameters of a function.
pub fn param_completions<'a>(
ctx: &mut CompletionContext<'a, '_>,
@ -314,6 +361,7 @@ pub fn param_completions<'a>(
// editor.action.triggerSuggest as command on a suggestion to
// "manually" retrigger suggest after inserting one
command: Some("editor.action.triggerSuggest"),
..Completion::default()
};
match param.infer_type {
Some(FlowType::Builtin(FlowBuiltinType::TextSize)) => {
@ -356,6 +404,7 @@ pub fn param_completions<'a>(
}
}
sort_and_explicit_code_completion(ctx);
if ctx.before.ends_with(',') {
ctx.enrich(" ", "");
}
@ -465,7 +514,7 @@ fn type_completion(
apply: Some(eco_format!("\"{}\"", key.to_lowercase())),
detail: Some(detail),
label_detail: Some(desc.name.into()),
command: None,
..Completion::default()
});
}
}
@ -478,7 +527,7 @@ fn type_completion(
apply: Some(eco_format!("\"{}\"", key.to_lowercase())),
detail: Some(detail),
label_detail: Some(desc.name.into()),
command: None,
..Completion::default()
});
}
}
@ -570,8 +619,7 @@ fn type_completion(
label: ty.long_name().into(),
apply: Some(eco_format!("${{{ty}}}")),
detail: Some(eco_format!("A value of type {ty}.")),
label_detail: None,
command: None,
..Completion::default()
});
ctx.strict_scope_completions(false, |value| value.ty() == *ty);
}
@ -687,8 +735,7 @@ pub fn named_param_value_completions<'a>(
label: expr.clone(),
apply: None,
detail: doc.map(Into::into),
label_detail: None,
command: None,
..Completion::default()
});
}
}
@ -703,6 +750,7 @@ pub fn named_param_value_completions<'a>(
ctx.cast_completions(&param.input);
}
sort_and_explicit_code_completion(ctx);
if ctx.before.ends_with(':') {
ctx.enrich(" ", "");
}
@ -805,10 +853,9 @@ pub fn complete_literal(ctx: &mut CompletionContext) -> Option<()> {
kind: CompletionKind::Field,
label: key.clone(),
apply: Some(eco_format!("{}: ${{}}", key)),
detail: None,
label_detail: None,
// todo: only vscode and neovim (0.9.1) support this
command: Some("editor.action.triggerSuggest"),
..Completion::default()
});
}
}
@ -862,6 +909,7 @@ pub fn complete_literal(ctx: &mut CompletionContext) -> Option<()> {
}
ctx.incomplete = false;
sort_and_explicit_code_completion(ctx);
Some(())
}