feat: complete parameter values on user functions (#149)

* feat: complete parameter values on user functions

* dev: separate type/value repr in parameter analysis
This commit is contained in:
Myriad-Dreamin 2024-04-02 17:52:15 +08:00 committed by GitHub
parent d708bdfe2d
commit d71dd38b98
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 63 additions and 35 deletions

View file

@ -220,7 +220,9 @@ pub struct ParamSpec {
pub docs: Cow<'static, str>,
/// Describe what values this parameter accepts.
pub input: CastInfo,
/// The parameter's default name.
/// The parameter's default name as type.
pub type_repr: Option<EcoString>,
/// The parameter's default name as value.
pub expr: Option<EcoString>,
/// Creates an instance of the parameter's default value.
pub default: Option<fn() -> Value>,
@ -243,7 +245,8 @@ impl ParamSpec {
name: Cow::Borrowed(s.name),
docs: Cow::Borrowed(s.docs),
input: s.input.clone(),
expr: Some(eco_format!("{}", TypeExpr(&s.input))),
type_repr: Some(eco_format!("{}", TypeExpr(&s.input))),
expr: None,
default: s.default,
positional: s.positional,
named: s.named,
@ -343,6 +346,7 @@ fn analyze_closure_signature(c: Arc<LazyHash<Closure>>) -> Vec<Arc<ParamSpec>> {
params.push(Arc::new(ParamSpec {
name: Cow::Borrowed("_"),
input: CastInfo::Any,
type_repr: None,
expr: None,
default: None,
positional: true,
@ -363,6 +367,7 @@ fn analyze_closure_signature(c: Arc<LazyHash<Closure>>) -> Vec<Arc<ParamSpec>> {
params.push(Arc::new(ParamSpec {
name: Cow::Owned(name.to_owned()),
input: CastInfo::Any,
type_repr: None,
expr: None,
default: None,
positional: true,
@ -378,6 +383,7 @@ fn analyze_closure_signature(c: Arc<LazyHash<Closure>>) -> Vec<Arc<ParamSpec>> {
params.push(Arc::new(ParamSpec {
name: Cow::Owned(n.name().as_str().to_owned()),
input: CastInfo::Any,
type_repr: Some(expr.clone()),
expr: Some(expr.clone()),
default: None,
positional: false,
@ -392,11 +398,12 @@ fn analyze_closure_signature(c: Arc<LazyHash<Closure>>) -> Vec<Arc<ParamSpec>> {
params.push(Arc::new(ParamSpec {
name: Cow::Owned(ident.unwrap_or_default().to_owned()),
input: CastInfo::Any,
type_repr: None,
expr: None,
default: None,
positional: false,
named: true,
variadic: false,
named: false,
variadic: true,
settable: false,
docs: Cow::Borrowed(""),
}));

View file

@ -155,7 +155,7 @@ impl<'a> fmt::Display for ParamTooltip<'a> {
if !sig.named.is_empty() {
let mut name_prints = vec![];
for v in sig.named.values() {
name_prints.push((v.name.clone(), v.expr.clone()))
name_prints.push((v.name.clone(), v.type_repr.clone()))
}
name_prints.sort();
for (k, v) in name_prints {

View file

@ -720,32 +720,6 @@ fn complete_params(ctx: &mut CompletionContext) -> bool {
false
}
/// Add completions for the values of a named function parameter.
fn named_param_value_completions<'a>(
ctx: &mut CompletionContext<'a, '_>,
callee: ast::Expr<'a>,
name: &str,
) {
let Some(func) = resolve_global_callee(ctx, callee) else {
return;
};
let Some(param) = func.param(name) else {
return;
};
if !param.named {
return;
}
ctx.cast_completions(&param.input);
if name == "font" {
ctx.font_completions();
}
if ctx.before.ends_with(':') {
ctx.enrich(" ", "");
}
}
/// Complete in code mode.
fn complete_code(ctx: &mut CompletionContext) -> bool {
if matches!(

View file

@ -152,7 +152,7 @@ pub fn param_completions<'a>(
set: bool,
args: ast::Args<'a>,
) {
let Some(func) = resolve_global_callee(ctx, callee) else {
let Some(func) = resolve_callee(ctx, callee) else {
return;
};
@ -203,9 +203,55 @@ pub fn param_completions<'a>(
}
}
/// Add completions for the values of a named function parameter.
pub fn named_param_value_completions<'a>(
ctx: &mut CompletionContext<'a, '_>,
callee: ast::Expr<'a>,
name: &str,
) {
let Some(func) = resolve_callee(ctx, callee) else {
return;
};
use typst::foundations::func::Repr;
let mut func = func;
while let Repr::With(f) = func.inner() {
// todo: complete with positional arguments
// with_args.push(ArgValue::Instance(f.1.clone()));
func = f.0.clone();
}
let signature = analyze_signature(func.clone());
let Some(param) = signature.named.get(name) else {
return;
};
if !param.named {
return;
}
if let Some(expr) = &param.type_repr {
ctx.completions.push(Completion {
kind: CompletionKind::Constant,
label: expr.clone(),
apply: None,
detail: Some(plain_docs_sentence(&param.docs)),
});
}
ctx.cast_completions(&param.input);
if name == "font" {
ctx.font_completions();
}
if ctx.before.ends_with(':') {
ctx.enrich(" ", "");
}
}
/// Resolve a callee expression to a function.
// todo: fallback to static analysis if we can't resolve the callee
pub fn resolve_global_callee<'a>(
pub fn resolve_callee<'a>(
ctx: &mut CompletionContext<'a, '_>,
callee: ast::Expr<'a>,
) -> Option<Func> {