docx_rs/documents/elements/
run.rs

1use super::*;
2use serde::ser::{SerializeStruct, Serializer};
3use serde::Serialize;
4use std::io::Write;
5
6use crate::documents::BuildXML;
7use crate::types::*;
8use crate::xml_builder::*;
9
10#[derive(Serialize, Debug, Clone, PartialEq)]
11#[serde(rename_all = "camelCase")]
12pub struct Run {
13    pub run_property: RunProperty,
14    pub children: Vec<RunChild>,
15}
16
17impl Default for Run {
18    fn default() -> Self {
19        let run_property = RunProperty::new();
20        Self {
21            run_property,
22            children: vec![],
23        }
24    }
25}
26
27#[derive(Debug, Clone, PartialEq)]
28pub enum RunChild {
29    Text(Text),
30    Sym(Sym),
31    DeleteText(DeleteText),
32    Tab(Tab),
33    PTab(PositionalTab),
34    Break(Break),
35    Drawing(Box<Drawing>),
36    Shape(Box<Shape>),
37    CommentStart(Box<CommentRangeStart>),
38    CommentEnd(CommentRangeEnd),
39    FieldChar(FieldChar),
40    InstrText(Box<InstrText>),
41    DeleteInstrText(Box<DeleteInstrText>),
42    // For reader
43    InstrTextString(String),
44    FootnoteReference(FootnoteReference),
45    Shading(Shading),
46}
47
48impl Serialize for RunChild {
49    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
50    where
51        S: Serializer,
52    {
53        match *self {
54            RunChild::Text(ref s) => {
55                let mut t = serializer.serialize_struct("Text", 2)?;
56                t.serialize_field("type", "text")?;
57                t.serialize_field("data", s)?;
58                t.end()
59            }
60            RunChild::Sym(ref s) => {
61                let mut t = serializer.serialize_struct("Sym", 2)?;
62                t.serialize_field("type", "sym")?;
63                t.serialize_field("data", s)?;
64                t.end()
65            }
66            RunChild::DeleteText(ref s) => {
67                let mut t = serializer.serialize_struct("DeleteText", 2)?;
68                t.serialize_field("type", "deleteText")?;
69                t.serialize_field("data", s)?;
70                t.end()
71            }
72            RunChild::Tab(_) => {
73                let mut t = serializer.serialize_struct("Tab", 1)?;
74                t.serialize_field("type", "tab")?;
75                t.end()
76            }
77            RunChild::PTab(ref s) => {
78                let mut t = serializer.serialize_struct("PTab", 1)?;
79                t.serialize_field("type", "ptab")?;
80                t.serialize_field("data", s)?;
81                t.end()
82            }
83            RunChild::Break(ref s) => {
84                let mut t = serializer.serialize_struct("Break", 2)?;
85                t.serialize_field("type", "break")?;
86                t.serialize_field("data", s)?;
87                t.end()
88            }
89            RunChild::Drawing(ref s) => {
90                let mut t = serializer.serialize_struct("Drawing", 2)?;
91                t.serialize_field("type", "drawing")?;
92                t.serialize_field("data", s)?;
93                t.end()
94            }
95            RunChild::Shape(ref s) => {
96                let mut t = serializer.serialize_struct("Shape", 2)?;
97                t.serialize_field("type", "shape")?;
98                t.serialize_field("data", s)?;
99                t.end()
100            }
101            RunChild::CommentStart(ref r) => {
102                let mut t = serializer.serialize_struct("CommentRangeStart", 2)?;
103                t.serialize_field("type", "commentRangeStart")?;
104                t.serialize_field("data", r)?;
105                t.end()
106            }
107            RunChild::CommentEnd(ref r) => {
108                let mut t = serializer.serialize_struct("CommentRangeEnd", 2)?;
109                t.serialize_field("type", "commentRangeEnd")?;
110                t.serialize_field("data", r)?;
111                t.end()
112            }
113            RunChild::FieldChar(ref f) => {
114                let mut t = serializer.serialize_struct("FieldChar", 2)?;
115                t.serialize_field("type", "fieldChar")?;
116                t.serialize_field("data", f)?;
117                t.end()
118            }
119            RunChild::InstrText(ref i) => {
120                let mut t = serializer.serialize_struct("InstrText", 2)?;
121                t.serialize_field("type", "instrText")?;
122                t.serialize_field("data", i)?;
123                t.end()
124            }
125            RunChild::DeleteInstrText(ref i) => {
126                let mut t = serializer.serialize_struct("DeleteInstrText", 2)?;
127                t.serialize_field("type", "deleteInstrText")?;
128                t.serialize_field("data", i)?;
129                t.end()
130            }
131            RunChild::InstrTextString(ref i) => {
132                let mut t = serializer.serialize_struct("InstrTextString", 2)?;
133                t.serialize_field("type", "instrTextString")?;
134                t.serialize_field("data", i)?;
135                t.end()
136            }
137            RunChild::FootnoteReference(ref f) => {
138                let mut t = serializer.serialize_struct("FootnoteReference", 2)?;
139                t.serialize_field("type", "footnoteReference")?;
140                t.serialize_field("data", f)?;
141                t.end()
142            }
143            RunChild::Shading(ref f) => {
144                let mut t = serializer.serialize_struct("Shading", 2)?;
145                t.serialize_field("type", "shading")?;
146                t.serialize_field("data", f)?;
147                t.end()
148            }
149        }
150    }
151}
152
153impl Run {
154    pub fn new() -> Run {
155        Run {
156            ..Default::default()
157        }
158    }
159
160    pub fn add_text(mut self, text: impl Into<String>) -> Run {
161        self.children
162            .push(RunChild::Text(Text::new(text.into().replace('\n', ""))));
163        self
164    }
165
166    pub(crate) fn add_text_without_escape(mut self, text: impl Into<String>) -> Run {
167        self.children.push(RunChild::Text(Text::without_escape(
168            text.into().replace('\n', ""),
169        )));
170        self
171    }
172
173    pub fn add_delete_text(mut self, text: impl Into<String>) -> Run {
174        self.children.push(RunChild::DeleteText(DeleteText::new(
175            text.into().replace('\n', ""),
176        )));
177        self
178    }
179
180    pub(crate) fn add_delete_text_without_escape(mut self, text: impl Into<String>) -> Run {
181        self.children
182            .push(RunChild::DeleteText(DeleteText::without_escape(
183                text.into().replace('\n', ""),
184            )));
185        self
186    }
187
188    pub fn add_field_char(mut self, t: crate::types::FieldCharType, dirty: bool) -> Run {
189        let mut f = FieldChar::new(t);
190        if dirty {
191            f = f.dirty();
192        };
193        self.children.push(RunChild::FieldChar(f));
194        self
195    }
196
197    pub fn add_tc(mut self, tc: InstrTC) -> Run {
198        self = self.add_field_char(crate::types::FieldCharType::Begin, false);
199        self = self.add_instr_text(InstrText::TC(tc));
200        self = self.add_field_char(crate::types::FieldCharType::End, false);
201        self
202    }
203
204    pub fn add_instr_text(mut self, i: InstrText) -> Run {
205        self.children.push(RunChild::InstrText(Box::new(i)));
206        self
207    }
208
209    pub fn add_delete_instr_text(mut self, i: DeleteInstrText) -> Run {
210        self.children.push(RunChild::DeleteInstrText(Box::new(i)));
211        self
212    }
213
214    pub fn add_tab(mut self) -> Run {
215        self.children.push(RunChild::Tab(Tab::new()));
216        self
217    }
218
219    pub fn add_ptab(mut self, ptab: PositionalTab) -> Run {
220        self.children.push(RunChild::PTab(ptab));
221        self
222    }
223
224    pub fn add_image(mut self, pic: Pic) -> Run {
225        self.children
226            .push(RunChild::Drawing(Box::new(Drawing::new().pic(pic))));
227        self
228    }
229
230    pub(crate) fn add_drawing(mut self, d: Drawing) -> Run {
231        self.children.push(RunChild::Drawing(Box::new(d)));
232        self
233    }
234
235    // For now reader only
236    //    pub(crate) fn add_shape(mut self, d: Shape) -> Run {
237    //        self.children.push(RunChild::Shape(Box::new(d)));
238    //        self
239    //    }
240
241    pub fn add_break(mut self, break_type: BreakType) -> Run {
242        self.children.push(RunChild::Break(Break::new(break_type)));
243        self
244    }
245
246    pub fn add_sym(mut self, sym: Sym) -> Run {
247        self.children.push(RunChild::Sym(sym));
248        self
249    }
250
251    pub fn style(mut self, style_id: &str) -> Self {
252        self.run_property = self.run_property.style(style_id);
253        self
254    }
255
256    pub fn size(mut self, size: usize) -> Run {
257        self.run_property = self.run_property.size(size);
258        self
259    }
260
261    pub fn character_spacing(mut self, v: i32) -> Run {
262        self.run_property = self.run_property.spacing(v);
263        self
264    }
265
266    pub fn stretch(mut self, v: i32) -> Run {
267        self.run_property = self.run_property.stretch(v);
268        self
269    }
270
271    pub fn color(mut self, color: impl Into<String>) -> Run {
272        self.run_property = self.run_property.color(color);
273        self
274    }
275
276    pub fn highlight(mut self, color: impl Into<String>) -> Run {
277        self.run_property = self.run_property.highlight(color);
278        self
279    }
280
281    pub fn bold(mut self) -> Run {
282        self.run_property = self.run_property.bold();
283        self
284    }
285
286    pub fn disable_bold(mut self) -> Run {
287        self.run_property = self.run_property.disable_bold();
288        self
289    }
290
291    pub fn italic(mut self) -> Run {
292        self.run_property = self.run_property.italic();
293        self
294    }
295
296    pub fn strike(mut self) -> Run {
297        self.run_property = self.run_property.strike();
298        self
299    }
300
301    pub fn dstrike(mut self) -> Run {
302        self.run_property = self.run_property.dstrike();
303        self
304    }
305
306    pub fn text_border(mut self, b: TextBorder) -> Run {
307        self.run_property = self.run_property.text_border(b);
308        self
309    }
310
311    pub fn disable_italic(mut self) -> Run {
312        self.run_property = self.run_property.disable_italic();
313        self
314    }
315
316    pub fn underline(mut self, line_type: impl Into<String>) -> Run {
317        self.run_property = self.run_property.underline(line_type);
318        self
319    }
320
321    pub fn vanish(mut self) -> Run {
322        self.run_property = self.run_property.vanish();
323        self
324    }
325
326    pub fn fonts(mut self, f: RunFonts) -> Run {
327        self.run_property = self.run_property.fonts(f);
328        self
329    }
330
331    pub(crate) fn set_property(mut self, p: RunProperty) -> Run {
332        self.run_property = p;
333        self
334    }
335
336    pub fn add_footnote_reference(mut self, footnote: Footnote) -> Run {
337        self.run_property = RunProperty::new().style("FootnoteReference");
338        self.children
339            .push(RunChild::FootnoteReference(footnote.into()));
340        self
341    }
342
343    pub fn shading(mut self, shading: Shading) -> Run {
344        self.run_property = self.run_property.shading(shading);
345        self
346    }
347}
348
349impl BuildXML for RunChild {
350    fn build_to<W: Write>(
351        &self,
352        stream: xml::writer::EventWriter<W>,
353    ) -> xml::writer::Result<xml::writer::EventWriter<W>> {
354        match self {
355            RunChild::Text(t) => t.build_to(stream),
356            RunChild::Sym(t) => t.build_to(stream),
357            RunChild::DeleteText(t) => t.build_to(stream),
358            RunChild::Tab(t) => t.build_to(stream),
359            RunChild::PTab(t) => t.build_to(stream),
360            RunChild::Break(t) => t.build_to(stream),
361            RunChild::Drawing(t) => t.build_to(stream),
362            RunChild::Shape(_t) => {
363                todo!("Support shape writer.")
364            }
365            RunChild::CommentStart(c) => c.build_to(stream),
366            RunChild::CommentEnd(c) => c.build_to(stream),
367            RunChild::FieldChar(c) => c.build_to(stream),
368            RunChild::InstrText(c) => c.build_to(stream),
369            RunChild::DeleteInstrText(c) => c.build_to(stream),
370            RunChild::InstrTextString(_) => unreachable!(),
371            RunChild::FootnoteReference(c) => c.build_to(stream),
372            RunChild::Shading(s) => s.build_to(stream),
373        }
374    }
375}
376
377impl BuildXML for Run {
378    fn build_to<W: Write>(
379        &self,
380        stream: xml::writer::EventWriter<W>,
381    ) -> xml::writer::Result<xml::writer::EventWriter<W>> {
382        XMLBuilder::from(stream)
383            .open_run()?
384            .add_child(&self.run_property)?
385            .add_children(&self.children)?
386            .close()?
387            .into_inner()
388    }
389}
390
391#[cfg(test)]
392mod tests {
393
394    use super::*;
395    #[cfg(test)]
396    use pretty_assertions::assert_eq;
397    use std::str;
398
399    #[test]
400    fn test_build() {
401        let b = Run::new().add_text("Hello").build();
402        assert_eq!(
403            str::from_utf8(&b).unwrap(),
404            r#"<w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r>"#
405        );
406    }
407
408    #[test]
409    fn test_underline() {
410        let b = Run::new().add_text("Hello").underline("single").build();
411        assert_eq!(
412            str::from_utf8(&b).unwrap(),
413            r#"<w:r><w:rPr><w:u w:val="single" /></w:rPr><w:t xml:space="preserve">Hello</w:t></w:r>"#
414        );
415    }
416
417    #[test]
418    fn test_strike() {
419        let b = Run::new().add_text("Hello").strike().build();
420        assert_eq!(
421            str::from_utf8(&b).unwrap(),
422            r#"<w:r><w:rPr><w:strike /></w:rPr><w:t xml:space="preserve">Hello</w:t></w:r>"#
423        );
424    }
425
426    #[test]
427    fn test_child_json() {
428        let c = RunChild::Text(Text::new("Hello"));
429        assert_eq!(
430            serde_json::to_string(&c).unwrap(),
431            r#"{"type":"text","data":{"preserveSpace":true,"text":"Hello"}}"#
432        );
433    }
434
435    #[test]
436    fn test_run_json() {
437        let run = Run {
438            children: vec![
439                RunChild::Tab(Tab::new()),
440                RunChild::Text(Text::new("Hello")),
441                RunChild::Break(Break::new(BreakType::Page)),
442                RunChild::DeleteText(DeleteText::new("deleted")),
443            ],
444            run_property: RunProperty {
445                sz: Some(Sz::new(30)),
446                sz_cs: Some(SzCs::new(30)),
447                color: Some(Color::new("C9211E")),
448                highlight: Some(Highlight::new("yellow")),
449                underline: Some(Underline::new("single")),
450                bold: Some(Bold::new()),
451                bold_cs: Some(BoldCs::new()),
452                italic: Some(Italic::new()),
453                italic_cs: Some(ItalicCs::new()),
454                vanish: Some(Vanish::new()),
455                character_spacing: Some(CharacterSpacing::new(100)),
456                ..RunProperty::default()
457            },
458        };
459        assert_eq!(
460            serde_json::to_string(&run).unwrap(),
461            r#"{"runProperty":{"sz":30,"szCs":30,"color":"C9211E","highlight":"yellow","underline":"single","bold":true,"boldCs":true,"italic":true,"italicCs":true,"vanish":true,"characterSpacing":100},"children":[{"type":"tab"},{"type":"text","data":{"preserveSpace":true,"text":"Hello"}},{"type":"break","data":{"breakType":"page"}},{"type":"deleteText","data":{"text":"deleted","preserveSpace":true}}]}"#,
462        );
463    }
464
465    #[test]
466    fn test_run_footnote_reference() {
467        let c = RunChild::FootnoteReference(FootnoteReference::new(1));
468        assert_eq!(
469            serde_json::to_string(&c).unwrap(),
470            r#"{"type":"footnoteReference","data":{"id":1}}"#
471        );
472    }
473
474    #[test]
475    fn test_run_shading() {
476        let c = RunChild::Shading(Shading::new());
477        assert_eq!(
478            serde_json::to_string(&c).unwrap(),
479            r#"{"type":"shading","data":{"shdType":"clear","color":"auto","fill":"FFFFFF"}}"#
480        );
481    }
482}