feat: Support space:preserve

main
bokuweb 2019-11-11 11:10:33 +09:00
parent 37d4a157d5
commit 517c3b0b9f
21 changed files with 163 additions and 294 deletions

View File

@ -5,18 +5,21 @@ use crate::xml_builder::*;
#[derive(Debug)]
pub struct Text {
text: String,
preserve_space: bool,
}
impl Text {
pub fn new(text: impl Into<String>) -> Text {
Text { text: text.into() }
Text {
text: text.into(),
preserve_space: true,
}
}
}
impl BuildXML for Text {
fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new();
b.text(&self.text).build()
XMLBuilder::new().text(&self.text, true).build()
}
}

View File

@ -11,7 +11,11 @@ pub fn simple() {
let path = std::path::Path::new("./test.docx");
let file = std::fs::File::create(&path).unwrap();
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()
.pack(file);
}

View 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" />"#
);
}
}

View File

@ -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" />"#
);
}
}

View File

@ -1,7 +0,0 @@
use super::XMLBuilder;
use super::XmlEvent;
impl XMLBuilder {
// i.e. <w:body... >
opened_el!(open_body, "w:body");
}

View File

@ -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" />"#);
}
}

View File

@ -1,6 +0,0 @@
use super::super::XmlEvent;
use crate::xml_builder::*;
impl XMLBuilder {
opened_el!(open_doc_defaults, "w:docDefaults");
}

View File

@ -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()
}
};
}

View File

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

View File

@ -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" />"#);
}
}

View File

@ -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" />"#);
}
}

View File

@ -1,7 +0,0 @@
use super::XMLBuilder;
use super::XmlEvent;
impl XMLBuilder {
// i.e. <w:p ... >
opened_el!(open_paragraph, "w:p");
}

View File

@ -1,6 +0,0 @@
use super::super::XmlEvent;
use crate::xml_builder::*;
impl XMLBuilder {
opened_el!(open_paragraph_property, "w:pPr");
}

View File

@ -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 />"#);
}
}

View File

@ -1,7 +0,0 @@
use super::XMLBuilder;
use super::XmlEvent;
impl XMLBuilder {
// i.e. <w:r ... >
opened_el!(open_run, "w:r");
}

View File

@ -1,6 +0,0 @@
use super::super::XmlEvent;
use crate::xml_builder::*;
impl XMLBuilder {
opened_el!(open_run_property, "w:rPr");
}

View File

@ -1,6 +0,0 @@
use super::super::XmlEvent;
use crate::xml_builder::*;
impl XMLBuilder {
opened_el!(open_run_property_default, "w:rPrDefault");
}

View File

@ -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" />"#
);
}
}

View File

@ -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" />"#);
}
}

View File

@ -1,7 +0,0 @@
use super::XMLBuilder;
use super::XmlEvent;
impl XMLBuilder {
// i.e. <w:t ... >
closed_el_with_child!(text, "w:t");
}

View File

@ -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()
}
};
}