summaryrefslogtreecommitdiff
path: root/library/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-03-17 16:04:14 +0100
committerLaurenz <laurmaedje@gmail.com>2023-03-17 16:04:14 +0100
commit6d64d3e8e9123f3fa8166c8b710e2b2c61ed5898 (patch)
tree086961c2dfb8e63a437379898e9fc70c21cf8949 /library/src
parentc47e4cb4969836e7fb8955361728105555b6d722 (diff)
Query
Diffstat (limited to 'library/src')
-rw-r--r--library/src/lib.rs1
-rw-r--r--library/src/meta/mod.rs2
-rw-r--r--library/src/meta/query.rs69
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())
+}