summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/typst/src/introspection/counter.rs15
-rw-r--r--crates/typst/src/introspection/introspector.rs24
-rw-r--r--crates/typst/src/introspection/state.rs5
3 files changed, 29 insertions, 15 deletions
diff --git a/crates/typst/src/introspection/counter.rs b/crates/typst/src/introspection/counter.rs
index 82f8bbfc..2365b3e8 100644
--- a/crates/typst/src/introspection/counter.rs
+++ b/crates/typst/src/introspection/counter.rs
@@ -223,10 +223,7 @@ impl Counter {
location: Location,
) -> SourceResult<CounterState> {
let sequence = self.sequence(engine)?;
- let offset = engine
- .introspector
- .query(&self.selector().before(location.into(), true))
- .len();
+ let offset = engine.introspector.query_count_before(&self.selector(), location);
let (mut at_state, at_page) = sequence[offset].clone();
let (mut final_state, final_page) = sequence.last().unwrap().clone();
if self.is_page() {
@@ -245,16 +242,14 @@ impl Counter {
pub fn at_loc(
&self,
engine: &mut Engine,
- loc: Location,
+ location: Location,
) -> SourceResult<CounterState> {
let sequence = self.sequence(engine)?;
- let offset = engine
- .introspector
- .query(&self.selector().before(loc.into(), true))
- .len();
+ let offset = engine.introspector.query_count_before(&self.selector(), location);
let (mut state, page) = sequence[offset].clone();
if self.is_page() {
- let delta = engine.introspector.page(loc).get().saturating_sub(page.get());
+ let delta =
+ engine.introspector.page(location).get().saturating_sub(page.get());
state.step(NonZeroUsize::ONE, delta);
}
Ok(state)
diff --git a/crates/typst/src/introspection/introspector.rs b/crates/typst/src/introspection/introspector.rs
index b6c32a47..ebd787fe 100644
--- a/crates/typst/src/introspection/introspector.rs
+++ b/crates/typst/src/introspection/introspector.rs
@@ -121,7 +121,7 @@ impl Introspector {
indices.iter().map(|&index| self.elems[index].0.clone()).collect()
})
.unwrap_or_default(),
- Selector::Elem(..) | Selector::Regex(_) | Selector::Can(_) => self
+ Selector::Elem(..) | Selector::Can(_) => self
.all()
.filter(|elem| selector.matches(elem, None))
.cloned()
@@ -188,6 +188,8 @@ impl Introspector {
.into_iter()
.map(|index| self.elems[index].0.clone())
.collect(),
+ // Not supported here.
+ Selector::Regex(_) => EcoVec::new(),
};
self.queries.insert(hash, output.clone());
@@ -198,6 +200,11 @@ impl Introspector {
pub fn query_first(&self, selector: &Selector) -> Option<Content> {
match selector {
Selector::Location(location) => self.get(location).cloned(),
+ Selector::Label(label) => self
+ .labels
+ .get(label)
+ .and_then(|indices| indices.first())
+ .map(|&index| self.elems[index].0.clone()),
_ => self.query(selector).first().cloned(),
}
}
@@ -236,6 +243,21 @@ impl Introspector {
Ok(&self.elems[indices[0]].0)
}
+ /// This is an optimized version of
+ /// `query(selector.before(end, true).len()` used by counters and state.
+ pub fn query_count_before(&self, selector: &Selector, end: Location) -> usize {
+ // See `query()` for details.
+ let list = self.query(selector);
+ if let Some(end) = self.get(&end) {
+ match self.binary_search(&list, end) {
+ Ok(i) => i + 1,
+ Err(i) => i,
+ }
+ } else {
+ list.len()
+ }
+ }
+
/// The total number pages.
pub fn pages(&self) -> NonZeroUsize {
NonZeroUsize::new(self.pages).unwrap_or(NonZeroUsize::ONE)
diff --git a/crates/typst/src/introspection/state.rs b/crates/typst/src/introspection/state.rs
index c4c95137..5cbd2fc3 100644
--- a/crates/typst/src/introspection/state.rs
+++ b/crates/typst/src/introspection/state.rs
@@ -202,10 +202,7 @@ impl State {
/// Get the value of the state at the given location.
pub fn at_loc(&self, engine: &mut Engine, loc: Location) -> SourceResult<Value> {
let sequence = self.sequence(engine)?;
- let offset = engine
- .introspector
- .query(&self.selector().before(loc.into(), true))
- .len();
+ let offset = engine.introspector.query_count_before(&self.selector(), loc);
Ok(sequence[offset].clone())
}