Skip to content

Commit 2ae569f

Browse files
authored
Support carriage return runs (#887)
* Support carriage return runs * Update snapshot for carriage return runs
1 parent bc74fbc commit 2ae569f

12 files changed

Lines changed: 99 additions & 2 deletions

File tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use serde::ser::{Serialize, SerializeStruct, Serializer};
2+
use serde::Deserialize;
3+
use std::io::Write;
4+
5+
use crate::documents::BuildXML;
6+
use crate::xml_builder::*;
7+
8+
#[derive(Debug, Clone, Deserialize, PartialEq)]
9+
pub struct CarriageReturn {}
10+
11+
impl CarriageReturn {
12+
pub fn new() -> CarriageReturn {
13+
CarriageReturn {}
14+
}
15+
}
16+
17+
impl BuildXML for CarriageReturn {
18+
fn build_to<W: Write>(
19+
&self,
20+
stream: crate::xml::writer::EventWriter<W>,
21+
) -> crate::xml::writer::Result<crate::xml::writer::EventWriter<W>> {
22+
XMLBuilder::from(stream).cr()?.into_inner()
23+
}
24+
}
25+
26+
impl Serialize for CarriageReturn {
27+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
28+
where
29+
S: Serializer,
30+
{
31+
let t = serializer.serialize_struct("CarriageReturn", 0)?;
32+
t.end()
33+
}
34+
}

docx-core/src/documents/elements/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod comment;
1717
mod comment_extended;
1818
mod comment_range_end;
1919
mod comment_range_start;
20+
mod cr;
2021
mod data_binding;
2122
mod default_tab_stop;
2223
mod delete;
@@ -158,6 +159,7 @@ pub use comment::*;
158159
pub use comment_extended::*;
159160
pub use comment_range_end::*;
160161
pub use comment_range_start::*;
162+
pub use cr::*;
161163
pub use data_binding::*;
162164
pub use default_tab_stop::*;
163165
pub use delete::*;

docx-core/src/documents/elements/run.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub enum RunChild {
3232
Tab(Tab),
3333
PTab(PositionalTab),
3434
Break(Break),
35+
CarriageReturn(CarriageReturn),
3536
Drawing(Box<Drawing>),
3637
Shape(Box<Shape>),
3738
CommentStart(Box<CommentRangeStart>),
@@ -86,6 +87,11 @@ impl Serialize for RunChild {
8687
t.serialize_field("data", s)?;
8788
t.end()
8889
}
90+
RunChild::CarriageReturn(_) => {
91+
let mut t = serializer.serialize_struct("CarriageReturn", 1)?;
92+
t.serialize_field("type", "carriageReturn")?;
93+
t.end()
94+
}
8995
RunChild::Drawing(ref s) => {
9096
let mut t = serializer.serialize_struct("Drawing", 2)?;
9197
t.serialize_field("type", "drawing")?;
@@ -243,6 +249,12 @@ impl Run {
243249
self
244250
}
245251

252+
pub fn add_carriage_return(mut self) -> Run {
253+
self.children
254+
.push(RunChild::CarriageReturn(CarriageReturn::new()));
255+
self
256+
}
257+
246258
pub fn add_sym(mut self, sym: Sym) -> Run {
247259
self.children.push(RunChild::Sym(sym));
248260
self
@@ -358,6 +370,7 @@ impl BuildXML for RunChild {
358370
RunChild::Tab(t) => t.build_to(stream),
359371
RunChild::PTab(t) => t.build_to(stream),
360372
RunChild::Break(t) => t.build_to(stream),
373+
RunChild::CarriageReturn(t) => t.build_to(stream),
361374
RunChild::Drawing(t) => t.build_to(stream),
362375
RunChild::Shape(_t) => {
363376
todo!("Support shape writer.")
@@ -439,6 +452,7 @@ mod tests {
439452
RunChild::Tab(Tab::new()),
440453
RunChild::Text(Text::new("Hello")),
441454
RunChild::Break(Break::new(BreakType::Page)),
455+
RunChild::CarriageReturn(CarriageReturn::new()),
442456
RunChild::DeleteText(DeleteText::new("deleted")),
443457
],
444458
run_property: RunProperty {
@@ -458,7 +472,7 @@ mod tests {
458472
};
459473
assert_eq!(
460474
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}}]}"#,
475+
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}}]}"#,
462476
);
463477
}
464478

