mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Autocomplete methods
This commit is contained in:
parent
2e039cb052
commit
a96141a3ea
@ -140,8 +140,11 @@ impl<T> Trace<T> for SourceResult<T> {
|
|||||||
F: Fn() -> Tracepoint,
|
F: Fn() -> Tracepoint,
|
||||||
{
|
{
|
||||||
self.map_err(|mut errors| {
|
self.map_err(|mut errors| {
|
||||||
|
if span.is_detached() {
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
let range = world.source(span.source()).range(span);
|
let range = world.source(span.source()).range(span);
|
||||||
for error in errors.iter_mut() {
|
for error in errors.iter_mut().filter(|e| !e.span.is_detached()) {
|
||||||
// Skip traces that surround the error.
|
// Skip traces that surround the error.
|
||||||
let error_range = world.source(error.span.source()).range(error.span);
|
let error_range = world.source(error.span.source()).range(error.span);
|
||||||
if range.start <= error_range.start && range.end >= error_range.end {
|
if range.start <= error_range.start && range.end >= error_range.end {
|
||||||
|
@ -22,6 +22,8 @@ pub fn analyze(world: &(dyn World + 'static), node: &LinkedNode) -> Vec<Value> {
|
|||||||
return tracer.finish();
|
return tracer.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(ast::Expr::Str(s)) => return vec![Value::Str(s.get().into())],
|
||||||
|
|
||||||
Some(ast::Expr::FieldAccess(access)) => {
|
Some(ast::Expr::FieldAccess(access)) => {
|
||||||
if let Some(child) = node.children().next() {
|
if let Some(child) = node.children().next() {
|
||||||
return analyze(world, &child)
|
return analyze(world, &child)
|
||||||
|
@ -3,7 +3,7 @@ use std::collections::{BTreeSet, HashSet};
|
|||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
|
|
||||||
use super::{analyze, plain_docs_sentence, summarize_font_family};
|
use super::{analyze, plain_docs_sentence, summarize_font_family};
|
||||||
use crate::model::{CastInfo, Scope, Value};
|
use crate::model::{methods_on, CastInfo, Scope, Value};
|
||||||
use crate::syntax::{ast, LinkedNode, Source, SyntaxKind, SyntaxNode};
|
use crate::syntax::{ast, LinkedNode, Source, SyntaxKind, SyntaxNode};
|
||||||
use crate::util::{format_eco, EcoString};
|
use crate::util::{format_eco, EcoString};
|
||||||
use crate::World;
|
use crate::World;
|
||||||
@ -271,7 +271,7 @@ fn math_completions(ctx: &mut CompletionContext) {
|
|||||||
|
|
||||||
/// Complete field accesses.
|
/// Complete field accesses.
|
||||||
fn complete_field_accesses(ctx: &mut CompletionContext) -> bool {
|
fn complete_field_accesses(ctx: &mut CompletionContext) -> bool {
|
||||||
// Behind an identifier plus dot: "emoji.|".
|
// Behind an expression plus dot: "emoji.|".
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if ctx.leaf.kind() == SyntaxKind::Dot
|
if ctx.leaf.kind() == SyntaxKind::Dot
|
||||||
|| (matches!(ctx.leaf.kind(), SyntaxKind::Text | SyntaxKind::MathAtom)
|
|| (matches!(ctx.leaf.kind(), SyntaxKind::Text | SyntaxKind::MathAtom)
|
||||||
@ -325,7 +325,16 @@ fn field_access_completions(ctx: &mut CompletionContext, value: &Value) {
|
|||||||
ctx.value_completion(Some(name.clone()), value, None);
|
ctx.value_completion(Some(name.clone()), value, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {
|
||||||
|
for &method in methods_on(value.type_name()) {
|
||||||
|
ctx.completions.push(Completion {
|
||||||
|
kind: CompletionKind::Func,
|
||||||
|
label: method.into(),
|
||||||
|
apply: Some(format_eco!("{method}(${{}})")),
|
||||||
|
detail: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,12 @@ pub fn eval(
|
|||||||
let route = unsafe { Route::insert(route, id) };
|
let route = unsafe { Route::insert(route, id) };
|
||||||
let scopes = Scopes::new(Some(library));
|
let scopes = Scopes::new(Some(library));
|
||||||
let mut vm = Vm::new(world, route.track(), tracer, id, scopes, 0);
|
let mut vm = Vm::new(world, route.track(), tracer, id, scopes, 0);
|
||||||
let result = source.ast()?.eval(&mut vm);
|
let root = match source.root().cast::<ast::Markup>() {
|
||||||
|
Some(markup) if vm.traced.is_some() => markup,
|
||||||
|
_ => source.ast()?,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = root.eval(&mut vm);
|
||||||
|
|
||||||
// Handle control flow.
|
// Handle control flow.
|
||||||
if let Some(flow) = vm.flow {
|
if let Some(flow) = vm.flow {
|
||||||
|
@ -210,3 +210,36 @@ pub fn is_accessor(method: &str) -> bool {
|
|||||||
fn missing_method(type_name: &str, method: &str) -> String {
|
fn missing_method(type_name: &str, method: &str) -> String {
|
||||||
format!("type {type_name} has no method `{method}`")
|
format!("type {type_name} has no method `{method}`")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// List the available methods for a type.
|
||||||
|
pub fn methods_on(type_name: &str) -> &[&'static str] {
|
||||||
|
match type_name {
|
||||||
|
"color" => &["lighten", "darken", "negate"],
|
||||||
|
"string" => &[
|
||||||
|
"len",
|
||||||
|
"at",
|
||||||
|
"contains",
|
||||||
|
"ends-with",
|
||||||
|
"find",
|
||||||
|
"first",
|
||||||
|
"last",
|
||||||
|
"match",
|
||||||
|
"matches",
|
||||||
|
"position",
|
||||||
|
"replace",
|
||||||
|
"slice",
|
||||||
|
"split",
|
||||||
|
"starts-with",
|
||||||
|
"trim",
|
||||||
|
],
|
||||||
|
"array" => &[
|
||||||
|
"all", "any", "at", "contains", "filter", "find", "first", "flatten", "fold",
|
||||||
|
"insert", "join", "last", "len", "map", "pop", "position", "push", "remove",
|
||||||
|
"rev", "slice", "sorted",
|
||||||
|
],
|
||||||
|
"dictionary" => &["at", "insert", "keys", "len", "pairs", "remove", "values"],
|
||||||
|
"function" => &["where", "with"],
|
||||||
|
"arguments" => &["named", "pos"],
|
||||||
|
_ => &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -38,6 +38,7 @@ pub use self::dict::*;
|
|||||||
pub use self::eval::*;
|
pub use self::eval::*;
|
||||||
pub use self::func::*;
|
pub use self::func::*;
|
||||||
pub use self::library::*;
|
pub use self::library::*;
|
||||||
|
pub use self::methods::*;
|
||||||
pub use self::module::*;
|
pub use self::module::*;
|
||||||
pub use self::realize::*;
|
pub use self::realize::*;
|
||||||
pub use self::scope::*;
|
pub use self::scope::*;
|
||||||
|
@ -150,6 +150,7 @@ impl SyntaxNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the child to another kind.
|
/// Convert the child to another kind.
|
||||||
|
#[track_caller]
|
||||||
pub(super) fn convert_to_kind(&mut self, kind: SyntaxKind) {
|
pub(super) fn convert_to_kind(&mut self, kind: SyntaxKind) {
|
||||||
debug_assert!(!kind.is_error());
|
debug_assert!(!kind.is_error());
|
||||||
match &mut self.0 {
|
match &mut self.0 {
|
||||||
@ -295,6 +296,7 @@ struct LeafNode {
|
|||||||
|
|
||||||
impl LeafNode {
|
impl LeafNode {
|
||||||
/// Create a new leaf node.
|
/// Create a new leaf node.
|
||||||
|
#[track_caller]
|
||||||
fn new(kind: SyntaxKind, text: impl Into<EcoString>) -> Self {
|
fn new(kind: SyntaxKind, text: impl Into<EcoString>) -> Self {
|
||||||
debug_assert!(!kind.is_error());
|
debug_assert!(!kind.is_error());
|
||||||
Self { kind, text: text.into(), span: Span::detached() }
|
Self { kind, text: text.into(), span: Span::detached() }
|
||||||
@ -340,6 +342,7 @@ struct InnerNode {
|
|||||||
|
|
||||||
impl InnerNode {
|
impl InnerNode {
|
||||||
/// Create a new inner node with the given kind and children.
|
/// Create a new inner node with the given kind and children.
|
||||||
|
#[track_caller]
|
||||||
fn new(kind: SyntaxKind, children: Vec<SyntaxNode>) -> Self {
|
fn new(kind: SyntaxKind, children: Vec<SyntaxNode>) -> Self {
|
||||||
debug_assert!(!kind.is_error());
|
debug_assert!(!kind.is_error());
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user