summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-03-19 10:19:24 +0100
committerLaurenz <laurmaedje@gmail.com>2023-03-19 10:19:34 +0100
commit0ba99ab8aa523645e2f0a0d9f6333ad4e48f5daa (patch)
tree2de7ce344b6d579dca8ae346c68b1931a6e79b25 /src
parentc7f4d6b12ee3138c752402889eeaa603ac69351d (diff)
Measurement and introspection rework
Diffstat (limited to 'src')
-rw-r--r--src/eval/library.rs3
-rw-r--r--src/eval/methods.rs33
-rw-r--r--src/model/content.rs21
-rw-r--r--src/model/styles.rs8
-rw-r--r--src/model/typeset.rs57
5 files changed, 65 insertions, 57 deletions
diff --git a/src/eval/library.rs b/src/eval/library.rs
index 485a766b..eae342c2 100644
--- a/src/eval/library.rs
+++ b/src/eval/library.rs
@@ -6,7 +6,7 @@ use comemo::Tracked;
use ecow::EcoString;
use once_cell::sync::OnceCell;
-use super::{Args, Dynamic, Module, Value};
+use super::{Args, Dynamic, Module, Value, Vm};
use crate::diag::SourceResult;
use crate::doc::Document;
use crate::geom::{Abs, Dir};
@@ -92,6 +92,7 @@ pub struct LangItems {
pub math_frac: fn(num: Content, denom: Content) -> Content,
/// Dispatch a method on a library value.
pub library_method: fn(
+ vm: &mut Vm,
dynamic: &Dynamic,
method: &str,
args: Args,
diff --git a/src/eval/methods.rs b/src/eval/methods.rs
index eef825ff..324191ab 100644
--- a/src/eval/methods.rs
+++ b/src/eval/methods.rs
@@ -4,6 +4,7 @@ use ecow::EcoString;
use super::{Args, Str, Value, Vm};
use crate::diag::{At, SourceResult};
+use crate::model::StableId;
use crate::syntax::Span;
/// Call a method on a value.
@@ -73,8 +74,11 @@ pub fn call(
"func" => Value::Func(content.id().into()),
"has" => Value::Bool(content.has(&args.expect::<EcoString>("field")?)),
"at" => content.at(&args.expect::<EcoString>("field")?).at(span)?.clone(),
- "page" => content.page(&vm.vt).at(span)?.into(),
- "location" => content.location(&vm.vt).at(span)?.into(),
+ "id" => content
+ .stable_id()
+ .ok_or("this method can only be called on content returned by query()")
+ .at(span)?
+ .into(),
_ => return missing(),
},
@@ -137,7 +141,15 @@ pub fn call(
},
Value::Dyn(dynamic) => {
- return (vm.items.library_method)(&dynamic, method, args, span);
+ if let Some(&id) = dynamic.downcast::<StableId>() {
+ match method {
+ "page" => vm.vt.introspector.page(id).into(),
+ "location" => vm.vt.introspector.location(id).into(),
+ _ => return missing(),
+ }
+ } else {
+ return (vm.items.library_method)(vm, &dynamic, method, args, span);
+ }
}
_ => return missing(),
@@ -251,13 +263,7 @@ pub fn methods_on(type_name: &str) -> &[(&'static str, bool)] {
("starts-with", true),
("trim", true),
],
- "content" => &[
- ("func", false),
- ("has", true),
- ("at", true),
- ("page", false),
- ("location", false),
- ],
+ "content" => &[("func", false), ("has", true), ("at", true), ("id", false)],
"array" => &[
("all", true),
("any", true),
@@ -293,14 +299,15 @@ pub fn methods_on(type_name: &str) -> &[(&'static str, bool)] {
],
"function" => &[("where", true), ("with", true)],
"arguments" => &[("named", false), ("pos", false)],
+ "stable id" => &[("page", false), ("location", false)],
"counter" => &[
- ("get", true),
+ ("display", true),
+ ("at", true),
("final", true),
- ("both", true),
("step", true),
("update", true),
],
- "state" => &[("get", true), ("final", true), ("update", true)],
+ "state" => &[("display", true), ("at", true), ("final", true), ("update", true)],
_ => &[],
}
}
diff --git a/src/model/content.rs b/src/model/content.rs
index 3c661929..5317236e 100644
--- a/src/model/content.rs
+++ b/src/model/content.rs
@@ -2,7 +2,6 @@ use std::any::TypeId;
use std::fmt::{self, Debug, Formatter, Write};
use std::hash::{Hash, Hasher};
use std::iter::{self, Sum};
-use std::num::NonZeroUsize;
use std::ops::{Add, AddAssign, Deref};
use ecow::{eco_format, EcoString, EcoVec};
@@ -10,10 +9,10 @@ use once_cell::sync::Lazy;
use super::{
node, Behave, Behaviour, Fold, Guard, Locatable, Recipe, StableId, Style, StyleMap,
- Synthesize, Vt,
+ Synthesize,
};
use crate::diag::{SourceResult, StrResult};
-use crate::doc::{Location, Meta};
+use crate::doc::Meta;
use crate::eval::{
cast_from_value, cast_to_value, Args, Cast, Func, FuncInfo, Str, Value, Vm,
};
@@ -186,22 +185,6 @@ impl Content {
self.field(field).ok_or_else(|| missing_field(field))
}
- /// Determine the page of this content.
- pub fn page(&self, vt: &Vt) -> StrResult<NonZeroUsize> {
- match self.stable_id() {
- Some(id) => Ok(vt.introspector.page(id)),
- None => Err("this method can only be called on queried content".into()),
- }
- }
-
- /// Determine the location of this content.
- pub fn location(&self, vt: &Vt) -> StrResult<Location> {
- match self.stable_id() {
- Some(id) => Ok(vt.introspector.location(id)),
- None => Err("this method can only be called on queried content".into()),
- }
- }
-
/// The content's label.
pub fn label(&self) -> Option<&Label> {
match self.field("label")? {
diff --git a/src/model/styles.rs b/src/model/styles.rs
index 7b725af9..b7d09774 100644
--- a/src/model/styles.rs
+++ b/src/model/styles.rs
@@ -78,13 +78,7 @@ impl PartialEq for StyleMap {
impl Debug for StyleMap {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- if let [style] = self.0.as_slice() {
- return style.fmt(f);
- }
-
- let pieces: Vec<_> =
- self.0.iter().map(|value| eco_format!("{value:?}")).collect();
- f.write_str(&pretty_array_like(&pieces, false))
+ f.pad("..")
}
}
diff --git a/src/model/typeset.rs b/src/model/typeset.rs
index 162a2a67..8216d7a8 100644
--- a/src/model/typeset.rs
+++ b/src/model/typeset.rs
@@ -1,3 +1,4 @@
+use std::fmt::{self, Debug, Formatter};
use std::hash::Hash;
use std::num::NonZeroUsize;
@@ -6,7 +7,7 @@ use comemo::{Constraint, Track, Tracked, TrackedMut};
use super::{Content, Selector, StyleChain};
use crate::diag::SourceResult;
use crate::doc::{Document, Element, Frame, Location, Meta};
-use crate::eval::Tracer;
+use crate::eval::{cast_from_value, Tracer};
use crate::geom::{Point, Transform};
use crate::util::NonZeroExt;
use crate::World;
@@ -116,7 +117,7 @@ impl StabilityProvider {
/// Stably identifies a call site across multiple layout passes.
///
/// This struct is created by [`StabilityProvider::identify`].
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct StableId(u128, usize, usize);
impl StableId {
@@ -126,16 +127,27 @@ impl StableId {
}
}
+impl Debug for StableId {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ f.pad("..")
+ }
+}
+
+cast_from_value! {
+ StableId: "stable id",
+}
+
/// Provides access to information about the document.
pub struct Introspector {
init: bool,
+ pages: usize,
nodes: Vec<(Content, Location)>,
}
impl Introspector {
/// Create a new introspector.
pub fn new(frames: &[Frame]) -> Self {
- let mut introspector = Self { init: false, nodes: vec![] };
+ let mut introspector = Self { init: false, pages: frames.len(), nodes: vec![] };
for (i, frame) in frames.iter().enumerate() {
let page = NonZeroUsize::new(1 + i).unwrap();
introspector.extract(frame, page, Transform::identity());
@@ -180,26 +192,37 @@ impl Introspector {
self.init
}
- /// Query for all metadata matches for the given selector.
+ /// Query for all nodes for the given selector.
pub fn query(&self, selector: Selector) -> Vec<Content> {
self.all().filter(|node| selector.matches(node)).cloned().collect()
}
- /// Query for all metadata matches before the given id.
- pub fn query_split(
- &self,
- selector: Selector,
- id: StableId,
- ) -> (Vec<Content>, Vec<Content>) {
- let mut iter = self.all();
- let before = iter
- .by_ref()
- .take_while(|node| node.stable_id() != Some(id))
+ /// Query for all nodes up to the given id.
+ pub fn query_before(&self, selector: Selector, id: StableId) -> Vec<Content> {
+ let mut matches = vec![];
+ for node in self.all() {
+ if selector.matches(node) {
+ matches.push(node.clone());
+ }
+ if node.stable_id() == Some(id) {
+ break;
+ }
+ }
+ matches
+ }
+
+ /// Query for all nodes starting from the given id.
+ pub fn query_after(&self, selector: Selector, id: StableId) -> Vec<Content> {
+ self.all()
+ .skip_while(|node| node.stable_id() != Some(id))
.filter(|node| selector.matches(node))
.cloned()
- .collect();
- let after = iter.filter(|node| selector.matches(node)).cloned().collect();
- (before, after)
+ .collect()
+ }
+
+ /// The total number pages.
+ pub fn pages(&self) -> NonZeroUsize {
+ NonZeroUsize::new(self.pages).unwrap_or(NonZeroUsize::ONE)
}
/// Find the page number for the given stable id.