feat: Support space:preserve
parent
37d4a157d5
commit
517c3b0b9f
|
@ -5,18 +5,21 @@ use crate::xml_builder::*;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Text {
|
pub struct Text {
|
||||||
text: String,
|
text: String,
|
||||||
|
preserve_space: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Text {
|
impl Text {
|
||||||
pub fn new(text: impl Into<String>) -> Text {
|
pub fn new(text: impl Into<String>) -> Text {
|
||||||
Text { text: text.into() }
|
Text {
|
||||||
|
text: text.into(),
|
||||||
|
preserve_space: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildXML for Text {
|
impl BuildXML for Text {
|
||||||
fn build(&self) -> Vec<u8> {
|
fn build(&self) -> Vec<u8> {
|
||||||
let b = XMLBuilder::new();
|
XMLBuilder::new().text(&self.text, true).build()
|
||||||
b.text(&self.text).build()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,11 @@ pub fn simple() {
|
||||||
let path = std::path::Path::new("./test.docx");
|
let path = std::path::Path::new("./test.docx");
|
||||||
let file = std::fs::File::create(&path).unwrap();
|
let file = std::fs::File::create(&path).unwrap();
|
||||||
Docx::new()
|
Docx::new()
|
||||||
.add_paragraph(Paragraph::new().add_run(Run::new("Hello")))
|
.add_paragraph(
|
||||||
|
Paragraph::new()
|
||||||
|
.add_run(Run::new("Hello"))
|
||||||
|
.add_run(Run::new(" World")),
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
.pack(file);
|
.pack(file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
use super::XMLBuilder;
|
||||||
|
use super::XmlEvent;
|
||||||
|
use crate::types::*;
|
||||||
|
|
||||||
|
impl XMLBuilder {
|
||||||
|
// i.e. <w:body... >
|
||||||
|
opened_el!(open_body, "w:body");
|
||||||
|
// i.e. <w:basedOn ... >
|
||||||
|
only_str_val_el!(based_on, "w:basedOn");
|
||||||
|
// i.e. <w:t ... >
|
||||||
|
// i.e. <w:sz ... >
|
||||||
|
pub(crate) fn text(mut self, text: &str, preserve_space: bool) -> Self {
|
||||||
|
let space = if preserve_space {
|
||||||
|
"preserve"
|
||||||
|
} else {
|
||||||
|
"default"
|
||||||
|
};
|
||||||
|
self.writer
|
||||||
|
.write(XmlEvent::start_element("w:t").attr("xml:space", space))
|
||||||
|
.expect("should write to buf");
|
||||||
|
self.writer.write(text).expect("should write to buf");
|
||||||
|
self.close()
|
||||||
|
}
|
||||||
|
// i.e. <w:r ... >
|
||||||
|
opened_el!(open_run, "w:r");
|
||||||
|
opened_el!(open_run_property, "w:rPr");
|
||||||
|
opened_el!(open_run_property_default, "w:rPrDefault");
|
||||||
|
// i.e. <w:qFormat ... >
|
||||||
|
closed_el!(q_format, "w:qFormat");
|
||||||
|
// i.e. <w:p ... >
|
||||||
|
opened_el!(open_paragraph, "w:p");
|
||||||
|
opened_el!(open_paragraph_property, "w:pPr");
|
||||||
|
opened_el!(open_doc_defaults, "w:docDefaults");
|
||||||
|
// i.e. <w:name ... >
|
||||||
|
only_str_val_el!(name, "w:name");
|
||||||
|
// i.e. <w:sz ... >
|
||||||
|
pub(crate) fn sz(mut self, val: usize) -> Self {
|
||||||
|
self.writer
|
||||||
|
.write(XmlEvent::start_element("w:sz").attr("w:val", &format!("{}", val)))
|
||||||
|
.expect("should write to buf");
|
||||||
|
self.close()
|
||||||
|
}
|
||||||
|
// Build w:style element
|
||||||
|
// i.e. <w:style ... >
|
||||||
|
pub(crate) fn open_style(mut self, style_type: StyleType, id: &str) -> Self {
|
||||||
|
self.writer
|
||||||
|
.write(
|
||||||
|
XmlEvent::start_element("w:style")
|
||||||
|
.attr("w:type", &style_type.to_string())
|
||||||
|
.attr("w:styleId", id),
|
||||||
|
)
|
||||||
|
.expect("should write to buf");
|
||||||
|
self
|
||||||
|
}
|
||||||
|
// i.e. <w:next ... >
|
||||||
|
pub(crate) fn next(mut self, val: &str) -> Self {
|
||||||
|
self.writer
|
||||||
|
.write(XmlEvent::start_element("w:next").attr("w:val", val))
|
||||||
|
.expect("should write to buf");
|
||||||
|
self.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// i.e. <w:color ... >
|
||||||
|
pub(crate) fn color(mut self, val: &str) -> Self {
|
||||||
|
self.writer
|
||||||
|
.write(XmlEvent::start_element("w:color").attr("w:val", val))
|
||||||
|
.expect("should write to buf");
|
||||||
|
self.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
#[cfg(test)]
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sz() {
|
||||||
|
let b = XMLBuilder::new();
|
||||||
|
let r = b.sz(20).build();
|
||||||
|
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:sz w:val="20" />"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_declaration() {
|
||||||
|
let b = XMLBuilder::new();
|
||||||
|
let r = b
|
||||||
|
.open_style(StyleType::Paragraph, "Heading")
|
||||||
|
.close()
|
||||||
|
.build();
|
||||||
|
assert_eq!(
|
||||||
|
str::from_utf8(&r).unwrap(),
|
||||||
|
r#"<w:style w:type="paragraph" w:styleId="Heading" />"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_next() {
|
||||||
|
let b = XMLBuilder::new();
|
||||||
|
let r = b.next("Normal").build();
|
||||||
|
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:next w:val="Normal" />"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_name() {
|
||||||
|
let b = XMLBuilder::new();
|
||||||
|
let r = b.name("Heading").build();
|
||||||
|
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:name w:val="Heading" />"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_color() {
|
||||||
|
let b = XMLBuilder::new();
|
||||||
|
let r = b.color("2E74B5").build();
|
||||||
|
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:color w:val="2E74B5" />"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_based_on() {
|
||||||
|
let b = XMLBuilder::new();
|
||||||
|
let r = b.based_on("Normal").build();
|
||||||
|
assert_eq!(
|
||||||
|
str::from_utf8(&r).unwrap(),
|
||||||
|
r#"<w:basedOn w:val="Normal" />"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
use super::XMLBuilder;
|
|
||||||
use super::XmlEvent;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
// i.e. <w:basedOn ... >
|
|
||||||
only_str_val_el!(based_on, "w:basedOn");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
#[cfg(test)]
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_based_on() {
|
|
||||||
let b = XMLBuilder::new();
|
|
||||||
let r = b.based_on("Normal").build();
|
|
||||||
assert_eq!(
|
|
||||||
str::from_utf8(&r).unwrap(),
|
|
||||||
r#"<w:basedOn w:val="Normal" />"#
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
use super::XMLBuilder;
|
|
||||||
use super::XmlEvent;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
// i.e. <w:body... >
|
|
||||||
opened_el!(open_body, "w:body");
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
use super::XMLBuilder;
|
|
||||||
use super::XmlEvent;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
// i.e. <w:color ... >
|
|
||||||
pub(crate) fn color(mut self, val: &str) -> Self {
|
|
||||||
self.writer
|
|
||||||
.write(XmlEvent::start_element("w:color").attr("w:val", val))
|
|
||||||
.expect("should write to buf");
|
|
||||||
self.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
#[cfg(test)]
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_color() {
|
|
||||||
let b = XMLBuilder::new();
|
|
||||||
let r = b.color("2E74B5").build();
|
|
||||||
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:color w:val="2E74B5" />"#);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
use super::super::XmlEvent;
|
|
||||||
use crate::xml_builder::*;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
opened_el!(open_doc_defaults, "w:docDefaults");
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
macro_rules! only_str_val_el {
|
|
||||||
($name: ident, $el_name: expr) => {
|
|
||||||
pub(crate) fn $name(mut self, val: &str) -> Self {
|
|
||||||
self.writer
|
|
||||||
.write(XmlEvent::start_element($el_name).attr("w:val", val))
|
|
||||||
.expect("should write to buf");
|
|
||||||
self.close()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! only_usize_val_el {
|
|
||||||
($name: ident, $el_name: expr) => {
|
|
||||||
pub(crate) fn $name(mut self, val: usize) -> Self {
|
|
||||||
self.writer
|
|
||||||
.write(XmlEvent::start_element($el_name).attr("w:val", val))
|
|
||||||
.expect("should write to buf");
|
|
||||||
self.close()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
#[macro_use]
|
|
||||||
mod macros;
|
|
||||||
|
|
||||||
pub mod based_on;
|
|
||||||
pub mod body;
|
|
||||||
pub mod color;
|
|
||||||
pub mod doc_defaults;
|
|
||||||
pub mod name;
|
|
||||||
pub mod next;
|
|
||||||
pub mod paragraph;
|
|
||||||
pub mod paragraph_property;
|
|
||||||
pub mod q_format;
|
|
||||||
pub mod run;
|
|
||||||
pub mod run_property;
|
|
||||||
pub mod run_property_default;
|
|
||||||
pub mod style;
|
|
||||||
pub mod sz;
|
|
||||||
pub mod text;
|
|
||||||
|
|
||||||
use super::{XMLBuilder, XmlEvent};
|
|
|
@ -1,25 +0,0 @@
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
use super::XMLBuilder;
|
|
||||||
use super::XmlEvent;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
// i.e. <w:name ... >
|
|
||||||
only_str_val_el!(name, "w:name");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
#[cfg(test)]
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_name() {
|
|
||||||
let b = XMLBuilder::new();
|
|
||||||
let r = b.name("Heading").build();
|
|
||||||
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:name w:val="Heading" />"#);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
use super::XMLBuilder;
|
|
||||||
use super::XmlEvent;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
// i.e. <w:next ... >
|
|
||||||
pub(crate) fn next(mut self, val: &str) -> Self {
|
|
||||||
self.writer
|
|
||||||
.write(XmlEvent::start_element("w:next").attr("w:val", val))
|
|
||||||
.expect("should write to buf");
|
|
||||||
self.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
#[cfg(test)]
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_next() {
|
|
||||||
let b = XMLBuilder::new();
|
|
||||||
let r = b.next("Normal").build();
|
|
||||||
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:next w:val="Normal" />"#);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
use super::XMLBuilder;
|
|
||||||
use super::XmlEvent;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
// i.e. <w:p ... >
|
|
||||||
opened_el!(open_paragraph, "w:p");
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
use super::super::XmlEvent;
|
|
||||||
use crate::xml_builder::*;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
opened_el!(open_paragraph_property, "w:pPr");
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
use super::XMLBuilder;
|
|
||||||
use super::XmlEvent;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
// i.e. <w:qFormat ... >
|
|
||||||
closed_el!(q_format, "w:qFormat");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
#[cfg(test)]
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_q_format() {
|
|
||||||
let b = XMLBuilder::new();
|
|
||||||
let r = b.q_format().build();
|
|
||||||
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:qFormat />"#);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
use super::XMLBuilder;
|
|
||||||
use super::XmlEvent;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
// i.e. <w:r ... >
|
|
||||||
opened_el!(open_run, "w:r");
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
use super::super::XmlEvent;
|
|
||||||
use crate::xml_builder::*;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
opened_el!(open_run_property, "w:rPr");
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
use super::super::XmlEvent;
|
|
||||||
use crate::xml_builder::*;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
opened_el!(open_run_property_default, "w:rPrDefault");
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
use super::{XMLBuilder, XmlEvent};
|
|
||||||
use crate::StyleType;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
// Build w:style element
|
|
||||||
// i.e. <w:style ... >
|
|
||||||
pub(crate) fn open_style(mut self, style_type: StyleType, id: &str) -> Self {
|
|
||||||
self.writer
|
|
||||||
.write(
|
|
||||||
XmlEvent::start_element("w:style")
|
|
||||||
.attr("w:type", &style_type.to_string())
|
|
||||||
.attr("w:styleId", id),
|
|
||||||
)
|
|
||||||
.expect("should write to buf");
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
#[cfg(test)]
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_declaration() {
|
|
||||||
let b = XMLBuilder::new();
|
|
||||||
let r = b
|
|
||||||
.open_style(StyleType::Paragraph, "Heading")
|
|
||||||
.close()
|
|
||||||
.build();
|
|
||||||
assert_eq!(
|
|
||||||
str::from_utf8(&r).unwrap(),
|
|
||||||
r#"<w:style w:type="paragraph" w:styleId="Heading" />"#
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
use super::XMLBuilder;
|
|
||||||
use super::XmlEvent;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
// i.e. <w:sz ... >
|
|
||||||
pub(crate) fn sz(mut self, val: usize) -> Self {
|
|
||||||
self.writer
|
|
||||||
.write(XmlEvent::start_element("w:sz").attr("w:val", &format!("{}", val)))
|
|
||||||
.expect("should write to buf");
|
|
||||||
self.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
#[cfg(test)]
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_name() {
|
|
||||||
let b = XMLBuilder::new();
|
|
||||||
let r = b.sz(20).build();
|
|
||||||
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:sz w:val="20" />"#);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
use super::XMLBuilder;
|
|
||||||
use super::XmlEvent;
|
|
||||||
|
|
||||||
impl XMLBuilder {
|
|
||||||
// i.e. <w:t ... >
|
|
||||||
closed_el_with_child!(text, "w:t");
|
|
||||||
}
|
|
|
@ -130,3 +130,25 @@ macro_rules! closed_el {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! only_str_val_el {
|
||||||
|
($name: ident, $el_name: expr) => {
|
||||||
|
pub(crate) fn $name(mut self, val: &str) -> Self {
|
||||||
|
self.writer
|
||||||
|
.write(XmlEvent::start_element($el_name).attr("w:val", val))
|
||||||
|
.expect("should write to buf");
|
||||||
|
self.close()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! only_usize_val_el {
|
||||||
|
($name: ident, $el_name: expr) => {
|
||||||
|
pub(crate) fn $name(mut self, val: usize) -> Self {
|
||||||
|
self.writer
|
||||||
|
.write(XmlEvent::start_element($el_name).attr("w:val", val))
|
||||||
|
.expect("should write to buf");
|
||||||
|
self.close()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue