Autocomplete parentheses

This commit is contained in:
Laurenz 2023-02-12 20:06:49 +01:00
parent 3ffa7393f0
commit 77c29b36d4

View File

@ -249,7 +249,7 @@ fn complete_math(ctx: &mut CompletionContext) -> bool {
/// Add completions for math snippets. /// Add completions for math snippets.
#[rustfmt::skip] #[rustfmt::skip]
fn math_completions(ctx: &mut CompletionContext) { fn math_completions(ctx: &mut CompletionContext) {
ctx.scope_completions(|_| true); ctx.scope_completions(true, |_| true);
ctx.snippet_completion( ctx.snippet_completion(
"subscript", "subscript",
@ -336,12 +336,12 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value) {
} }
Value::Dict(dict) => { Value::Dict(dict) => {
for (name, value) in dict.iter() { for (name, value) in dict.iter() {
ctx.value_completion(Some(name.clone().into()), value, None); ctx.value_completion(Some(name.clone().into()), value, false, None);
} }
} }
Value::Module(module) => { Value::Module(module) => {
for (name, value) in module.scope().iter() { for (name, value) in module.scope().iter() {
ctx.value_completion(Some(name.clone()), value, None); ctx.value_completion(Some(name.clone()), value, true, None);
} }
} }
_ => {} _ => {}
@ -408,7 +408,7 @@ fn import_completions(
for (name, value) in module.scope().iter() { for (name, value) in module.scope().iter() {
if existing.iter().all(|ident| ident.as_str() != name) { if existing.iter().all(|ident| ident.as_str() != name) {
ctx.value_completion(Some(name.clone()), value, None); ctx.value_completion(Some(name.clone()), value, false, None);
} }
} }
} }
@ -453,7 +453,7 @@ fn complete_rules(ctx: &mut CompletionContext) -> bool {
/// Add completions for all functions from the global scope. /// Add completions for all functions from the global scope.
fn set_rule_completions(ctx: &mut CompletionContext) { fn set_rule_completions(ctx: &mut CompletionContext) {
ctx.scope_completions(|value| { ctx.scope_completions(true, |value| {
matches!( matches!(
value, value,
Value::Func(func) if func.info().map_or(false, |info| { Value::Func(func) if func.info().map_or(false, |info| {
@ -466,6 +466,7 @@ fn set_rule_completions(ctx: &mut CompletionContext) {
/// Add completions for selectors. /// Add completions for selectors.
fn show_rule_selector_completions(ctx: &mut CompletionContext) { fn show_rule_selector_completions(ctx: &mut CompletionContext) {
ctx.scope_completions( ctx.scope_completions(
false,
|value| matches!(value, Value::Func(func) if func.select(None).is_ok()), |value| matches!(value, Value::Func(func) if func.select(None).is_ok()),
); );
@ -504,7 +505,7 @@ fn show_rule_recipe_completions(ctx: &mut CompletionContext) {
"Transform the element with a function.", "Transform the element with a function.",
); );
ctx.scope_completions(|value| matches!(value, Value::Func(_))); ctx.scope_completions(false, |value| matches!(value, Value::Func(_)));
} }
/// Complete call and set rule parameters. /// Complete call and set rule parameters.
@ -688,7 +689,7 @@ fn complete_code(ctx: &mut CompletionContext) -> bool {
/// Add completions for expression snippets. /// Add completions for expression snippets.
#[rustfmt::skip] #[rustfmt::skip]
fn code_completions(ctx: &mut CompletionContext, hashtag: bool) { fn code_completions(ctx: &mut CompletionContext, hashtag: bool) {
ctx.scope_completions(|value| !hashtag || { ctx.scope_completions(true, |value| !hashtag || {
matches!(value, Value::Symbol(_) | Value::Func(_) | Value::Module(_)) matches!(value, Value::Symbol(_) | Value::Func(_) | Value::Module(_))
}); });
@ -896,6 +897,7 @@ impl<'a> CompletionContext<'a> {
&mut self, &mut self,
label: Option<EcoString>, label: Option<EcoString>,
value: &Value, value: &Value,
parens: bool,
docs: Option<&'static str>, docs: Option<&'static str>,
) { ) {
let mut label = label.unwrap_or_else(|| value.repr().into()); let mut label = label.unwrap_or_else(|| value.repr().into());
@ -916,6 +918,10 @@ impl<'a> CompletionContext<'a> {
v => Some(v.repr().into()), v => Some(v.repr().into()),
}); });
if parens && matches!(value, Value::Func(_)) {
apply = Some(format_eco!("{label}(${{}})"));
}
self.completions.push(Completion { self.completions.push(Completion {
kind: match value { kind: match value {
Value::Func(_) => CompletionKind::Func, Value::Func(_) => CompletionKind::Func,
@ -938,7 +944,7 @@ impl<'a> CompletionContext<'a> {
match cast { match cast {
CastInfo::Any => {} CastInfo::Any => {}
CastInfo::Value(value, docs) => { CastInfo::Value(value, docs) => {
self.value_completion(None, value, Some(docs)); self.value_completion(None, value, true, Some(docs));
} }
CastInfo::Type("none") => self.snippet_completion("none", "none", "Nothing."), CastInfo::Type("none") => self.snippet_completion("none", "none", "Nothing."),
CastInfo::Type("auto") => { CastInfo::Type("auto") => {
@ -964,7 +970,7 @@ impl<'a> CompletionContext<'a> {
"cmyk(${c}, ${m}, ${y}, ${k})", "cmyk(${c}, ${m}, ${y}, ${k})",
"A custom CMYK color.", "A custom CMYK color.",
); );
self.scope_completions(|value| value.type_name() == "color"); self.scope_completions(false, |value| value.type_name() == "color");
} }
CastInfo::Type("function") => { CastInfo::Type("function") => {
self.snippet_completion( self.snippet_completion(
@ -980,7 +986,7 @@ impl<'a> CompletionContext<'a> {
apply: Some(format_eco!("${{{ty}}}")), apply: Some(format_eco!("${{{ty}}}")),
detail: Some(format_eco!("A value of type {ty}.")), detail: Some(format_eco!("A value of type {ty}.")),
}); });
self.scope_completions(|value| value.type_name() == *ty); self.scope_completions(false, |value| value.type_name() == *ty);
} }
CastInfo::Union(union) => { CastInfo::Union(union) => {
for info in union { for info in union {
@ -992,7 +998,7 @@ impl<'a> CompletionContext<'a> {
/// Add completions for definitions that are available at the cursor. /// Add completions for definitions that are available at the cursor.
/// Filters the global/math scope with the given filter. /// Filters the global/math scope with the given filter.
fn scope_completions(&mut self, filter: impl Fn(&Value) -> bool) { fn scope_completions(&mut self, parens: bool, filter: impl Fn(&Value) -> bool) {
let mut defined = BTreeSet::new(); let mut defined = BTreeSet::new();
let mut ancestor = Some(self.leaf.clone()); let mut ancestor = Some(self.leaf.clone());
@ -1034,7 +1040,7 @@ impl<'a> CompletionContext<'a> {
let scope = if in_math { self.math } else { self.global }; let scope = if in_math { self.math } else { self.global };
for (name, value) in scope.iter() { for (name, value) in scope.iter() {
if filter(value) && !defined.contains(name) { if filter(value) && !defined.contains(name) {
self.value_completion(Some(name.clone()), value, None); self.value_completion(Some(name.clone()), value, parens, None);
} }
} }