summaryrefslogtreecommitdiff
path: root/library/src/layout
diff options
context:
space:
mode:
Diffstat (limited to 'library/src/layout')
-rw-r--r--library/src/layout/enum.rs2
-rw-r--r--library/src/layout/list.rs81
-rw-r--r--library/src/layout/terms.rs4
3 files changed, 78 insertions, 9 deletions
diff --git a/library/src/layout/enum.rs b/library/src/layout/enum.rs
index 9b7ea199..866a6195 100644
--- a/library/src/layout/enum.rs
+++ b/library/src/layout/enum.rs
@@ -150,7 +150,7 @@ impl EnumNode {
/// The spacing between the items of a wide (non-tight) enumeration.
///
- /// If set to `{auto}` uses the spacing [below blocks]($func/block.below).
+ /// If set to `{auto}`, uses the spacing [below blocks]($func/block.below).
pub const SPACING: Smart<Spacing> = Smart::Auto;
/// The numbers of parent items.
diff --git a/library/src/layout/list.rs b/library/src/layout/list.rs
index eab835ca..38816933 100644
--- a/library/src/layout/list.rs
+++ b/library/src/layout/list.rs
@@ -76,16 +76,29 @@ pub struct ListNode {
#[node]
impl ListNode {
- /// The marker which introduces each element.
+ /// The marker which introduces each item.
+ ///
+ /// Instead of plain content, you can also pass an array with multiple
+ /// markers that should be used for nested lists. If the list nesting depth
+ /// exceeds the number of markers, the last one is repeated. For total
+ /// control, you may pass a function that maps the list's nesting depth
+ /// (starting from `{0}`) to a desired marker.
+ ///
+ /// Default: `•`
///
/// ```example
/// #set list(marker: [--])
- ///
/// - A more classic list
/// - With en-dashes
+ ///
+ /// #set list(marker: ([•], [--]))
+ /// - Top-level
+ /// - Nested
+ /// - Items
+ /// - Items
/// ```
#[property(referenced)]
- pub const MARKER: Content = TextNode::packed('•');
+ pub const MARKER: Marker = Marker::Content(vec![]);
/// The indent of each item's marker.
#[property(resolve)]
@@ -97,9 +110,13 @@ impl ListNode {
/// The spacing between the items of a wide (non-tight) list.
///
- /// If set to `{auto}` uses the spacing [below blocks]($func/block.below).
+ /// If set to `{auto}`, uses the spacing [below blocks]($func/block.below).
pub const SPACING: Smart<Spacing> = Smart::Auto;
+ /// The nesting depth.
+ #[property(skip, fold)]
+ const DEPTH: Depth = 0;
+
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self {
tight: args.named("tight")?.unwrap_or(true),
@@ -126,7 +143,6 @@ impl Layout for ListNode {
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
- let marker = styles.get(Self::MARKER);
let indent = styles.get(Self::INDENT);
let body_indent = styles.get(Self::BODY_INDENT);
let gutter = if self.tight {
@@ -137,12 +153,17 @@ impl Layout for ListNode {
.unwrap_or_else(|| styles.get(BlockNode::BELOW).amount)
};
+ let depth = styles.get(Self::DEPTH);
+ let marker = styles.get(Self::MARKER).resolve(vt.world(), depth)?;
+
let mut cells = vec![];
for (item, map) in self.items.iter() {
cells.push(Content::empty());
cells.push(marker.clone());
cells.push(Content::empty());
- cells.push(item.clone().styled_with_map(map.clone()));
+ cells.push(
+ item.clone().styled_with_map(map.clone()).styled(Self::DEPTH, Depth),
+ );
}
GridNode {
@@ -158,3 +179,51 @@ impl Layout for ListNode {
.layout(vt, styles, regions)
}
}
+
+/// A list's marker.
+#[derive(Debug, Clone, Hash)]
+pub enum Marker {
+ Content(Vec<Content>),
+ Func(Func),
+}
+
+impl Marker {
+ /// Resolve the marker for the given depth.
+ fn resolve(&self, world: Tracked<dyn World>, depth: usize) -> SourceResult<Content> {
+ Ok(match self {
+ Self::Content(list) => list
+ .get(depth)
+ .or(list.last())
+ .cloned()
+ .unwrap_or_else(|| TextNode::packed('•')),
+ Self::Func(func) => {
+ let args = Args::new(func.span(), [Value::Int(depth as i64)]);
+ func.call_detached(world, args)?.display()
+ }
+ })
+ }
+}
+
+castable! {
+ Marker,
+ v: Content => Self::Content(vec![v]),
+ array: Array => {
+ if array.len() == 0 {
+ Err("must contain at least one marker")?;
+ }
+ Self::Content(array.into_iter().map(Value::display).collect())
+ },
+ v: Func => Self::Func(v),
+}
+
+#[derive(Debug, Clone, Hash)]
+struct Depth;
+
+impl Fold for Depth {
+ type Output = usize;
+
+ fn fold(self, mut outer: Self::Output) -> Self::Output {
+ outer += 1;
+ outer
+ }
+}
diff --git a/library/src/layout/terms.rs b/library/src/layout/terms.rs
index b1d399db..f2902b80 100644
--- a/library/src/layout/terms.rs
+++ b/library/src/layout/terms.rs
@@ -82,7 +82,7 @@ impl TermsNode {
/// The spacing between the items of a wide (non-tight) term list.
///
- /// If set to `{auto}` uses the spacing [below blocks]($func/block.below).
+ /// If set to `{auto}`, uses the spacing [below blocks]($func/block.below).
pub const SPACING: Smart<Spacing> = Smart::Auto;
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
@@ -171,7 +171,7 @@ castable! {
let mut iter = array.into_iter();
let (term, description) = match (iter.next(), iter.next(), iter.next()) {
(Some(a), Some(b), None) => (a.cast()?, b.cast()?),
- _ => Err("array must contain exactly two entries")?,
+ _ => Err("term array must contain exactly two entries")?,
};
Self { term, description }
},