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 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 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}