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#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
40#[cfg_attr(test, derive(PartialEq))]
41#[xml(tag = "w:r")]
42pub struct Run<'a> {
43 #[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 #[xml(child = "w:rPr")]
51 pub property: Option<CharacterProperty<'a>>,
52 #[xml(
53 child = "w:br", child = "w:t", child = "w:delText", child = "w:instrText", child = "w:delInstrText", child = "w:noBreakHyphen", child = "w:softHyphen", child = "w:dayShort", child = "w:monthShort", child = "w:yearShort", child = "w:dayLong", child = "w:monthLong", child = "w:yearLong", child = "w:annotationRef", child = "w:footnoteRef", child = "w:endnoteRef", child = "w:separator", child = "w:continuationSeparator", child = "w:sym", child = "w:pgNum", child = "w:cr", child = "w:tab", child = "w:fldChar", child = "w:footnoteReference", child = "w:endnoteReference", child = "w:commentReference", child = "w:drawing", child = "w:ptab", child = "w:lastRenderedPageBreak", )]
86 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#[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:fldChar")]
233 FieldChar(FieldChar),
234 #[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 "w:relativeTo", relative_to, PTabRelativeTo "w:leader", leader, PTabLeader }
256}
257
258__define_enum! {
259 PTabAlignment {
260 Left = "left", Center = "center", Right = "right", }
264}
265
266__define_enum! {
267 PTabRelativeTo {
268 Margin = "margin", Indent = "indent", }
271}
272
273__define_enum! {
274 PTabLeader {
275 None = "none", Dot = "dot", Hyphen = "hyphen", Underscore = "underscore", MiddleDot = "middleDot", }
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);