docx_rs/documents/elements/
instr_tc.rs

1use serde::Serialize;
2use std::io::Write;
3
4use crate::documents::*;
5use crate::escape::escape;
6use crate::xml_builder::XMLBuilder;
7
8// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_TCTC_topic_ID0EU2N1.html
9#[derive(Serialize, Debug, Clone, PartialEq, Default)]
10#[serde(rename_all = "camelCase")]
11pub struct InstrTC {
12    pub text: String,
13    // \n Omits the page number for the entry.
14    pub omits_page_number: bool,
15    pub level: Option<usize>,
16    // \f
17    pub item_type_identifier: Option<String>,
18}
19
20impl InstrTC {
21    pub fn new(text: impl Into<String>) -> Self {
22        Self {
23            text: escape(&text.into()),
24            ..Default::default()
25        }
26    }
27
28    pub fn omits_page_number(mut self) -> Self {
29        self.omits_page_number = true;
30        self
31    }
32
33    pub fn level(mut self, level: usize) -> Self {
34        self.level = Some(level);
35        self
36    }
37
38    pub fn item_type_identifier(mut self, t: impl Into<String>) -> Self {
39        self.item_type_identifier = Some(t.into());
40        self
41    }
42}
43
44impl BuildXML for InstrTC {
45    fn build_to<W: Write>(
46        &self,
47        stream: xml::writer::EventWriter<W>,
48    ) -> xml::writer::Result<xml::writer::EventWriter<W>> {
49        let mut b = XMLBuilder::from(stream);
50        let raw = b.inner_mut()?;
51
52        write!(raw, "TC \"{}\"", self.text)?;
53
54        if let Some(ref t) = self.item_type_identifier {
55            write!(raw, " \\f {}", t)?;
56        }
57
58        if let Some(level) = self.level {
59            write!(raw, " \\l {}", level)?;
60        }
61
62        if self.omits_page_number {
63            write!(raw, " \\n")?;
64        }
65
66        b.into_inner()
67    }
68}
69
70fn parse_level(i: &str) -> Option<usize> {
71    let r = i.replace("&quot;", "").replace('\"', "");
72    if let Ok(l) = usize::from_str(&r) {
73        return Some(l);
74    }
75    None
76}
77
78impl std::str::FromStr for InstrTC {
79    type Err = ();
80
81    fn from_str(instr: &str) -> Result<Self, Self::Err> {
82        let mut s = instr.split(' ');
83        let text = s.next();
84        let mut tc = InstrTC::new(text.unwrap_or_default());
85        loop {
86            if let Some(i) = s.next() {
87                match i {
88                    "\\f" => {
89                        if let Some(r) = s.next() {
90                            let r = r.replace("&quot;", "").replace('\"', "");
91                            tc = tc.item_type_identifier(r);
92                        }
93                    }
94                    "\\l" => {
95                        if let Some(r) = s.next() {
96                            if let Some(l) = parse_level(r) {
97                                tc = tc.level(l);
98                            }
99                        }
100                    }
101                    "\\n" => tc = tc.omits_page_number(),
102                    _ => {}
103                }
104            } else {
105                return Ok(tc);
106            }
107        }
108    }
109}