docx-core/src/reader/run.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ impl ElementReader for Run {
9494
run = run.add_break(BreakType::TextWrapping)
9595
}
9696
}
97+
XMLElement::CarriageReturn => {
98+
run = run.add_carriage_return();
99+
}
97100
XMLElement::Drawing => {
98101
if let Ok(drawing) = Drawing::read(r, &attributes) {
99102
run = run.add_drawing(drawing);
@@ -262,6 +265,22 @@ mod tests {
262265
);
263266
}
264267

268+
#[test]
269+
fn test_read_cr() {
270+
let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
271+
<w:r><w:cr /></w:r>
272+
</w:document>"#;
273+
let mut parser = EventReader::new(c.as_bytes());
274+
let run = Run::read(&mut parser, &[]).unwrap();
275+
assert_eq!(
276+
run,
277+
Run {
278+
children: vec![RunChild::CarriageReturn(CarriageReturn::new())],
279+
run_property: RunProperty::default(),
280+
}
281+
);
282+
}
283+
265284
#[test]
266285
fn test_read_italic_false() {
267286
let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">

docx-core/src/reader/xml_element.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub enum XMLElement {
3535
RunStyle,
3636
BoldCs,
3737
Break,
38+
CarriageReturn,
3839
Tab,
3940
Tabs,
4041
PTab,
@@ -293,6 +294,7 @@ impl FromStr for XMLElement {
293294
"tabs" => Ok(XMLElement::Tabs),
294295
"ptab" => Ok(XMLElement::PTab),
295296
"br" => Ok(XMLElement::Break),
297+
"cr" => Ok(XMLElement::CarriageReturn),
296298
"ind" => Ok(XMLElement::Indent),
297299
"numPr" => Ok(XMLElement::NumberingProperty),
298300
"ilvl" => Ok(XMLElement::IndentLevel),

docx-core/src/xml_builder/elements.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ impl<W: Write> XMLBuilder<W> {
403403
closed!(tab_with_pos, "w:tab", "w:val", "w:pos");
404404

405405
closed!(br, "w:br", "w:type");
406+
closed!(cr, "w:cr");
406407
closed!(sym, "w:sym", "w:font", "w:char");
407408
closed!(zoom, "w:zoom", "w:percent");
408409
closed_with_usize!(default_tab_stop, "w:defaultTabStop");

docx-wasm/js/carriage-return.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export class CarriageReturn {}

docx-wasm/js/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,7 @@ export * from "./abstract-numbering";
716716
export * from "./bookmark-start";
717717
export * from "./bookmark-end";
718718
export * from "./break";
719+
export * from "./carriage-return";
719720
export * from "./delete-text";
720721
export * from "./level";
721722
export * from "./tab";

docx-wasm/js/json/run.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export type RunChildJSON =
7171
| SymJSON
7272
| DeleteTextJSON
7373
| TabJSON
74+
| CarriageReturnJSON
7475
| BreakJSON
7576
| DrawingJSON
7677
| PtabJSON
@@ -117,6 +118,10 @@ export type TabJSON = {
117118
type: "tab";
118119
};
119120

121+
export type CarriageReturnJSON = {
122+
type: "carriageReturn";
123+
};
124+
120125
export type BreakJSON = {
121126
type: "break";
122127
data: {

docx-wasm/js/run.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Text } from "./text";
44
import { DeleteText } from "./delete-text";
55
import { Tab } from "./tab";
66
import { Break, BreakType } from "./break";
7+
import { CarriageReturn } from "./carriage-return";
78
import { BorderType } from "./border";
89
import { Image } from "./image";
910
import { PositionalTab } from "./positional-tab";
@@ -20,6 +21,7 @@ export type RunChild =
2021
| Text
2122
| DeleteText
2223
| Tab
24+
| CarriageReturn
2325
| Break
2426
| Image
2527
| PositionalTab
@@ -59,6 +61,11 @@ export class Run {
5961
return this;
6062
}
6163

64+
addCarriageReturn() {
65+
this.children.push(new CarriageReturn());
66+
return this;
67+
}
68+
6269
addTc(tc: Tc) {
6370
this.children.push(tc);
6471
return this;
@@ -187,6 +194,8 @@ export class Run {
187194
run = run.add_delete_text(child.text);
188195
} else if (child instanceof Tab) {
189196
run = run.add_tab();
197+
} else if (child instanceof CarriageReturn) {
198+
run = run.add_carriage_return();
190199
} else if (child instanceof PositionalTab) {
191200
run = run.add_ptab(child.buildWasmObject());
192201
} else if (child instanceof Break) {

0 commit comments

Comments
 (0)