summaryrefslogtreecommitdiff
path: root/crates/typst-ide/src/complete.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/typst-ide/src/complete.rs')
-rw-r--r--crates/typst-ide/src/complete.rs50
1 files changed, 44 insertions, 6 deletions
diff --git a/crates/typst-ide/src/complete.rs b/crates/typst-ide/src/complete.rs
index b58a9bcc..94679552 100644
--- a/crates/typst-ide/src/complete.rs
+++ b/crates/typst-ide/src/complete.rs
@@ -6,7 +6,7 @@ use if_chain::if_chain;
use serde::{Deserialize, Serialize};
use typst::foundations::{
fields_on, format_str, mutable_methods_on, repr, AutoValue, CastInfo, Func, Label,
- NoneValue, Repr, Scope, Type, Value,
+ NoneValue, Repr, Scope, StyleChain, Styles, Type, Value,
};
use typst::model::Document;
use typst::syntax::{
@@ -135,6 +135,17 @@ fn complete_markup(ctx: &mut CompletionContext) -> bool {
}
}
+ // Behind a half-completed context block: "#context |".
+ if_chain! {
+ if let Some(prev) = ctx.leaf.prev_leaf();
+ if prev.kind() == SyntaxKind::Context;
+ then {
+ ctx.from = ctx.cursor;
+ code_completions(ctx, false);
+ return true;
+ }
+ }
+
// Directly after a raw block.
let mut s = Scanner::new(ctx.text);
s.jump(ctx.leaf.offset());
@@ -333,10 +344,10 @@ fn complete_field_accesses(ctx: &mut CompletionContext) -> bool {
if prev.is::<ast::Expr>();
if prev.parent_kind() != Some(SyntaxKind::Markup) ||
prev.prev_sibling_kind() == Some(SyntaxKind::Hash);
- if let Some(value) = analyze_expr(ctx.world, &prev).into_iter().next();
+ if let Some((value, styles)) = analyze_expr(ctx.world, &prev).into_iter().next();
then {
ctx.from = ctx.cursor;
- field_access_completions(ctx, &value);
+ field_access_completions(ctx, &value, &styles);
return true;
}
}
@@ -348,10 +359,10 @@ fn complete_field_accesses(ctx: &mut CompletionContext) -> bool {
if prev.kind() == SyntaxKind::Dot;
if let Some(prev_prev) = prev.prev_sibling();
if prev_prev.is::<ast::Expr>();
- if let Some(value) = analyze_expr(ctx.world, &prev_prev).into_iter().next();
+ if let Some((value, styles)) = analyze_expr(ctx.world, &prev_prev).into_iter().next();
then {
ctx.from = ctx.leaf.offset();
- field_access_completions(ctx, &value);
+ field_access_completions(ctx, &value, &styles);
return true;
}
}
@@ -360,7 +371,11 @@ fn complete_field_accesses(ctx: &mut CompletionContext) -> bool {
}
/// Add completions for all fields on a value.
-fn field_access_completions(ctx: &mut CompletionContext, value: &Value) {
+fn field_access_completions(
+ ctx: &mut CompletionContext,
+ value: &Value,
+ styles: &Option<Styles>,
+) {
for (name, value) in value.ty().scope().iter() {
ctx.value_completion(Some(name.clone()), value, true, None);
}
@@ -421,6 +436,23 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value) {
ctx.value_completion(Some(name.clone().into()), value, false, None);
}
}
+ Value::Func(func) => {
+ // Autocomplete get rules.
+ if let Some((elem, styles)) = func.element().zip(styles.as_ref()) {
+ for param in elem.params().iter().filter(|param| !param.required) {
+ if let Some(value) = elem.field_id(param.name).and_then(|id| {
+ elem.field_from_styles(id, StyleChain::new(styles))
+ }) {
+ ctx.value_completion(
+ Some(param.name.into()),
+ &value,
+ false,
+ None,
+ );
+ }
+ }
+ }
+ }
Value::Plugin(plugin) => {
for name in plugin.iter() {
ctx.completions.push(Completion {
@@ -863,6 +895,12 @@ fn code_completions(ctx: &mut CompletionContext, hash: bool) {
);
ctx.snippet_completion(
+ "context expression",
+ "context ${}",
+ "Provides contextual data.",
+ );
+
+ ctx.snippet_completion(
"let binding",
"let ${name} = ${value}",
"Saves a value in a variable.",