diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-03-19 10:19:24 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-03-19 10:19:34 +0100 |
| commit | 0ba99ab8aa523645e2f0a0d9f6333ad4e48f5daa (patch) | |
| tree | 2de7ce344b6d579dca8ae346c68b1931a6e79b25 /src | |
| parent | c7f4d6b12ee3138c752402889eeaa603ac69351d (diff) | |
Measurement and introspection rework
Diffstat (limited to 'src')
| -rw-r--r-- | src/eval/library.rs | 3 | ||||
| -rw-r--r-- | src/eval/methods.rs | 33 | ||||
| -rw-r--r-- | src/model/content.rs | 21 | ||||
| -rw-r--r-- | src/model/styles.rs | 8 | ||||
| -rw-r--r-- | src/model/typeset.rs | 57 |
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. |
