mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Merge 5aa9b90a7b3e7f5ed964bf6727e445bdfc5211cd into 9b09146a6b5e936966ed7ee73bce9dd2df3810ae
This commit is contained in:
commit
d70ed5eadd
@ -412,7 +412,7 @@ impl Content {
|
|||||||
/// Queries the content tree for all elements that match the given selector.
|
/// Queries the content tree for all elements that match the given selector.
|
||||||
///
|
///
|
||||||
/// Elements produced in `show` rules will not be included in the results.
|
/// Elements produced in `show` rules will not be included in the results.
|
||||||
pub fn query(&self, selector: Selector) -> Vec<Content> {
|
pub fn query(&self, selector: &Selector) -> Vec<Content> {
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
self.traverse(&mut |element| -> ControlFlow<()> {
|
self.traverse(&mut |element| -> ControlFlow<()> {
|
||||||
if selector.matches(&element, None) {
|
if selector.matches(&element, None) {
|
||||||
|
@ -93,6 +93,8 @@ pub enum Selector {
|
|||||||
Before { selector: Arc<Self>, end: Arc<Self>, inclusive: bool },
|
Before { selector: Arc<Self>, end: Arc<Self>, inclusive: bool },
|
||||||
/// Matches all matches of `selector` after `start`.
|
/// Matches all matches of `selector` after `start`.
|
||||||
After { selector: Arc<Self>, start: Arc<Self>, inclusive: bool },
|
After { selector: Arc<Self>, start: Arc<Self>, inclusive: bool },
|
||||||
|
/// Matches all children of `ancestor` matching `selector`
|
||||||
|
Within { selector: Arc<Self>, ancestor: Arc<Self> },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Selector {
|
impl Selector {
|
||||||
@ -139,7 +141,10 @@ impl Selector {
|
|||||||
}
|
}
|
||||||
Self::Location(location) => target.location() == Some(*location),
|
Self::Location(location) => target.location() == Some(*location),
|
||||||
// Not supported here.
|
// Not supported here.
|
||||||
Self::Regex(_) | Self::Before { .. } | Self::After { .. } => false,
|
Self::Regex(_)
|
||||||
|
| Self::Before { .. }
|
||||||
|
| Self::After { .. }
|
||||||
|
| Self::Within { .. } => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,6 +226,15 @@ impl Selector {
|
|||||||
inclusive,
|
inclusive,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a modified selector that only matches `self` if it is contained in an `ancestor`.
|
||||||
|
#[func]
|
||||||
|
pub fn within(self, ancestor: LocatableSelector) -> Selector {
|
||||||
|
Self::Within {
|
||||||
|
selector: Arc::new(self),
|
||||||
|
ancestor: Arc::new(ancestor.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Location> for Selector {
|
impl From<Location> for Selector {
|
||||||
@ -266,6 +280,9 @@ impl Repr for Selector {
|
|||||||
inclusive_arg
|
inclusive_arg
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Self::Within { selector, ancestor } => {
|
||||||
|
eco_format!("{}.within({})", selector.repr(), ancestor.repr())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -352,7 +369,8 @@ impl FromValue for LocatableSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Selector::Before { selector, end: split, .. }
|
Selector::Before { selector, end: split, .. }
|
||||||
| Selector::After { selector, start: split, .. } => {
|
| Selector::After { selector, start: split, .. }
|
||||||
|
| Selector::Within { selector, ancestor: split } => {
|
||||||
for selector in [selector, split] {
|
for selector in [selector, split] {
|
||||||
validate(selector)?;
|
validate(selector)?;
|
||||||
}
|
}
|
||||||
@ -431,7 +449,8 @@ impl FromValue for ShowableSelector {
|
|||||||
| Selector::Location(_)
|
| Selector::Location(_)
|
||||||
| Selector::Can(_)
|
| Selector::Can(_)
|
||||||
| Selector::Before { .. }
|
| Selector::Before { .. }
|
||||||
| Selector::After { .. } => {
|
| Selector::After { .. }
|
||||||
|
| Selector::Within { .. } => {
|
||||||
bail!("this selector cannot be used with show")
|
bail!("this selector cannot be used with show")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,11 @@ impl Introspector {
|
|||||||
}
|
}
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
Selector::Within { selector, ancestor } => self
|
||||||
|
.query(ancestor)
|
||||||
|
.iter()
|
||||||
|
.flat_map(|children| children.query(selector))
|
||||||
|
.collect(),
|
||||||
// Not supported here.
|
// Not supported here.
|
||||||
Selector::Can(_) | Selector::Regex(_) => EcoVec::new(),
|
Selector::Can(_) | Selector::Regex(_) => EcoVec::new(),
|
||||||
};
|
};
|
||||||
|
BIN
tests/ref/query-within.png
Normal file
BIN
tests/ref/query-within.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 560 B |
@ -250,3 +250,27 @@
|
|||||||
t("b")
|
t("b")
|
||||||
block(height: 1fr, metadata("b"))
|
block(height: 1fr, metadata("b"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- query-within ---
|
||||||
|
|
||||||
|
#let test-selector(selector, ref) = context {
|
||||||
|
test(query(selector).map(e => e.body), ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
= A #strong[a] #label("strong")
|
||||||
|
|
||||||
|
#strong[b] #label("strong")
|
||||||
|
|
||||||
|
== B
|
||||||
|
|
||||||
|
== C #strong[c] #label("strong")
|
||||||
|
>
|
||||||
|
#test-selector(
|
||||||
|
selector(<strong>).within(heading),
|
||||||
|
([a], [c]),
|
||||||
|
)
|
||||||
|
|
||||||
|
#test-selector(
|
||||||
|
selector(<strong>).within(heading.where(level: 2)),
|
||||||
|
([c], ),
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user