summaryrefslogtreecommitdiff
path: root/src/model/content.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/model/content.rs')
-rw-r--r--src/model/content.rs64
1 files changed, 63 insertions, 1 deletions
diff --git a/src/model/content.rs b/src/model/content.rs
index f95ce104..db867715 100644
--- a/src/model/content.rs
+++ b/src/model/content.rs
@@ -7,7 +7,7 @@ use ecow::{eco_format, EcoString, EcoVec};
use super::{
element, Behave, Behaviour, ElemFunc, Element, Fold, Guard, Label, Locatable,
- Location, Recipe, Style, Styles, Synthesize,
+ Location, Recipe, Selector, Style, Styles, Synthesize,
};
use crate::diag::{SourceResult, StrResult};
use crate::doc::Meta;
@@ -105,6 +105,12 @@ impl Content {
(self.func.0.vtable)(TypeId::of::<C>()).is_some()
}
+ /// Whether the contained element has the given capability.
+ /// Where the capability is given by a `TypeId`.
+ pub fn can_type_id(&self, type_id: TypeId) -> bool {
+ (self.func.0.vtable)(type_id).is_some()
+ }
+
/// Cast to a trait object if the contained element has the given
/// capability.
pub fn with<C>(&self) -> Option<&C>
@@ -347,6 +353,62 @@ impl Content {
pub fn set_location(&mut self, location: Location) {
self.attrs.push(Attr::Location(location));
}
+
+ /// Gives an iterator over the children of this content
+ pub fn children(&self) -> impl Iterator<Item = &Content> {
+ self.attrs.iter().filter_map(Attr::child)
+ }
+
+ /// Gives an iterator over the children of this content that are contained
+ /// within the arguments of the content.
+ pub fn children_in_args(&self) -> impl Iterator<Item = &Content> {
+ self.attrs
+ .iter()
+ .filter_map(Attr::value)
+ .filter_map(|value| match value {
+ Value::Content(content) => Some(content),
+ _ => None,
+ })
+ }
+
+ /// Queries the content tree for all elements that match the given selector.
+ ///
+ /// # Show rules
+ /// Elements produced in `show` rules will not be included in the results.
+ pub fn query(&self, selector: Selector) -> Vec<Content> {
+ let mut results = Vec::new();
+ self.query_into(&selector, &mut results);
+ results
+ }
+
+ /// Queries the content tree for all elements that match the given selector
+ /// and stores the results inside of the `results` vec.
+ fn query_into(&self, selector: &Selector, results: &mut Vec<Content>) {
+ if selector.matches(self) {
+ results.push(self.clone());
+ }
+
+ for attr in &self.attrs {
+ match attr {
+ Attr::Child(child) => child.query_into(selector, results),
+ Attr::Value(value) => walk_value(&value, selector, results),
+ _ => {}
+ }
+ }
+
+ /// Walks a given value to find any content that matches the selector.
+ fn walk_value(value: &Value, selector: &Selector, results: &mut Vec<Content>) {
+ match value {
+ Value::Content(content) => content.query_into(selector, results),
+ Value::Array(array) => {
+ for value in array {
+ walk_value(value, selector, results);
+ }
+ }
+ _ => {}
+ }
+ }
+ }
}
impl Debug for Content {