docx_rust/document/
run.rs

1#![allow(unused_must_use)]
2use derive_more::From;
3use hard_xml::{XmlRead, XmlWrite};
4use std::borrow::{Borrow, Cow};
5
6use crate::{
7    __setter, __xml_test_suites,
8    document::{
9        drawing::Drawing, field_char::FieldChar, instrtext::InstrText, r#break::Break,
10        r#break::LastRenderedPageBreak, tab::Tab, text::Text,
11    },
12    formatting::CharacterProperty,
13    DocxResult, __define_enum, __define_struct,
14};
15
16use super::{
17    date::{DayLong, DayShort, MonthLong, MonthShort, YearLong, YearShort},
18    instrtext::DelInstrText,
19    sym::Sym,
20    AnnotationRef, CarriageReturn, CommentReference, DelText, EndnoteRef, EndnoteReference,
21    FootnoteRef, FootnoteReference,
22};
23
24/// Run
25///
26/// Run is a non-block region of text with properties.
27///
28/// ```rust
29/// use docx_rust::document::*;
30/// use docx_rust::formatting::*;
31///
32/// let run = Run::default()
33///     .property(CharacterProperty::default())
34///     .push_text("text")
35///     .push_break(None)
36///     .push_text((" text ", TextSpace::Preserve))
37///     .push_break(BreakType::Column);
38/// ```
39#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
40#[cfg_attr(test, derive(PartialEq))]
41#[xml(tag = "w:r")]
42pub struct Run<'a> {
43    /// Specifies the properties of a run
44    ///
45    #[xml(attr = "w:rsidR")]
46    pub rsid_r: Option<Cow<'a, str>>,
47    #[xml(attr = "w:rsidRDefault")]
48    pub rsid_r_default: Option<Cow<'a, str>>,
49    /// Just as paragraph, a run's properties is applied to all the contents of the run.
50    #[xml(child = "w:rPr")]
51    pub property: Option<CharacterProperty<'a>>,
52    #[xml(
53        child = "w:br", //Break
54        child = "w:t", //Text
55        child = "w:delText", //Deleted Text
56        child = "w:instrText", //Field Code
57        child = "w:delInstrText", //Deleted Field Code
58        child = "w:noBreakHyphen", //Non Breaking Hyphen Character
59        child = "w:softHyphen", //Optional Hyphen Character
60        child = "w:dayShort", //Date Block - Short Day Format
61        child = "w:monthShort", //Date Block - Short Month Format
62        child = "w:yearShort", //Date Block - Short Year Format
63        child = "w:dayLong", //Date Block - Long Day Format
64        child = "w:monthLong", //Date Block - Long Month Format
65        child = "w:yearLong", //Date Block - Long Year Format
66        child = "w:annotationRef", //Comment Information Block
67        child = "w:footnoteRef", //Footnote Reference Mark
68        child = "w:endnoteRef", //Endnote Reference Mark
69        child = "w:separator", //Footnote/Endnote Separator Mark
70        child = "w:continuationSeparator", //Continuation Separator Mark
71        child = "w:sym", //Symbol Character
72        child = "w:pgNum", //Page Number Block
73        child = "w:cr", //Carriage Return
74        child = "w:tab", //Tab Character
75        //child = "w:object", //Inline Embedded Object
76        //child = "w:pict", //VML Object
77        child = "w:fldChar", //Complex Field Character
78        //child = "w:ruby", //Phonetic Guide
79        child = "w:footnoteReference", //Footnote Reference
80        child = "w:endnoteReference", //Endnote Reference
81        child = "w:commentReference", //Comment Content Reference Mark
82        child = "w:drawing", //DrawingML Object
83        child = "w:ptab", //Absolute Position Tab Character
84        child = "w:lastRenderedPageBreak", //Position of Last Calculated Page Break
85    )]
86    /// Specifies the content of a run
87    pub content: Vec<RunContent<'a>>,
88}
89
90impl<'a> Run<'a> {
91    __setter!(property: Option<CharacterProperty<'a>>);
92
93    #[inline(always)]
94    pub fn push<T: Into<RunContent<'a>>>(mut self, content: T) -> Self {
95        self.content.push(content.into());
96        self
97    }
98
99    #[inline(always)]
100    pub fn push_text<T: Into<Text<'a>>>(mut self, content: T) -> Self {
101        self.content.push(RunContent::Text(content.into()));
102        self
103    }
104
105    #[inline(always)]
106    pub fn push_break<T: Into<Break>>(mut self, br: T) -> Self {
107        self.content.push(RunContent::Break(br.into()));
108        self
109    }
110
111    pub fn text(&self) -> String {
112        self.iter_text()
113            .map(|c| c.to_string())
114            .collect::<Vec<_>>()
115            .join("")
116    }
117
118    pub fn iter_text(&self) -> Box<dyn Iterator<Item = &Cow<'a, str>> + '_> {
119        Box::new(self.content.iter().filter_map(|content| match content {
120            RunContent::Text(Text { text, .. }) => Some(text),
121            RunContent::InstrText(InstrText { text, .. }) => Some(text),
122            RunContent::Break(_) => None,
123            RunContent::LastRenderedPageBreak(_) => None,
124            RunContent::FieldChar(_) => None,
125            RunContent::Separator(_) => None,
126            RunContent::ContinuationSeparator(_) => None,
127            RunContent::Tab(_) => None,
128            RunContent::CarriageReturn(_) => None,
129            RunContent::Drawing(_) => None,
130            _ => None,
131        }))
132    }
133
134    pub fn iter_text_mut(&mut self) -> Box<dyn Iterator<Item = &mut Cow<'a, str>> + '_> {
135        Box::new(self.content.iter_mut().filter_map(|content| match content {
136            RunContent::Text(Text { text, .. }) => Some(text),
137            RunContent::InstrText(InstrText { text, .. }) => Some(text),
138            RunContent::Break(_) => None,
139            RunContent::LastRenderedPageBreak(_) => None,
140            RunContent::FieldChar(_) => None,
141            RunContent::Separator(_) => None,
142            RunContent::ContinuationSeparator(_) => None,
143            RunContent::Tab(_) => None,
144            RunContent::CarriageReturn(_) => None,
145            RunContent::Drawing(_) => None,
146            _ => None,
147        }))
148    }
149
150    pub fn replace_text_simple<S>(&mut self, old: S, new: S)
151    where
152        S: AsRef<str>,
153    {
154        self.replace_text(&[(old, new)]);
155    }
156
157    pub fn replace_text<'b, I, T, S>(&mut self, dic: T) -> DocxResult<()>
158    where
159        S: AsRef<str> + 'b,
160        T: IntoIterator<Item = I> + Copy,
161        I: Borrow<(S, S)>,
162    {
163        for c in self.content.iter_mut() {
164            match c {
165                RunContent::Text(t) => {
166                    let mut tc = t.text.to_string();
167                    for p in dic {
168                        tc = tc.replace(p.borrow().0.as_ref(), p.borrow().1.as_ref());
169                    }
170                    t.text = tc.into();
171                }
172                _ => {}
173            }
174        }
175
176        Ok(())
177    }
178}
179
180/// A set of elements that can be contained as the content of a run.
181#[derive(Debug, From, XmlRead, XmlWrite, Clone)]
182#[cfg_attr(test, derive(PartialEq))]
183pub enum RunContent<'a> {
184    #[xml(tag = "w:br")]
185    Break(Break),
186    #[xml(tag = "w:t")]
187    Text(Text<'a>),
188    #[xml(tag = "w:delText")]
189    DelText(DelText<'a>),
190    #[xml(tag = "w:instrText")]
191    InstrText(InstrText<'a>),
192    #[xml(tag = "w:delInstrText")]
193    DelInstrText(DelInstrText<'a>),
194    #[xml(tag = "w:noBreakHyphen")]
195    NoBreakHyphen(NoBreakHyphen),
196    #[xml(tag = "w:softHyphen")]
197    SoftHyphen(SoftHyphen),
198    #[xml(tag = "w:dayShort")]
199    DayShort(DayShort),
200    #[xml(tag = "w:monthShort")]
201    MonthShort(MonthShort),
202    #[xml(tag = "w:yearShort")]
203    YearShort(YearShort),
204    #[xml(tag = "w:dayLong")]
205    DayLong(DayLong),
206    #[xml(tag = "w:monthLong")]
207    MonthLong(MonthLong),
208    #[xml(tag = "w:yearLong")]
209    YearLong(YearLong),
210    #[xml(tag = "w:annotationRef")]
211    AnnotationRef(AnnotationRef),
212    #[xml(tag = "w:footnoteRef")]
213    FootnoteRef(FootnoteRef),
214    #[xml(tag = "w:endnoteRef")]
215    EndnoteRef(EndnoteRef),
216    #[xml(tag = "w:separator")]
217    Separator(Separator),
218    #[xml(tag = "w:continuationSeparator")]
219    ContinuationSeparator(ContinuationSeparator),
220    #[xml(tag = "w:sym")]
221    Sym(Sym<'a>),
222    #[xml(tag = "w:pgNum")]
223    PgNum(PgNum),
224    #[xml(tag = "w:cr")]
225    CarriageReturn(CarriageReturn),
226    #[xml(tag = "w:tab")]
227    Tab(Tab),
228    //#[xml(tag = "w:object")]
229    //Object(Object<'a>),
230    //#[xml(tag = "w:pict")]
231    //Pict(Pict<'a>),
232    #[xml(tag = "w:fldChar")]
233    FieldChar(FieldChar),
234    //#[xml(tag = "w:ruby")]
235    //Ruby(Ruby<'a>),
236    #[xml(tag = "w:footnoteReference")]
237    FootnoteReference(FootnoteReference<'a>),
238    #[xml(tag = "w:endnoteReference")]
239    EndnoteReference(EndnoteReference<'a>),
240    #[xml(tag = "w:commentReference")]
241    CommentReference(CommentReference<'a>),
242    #[xml(tag = "w:drawing")]
243    Drawing(Drawing<'a>),
244    #[xml(tag = "w:ptab")]
245    PTab(PTab),
246    #[xml(tag = "w:lastRenderedPageBreak")]
247    LastRenderedPageBreak(LastRenderedPageBreak),
248}
249
250__define_struct! {
251    ("w:ptab", PTab) {
252        "w:alignment", alignment,	PTabAlignment	//Positional Tab Stop Alignment
253        "w:relativeTo",	relative_to,	PTabRelativeTo	//Positional Tab Base
254        "w:leader",	leader,	PTabLeader	//Tab Leader Character
255    }
256}
257
258__define_enum! {
259    PTabAlignment {
260        Left = "left", // Left
261        Center = "center", // Center
262        Right = "right", // Right
263    }
264}
265
266__define_enum! {
267    PTabRelativeTo {
268        Margin = "margin", // Relative To Text Margins
269        Indent = "indent", // Relative To Indents
270    }
271}
272
273__define_enum! {
274    PTabLeader {
275        None = "none", // No Leader Character
276        Dot = "dot", // Dot Leader Character
277        Hyphen = "hyphen", // Hyphen Leader Character
278        Underscore = "underscore", // Underscore Leader Character
279        MiddleDot = "middleDot", // Centered Dot Leader Character
280    }
281}
282
283#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
284#[cfg_attr(test, derive(PartialEq))]
285#[xml(tag = "w:noBreakHyphen")]
286pub struct NoBreakHyphen;
287
288#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
289#[cfg_attr(test, derive(PartialEq))]
290#[xml(tag = "w:softHyphen")]
291pub struct SoftHyphen {}
292
293#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
294#[cfg_attr(test, derive(PartialEq))]
295#[xml(tag = "w:separator")]
296pub struct Separator {}
297
298#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
299#[cfg_attr(test, derive(PartialEq))]
300#[xml(tag = "w:continuationSeparator")]
301pub struct ContinuationSeparator {}
302
303#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
304#[cfg_attr(test, derive(PartialEq))]
305#[xml(tag = "w:pgNum")]
306pub struct PgNum {}
307
308__xml_test_suites!(
309    Run,
310    Run::default(),
311    r#"<w:r/>"#,
312    Run::default().push_break(None),
313    r#"<w:r><w:br/></w:r>"#,
314    Run::default().push_text("text"),
315    r#"<w:r><w:t>text</w:t></w:r>"#,
316);