From 6d64d3e8e9123f3fa8166c8b710e2b2c61ed5898 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Fri, 17 Mar 2023 16:04:14 +0100 Subject: Query --- library/src/lib.rs | 1 + library/src/meta/mod.rs | 2 ++ library/src/meta/query.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 library/src/meta/query.rs (limited to 'library') diff --git a/library/src/lib.rs b/library/src/lib.rs index 83dbe17a..0850faf4 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -95,6 +95,7 @@ fn global(math: Module, calc: Module) -> Module { global.define("counter", meta::counter); global.define("numbering", meta::numbering); global.define("state", meta::state); + global.define("query", meta::query); // Symbols. global.define("sym", symbols::sym()); diff --git a/library/src/meta/mod.rs b/library/src/meta/mod.rs index 1d774058..50b8627e 100644 --- a/library/src/meta/mod.rs +++ b/library/src/meta/mod.rs @@ -8,6 +8,7 @@ mod heading; mod link; mod numbering; mod outline; +mod query; mod reference; mod state; @@ -19,6 +20,7 @@ pub use self::heading::*; pub use self::link::*; pub use self::numbering::*; pub use self::outline::*; +pub use self::query::*; pub use self::reference::*; pub use self::state::*; diff --git a/library/src/meta/query.rs b/library/src/meta/query.rs new file mode 100644 index 00000000..c91f0d1a --- /dev/null +++ b/library/src/meta/query.rs @@ -0,0 +1,69 @@ +use crate::prelude::*; + +/// Find elements in the document. +/// +/// Display: Query +/// Category: meta +/// Returns: content +#[func] +pub fn query( + /// The thing to search for. + target: Target, + /// A function to format the results with. + format: Func, +) -> Value { + QueryNode::new(target.0, format).pack().into() +} + +/// A query target. +struct Target(Selector); + +cast_from_value! { + Target, + label: Label => Self(Selector::Label(label)), + func: Func => { + let Some(id) = func.id() else { + return Err("this function is not selectable".into()); + }; + + if !Content::new(id).can::() { + Err(eco_format!("cannot query for {}s", id.name))?; + } + + Self(Selector::Node(id, None)) + } +} + +/// Executes a query. +/// +/// Display: Query +/// Category: special +#[node(Locatable, Show)] +pub struct QueryNode { + /// The thing to search for. + #[required] + pub target: Selector, + + /// The function to format the results with. + #[required] + pub format: Func, +} + +impl Show for QueryNode { + fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult { + if !vt.introspector.init() { + return Ok(Content::empty()); + } + + let id = self.0.stable_id().unwrap(); + let target = self.target(); + let (before, after) = vt.introspector.query_split(target, id); + let func = self.format(); + let args = Args::new(func.span(), [encode(before), encode(after)]); + Ok(func.call_detached(vt.world, args)?.display()) + } +} + +fn encode(list: Vec<&Content>) -> Value { + Value::Array(list.into_iter().cloned().map(Value::Content).collect()) +} -- cgit v1.2.3