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