roffman/
section.rs

1use crate::_macro::{ENDL, SECTION_HEADER, SPACE, SUB_HEADER};
2use crate::{
3    node::RoffNodeInner, write_quoted_if_whitespace, IntoRoffNode, RoffError, RoffText, Roffable,
4};
5
6use std::io::Write;
7
8#[derive(Clone, Debug)]
9/// A single section of the ROFF document.
10pub struct Section {
11    title: RoffText,
12    subtitle: Option<RoffText>,
13    nodes: Vec<RoffNodeInner>,
14}
15
16impl Section {
17    /// Create a new section with `title` and `content`.
18    pub fn new<I, R>(title: impl Roffable, content: I) -> Self
19    where
20        I: IntoIterator<Item = R>,
21        R: IntoRoffNode,
22    {
23        Self {
24            title: title.roff(),
25            subtitle: None,
26            nodes: content
27                .into_iter()
28                .map(|r| r.into_roff().into_inner())
29                .collect(),
30        }
31    }
32
33    /// Set the sub heading of this section.
34    pub fn subtitle(mut self, subtitle: impl Roffable) -> Self {
35        self.subtitle = Some(subtitle.roff());
36        self
37    }
38
39    pub(crate) fn render<W: Write>(
40        &self,
41        writer: &mut W,
42        was_text: bool,
43    ) -> Result<bool, RoffError> {
44        if was_text {
45            writer.write_all(ENDL)?;
46        }
47        writer.write_all(SECTION_HEADER)?;
48        writer.write_all(SPACE)?;
49        write_quoted_if_whitespace(&self.title, writer)?;
50        writer.write_all(ENDL)?;
51        if let Some(subtitle) = &self.subtitle {
52            writer.write_all(SUB_HEADER)?;
53            writer.write_all(SPACE)?;
54            write_quoted_if_whitespace(subtitle, writer)?;
55            writer.write_all(ENDL)?;
56        }
57
58        let mut was_text = false;
59        for node in &self.nodes {
60            was_text = node.render(writer, was_text)?;
61        }
62
63        Ok(was_text)
64    }
65}