diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-03-17 16:04:14 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-03-17 16:04:14 +0100 |
| commit | 6d64d3e8e9123f3fa8166c8b710e2b2c61ed5898 (patch) | |
| tree | 086961c2dfb8e63a437379898e9fc70c21cf8949 /library | |
| parent | c47e4cb4969836e7fb8955361728105555b6d722 (diff) | |
Query
Diffstat (limited to 'library')
| -rw-r--r-- | library/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/src/meta/mod.rs | 2 | ||||
| -rw-r--r-- | library/src/meta/query.rs | 69 |
3 files changed, 72 insertions, 0 deletions
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::<dyn Locatable>() { + 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<Content> { + 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()) +} |
