feat: Support insert / delete
parent
af75b6a41c
commit
35e6e1ecc3
|
@ -1,3 +1,7 @@
|
||||||
# docx-rs
|
# docx-rs
|
||||||
|
|
||||||
[](https://github.com/bokuweb/docx-rs/actions)
|
[](https://github.com/bokuweb/docx-rs/actions)
|
||||||
|
|
||||||
|
# Features
|
||||||
|
|
||||||
|
- [x] Paragraph
|
||||||
|
|
|
@ -3,33 +3,33 @@ use crate::documents::BuildXML;
|
||||||
use crate::xml_builder::*;
|
use crate::xml_builder::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Document {
|
pub struct Document<'a> {
|
||||||
children: Vec<DocumentChild>,
|
children: Vec<DocumentChild<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum DocumentChild {
|
pub enum DocumentChild<'a> {
|
||||||
Paragraph(Paragraph),
|
Paragraph(Paragraph<'a>),
|
||||||
Table(Table),
|
Table(Table<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Document {
|
impl<'a> Document<'a> {
|
||||||
pub fn new() -> Document {
|
pub fn new() -> Document<'a> {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_paragraph(mut self, p: Paragraph) -> Self {
|
pub fn add_paragraph(mut self, p: Paragraph<'a>) -> Self {
|
||||||
self.children.push(DocumentChild::Paragraph(p));
|
self.children.push(DocumentChild::Paragraph(p));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_table(mut self, t: Table) -> Self {
|
pub fn add_table(mut self, t: Table<'a>) -> Self {
|
||||||
self.children.push(DocumentChild::Table(t));
|
self.children.push(DocumentChild::Table(t));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Document {
|
impl<'a> Default for Document<'a> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
|
@ -37,7 +37,7 @@ impl Default for Document {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildXML for Document {
|
impl<'a> BuildXML for Document<'a> {
|
||||||
fn build(&self) -> Vec<u8> {
|
fn build(&self) -> Vec<u8> {
|
||||||
let mut b = XMLBuilder::new()
|
let mut b = XMLBuilder::new()
|
||||||
.declaration(Some(true))
|
.declaration(Some(true))
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
use crate::documents::{BuildXML, HistoryId, Run};
|
||||||
|
use crate::xml_builder::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Delete<'a> {
|
||||||
|
author: &'a str,
|
||||||
|
date: &'a str,
|
||||||
|
run: Run,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Default for Delete<'a> {
|
||||||
|
fn default() -> Delete<'a> {
|
||||||
|
Delete {
|
||||||
|
author: "unnamed",
|
||||||
|
date: "1970-01-01T00:00:00Z",
|
||||||
|
run: Run::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Delete<'a> {
|
||||||
|
pub fn new() -> Delete<'a> {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(mut self, run: Run) -> Delete<'a> {
|
||||||
|
self.run = run;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> HistoryId for Delete<'a> {}
|
||||||
|
|
||||||
|
impl<'a> BuildXML for Delete<'a> {
|
||||||
|
fn build(&self) -> Vec<u8> {
|
||||||
|
XMLBuilder::new()
|
||||||
|
.open_delete(&self.generate(), self.author, self.date)
|
||||||
|
.add_child(&self.run)
|
||||||
|
.close()
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
#[cfg(test)]
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_default() {
|
||||||
|
let b = Delete::new().build();
|
||||||
|
assert_eq!(
|
||||||
|
str::from_utf8(&b).unwrap(),
|
||||||
|
r#"<w:del w:id="123" w:author="unnamed" w:data="1970-01-01T00:00:00Z"><w:r><w:rPr /></w:r></w:del>"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
use crate::documents::BuildXML;
|
||||||
|
use crate::xml_builder::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DeleteText {
|
||||||
|
text: String,
|
||||||
|
preserve_space: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeleteText {
|
||||||
|
pub fn new(text: impl Into<String>) -> DeleteText {
|
||||||
|
DeleteText {
|
||||||
|
text: text.into(),
|
||||||
|
preserve_space: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuildXML for DeleteText {
|
||||||
|
fn build(&self) -> Vec<u8> {
|
||||||
|
XMLBuilder::new().delete_text(&self.text, true).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
#[cfg(test)]
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build() {
|
||||||
|
let b = DeleteText::new("Hello").build();
|
||||||
|
assert_eq!(
|
||||||
|
str::from_utf8(&b).unwrap(),
|
||||||
|
r#"<w:delText xml:space="preserve">Hello</w:delText>"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
use crate::documents::{BuildXML, HistoryId, Run};
|
||||||
|
use crate::xml_builder::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Insert<'a> {
|
||||||
|
author: &'a str,
|
||||||
|
date: &'a str,
|
||||||
|
run: Run,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Default for Insert<'a> {
|
||||||
|
fn default() -> Insert<'a> {
|
||||||
|
Insert {
|
||||||
|
author: "unnamed",
|
||||||
|
date: "1970-01-01T00:00:00Z",
|
||||||
|
run: Run::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Insert<'a> {
|
||||||
|
pub fn new() -> Insert<'a> {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(mut self, run: Run) -> Insert<'a> {
|
||||||
|
self.run = run;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> HistoryId for Insert<'a> {}
|
||||||
|
|
||||||
|
impl<'a> BuildXML for Insert<'a> {
|
||||||
|
fn build(&self) -> Vec<u8> {
|
||||||
|
XMLBuilder::new()
|
||||||
|
.open_insert(&self.generate(), self.author, self.date)
|
||||||
|
.add_child(&self.run)
|
||||||
|
.close()
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
#[cfg(test)]
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_default() {
|
||||||
|
let b = Insert::new().build();
|
||||||
|
assert_eq!(
|
||||||
|
str::from_utf8(&b).unwrap(),
|
||||||
|
r#"<w:ins w:id="123" w:author="unnamed" w:data="1970-01-01T00:00:00Z"><w:r><w:rPr /></w:r></w:ins>"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,11 +4,14 @@ mod bold_cs;
|
||||||
mod br;
|
mod br;
|
||||||
mod color;
|
mod color;
|
||||||
mod default_tab_stop;
|
mod default_tab_stop;
|
||||||
|
mod delete;
|
||||||
|
mod delete_text;
|
||||||
mod doc_defaults;
|
mod doc_defaults;
|
||||||
mod font;
|
mod font;
|
||||||
mod grid_span;
|
mod grid_span;
|
||||||
mod highlight;
|
mod highlight;
|
||||||
mod indent;
|
mod indent;
|
||||||
|
mod insert;
|
||||||
mod italic;
|
mod italic;
|
||||||
mod italic_cs;
|
mod italic_cs;
|
||||||
mod justification;
|
mod justification;
|
||||||
|
@ -48,11 +51,14 @@ pub use bold_cs::*;
|
||||||
pub use br::*;
|
pub use br::*;
|
||||||
pub use color::*;
|
pub use color::*;
|
||||||
pub use default_tab_stop::*;
|
pub use default_tab_stop::*;
|
||||||
|
pub use delete::*;
|
||||||
|
pub use delete_text::*;
|
||||||
pub use doc_defaults::*;
|
pub use doc_defaults::*;
|
||||||
pub use font::*;
|
pub use font::*;
|
||||||
pub use grid_span::*;
|
pub use grid_span::*;
|
||||||
pub use highlight::*;
|
pub use highlight::*;
|
||||||
pub use indent::*;
|
pub use indent::*;
|
||||||
|
pub use insert::*;
|
||||||
pub use italic::*;
|
pub use italic::*;
|
||||||
pub use italic_cs::*;
|
pub use italic_cs::*;
|
||||||
pub use justification::*;
|
pub use justification::*;
|
||||||
|
|
|
@ -1,67 +1,98 @@
|
||||||
use super::{ParagraphProperty, Run};
|
use super::{Delete, Insert, ParagraphProperty, Run};
|
||||||
use crate::documents::BuildXML;
|
use crate::documents::BuildXML;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
use crate::xml_builder::*;
|
use crate::xml_builder::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Paragraph {
|
pub struct Paragraph<'a> {
|
||||||
runs: Vec<Run>,
|
children: Vec<ParagraphChild<'a>>,
|
||||||
property: ParagraphProperty,
|
property: ParagraphProperty,
|
||||||
attrs: Vec<(String, String)>,
|
attrs: Vec<(String, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Paragraph {
|
impl<'a> Default for Paragraph<'a> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
runs: Vec::new(),
|
children: Vec::new(),
|
||||||
property: ParagraphProperty::new(),
|
property: ParagraphProperty::new(),
|
||||||
attrs: Vec::new(),
|
attrs: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Paragraph {
|
#[derive(Debug, Clone)]
|
||||||
pub fn new() -> Paragraph {
|
pub enum ParagraphChild<'a> {
|
||||||
|
Run(Run),
|
||||||
|
Insert(Insert<'a>),
|
||||||
|
Delete(Delete<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> BuildXML for ParagraphChild<'a> {
|
||||||
|
fn build(&self) -> Vec<u8> {
|
||||||
|
match self {
|
||||||
|
ParagraphChild::Run(v) => v.build(),
|
||||||
|
ParagraphChild::Insert(v) => v.build(),
|
||||||
|
ParagraphChild::Delete(v) => v.build(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Paragraph<'a> {
|
||||||
|
pub fn new() -> Paragraph<'a> {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_run(mut self, run: Run) -> Paragraph {
|
pub fn add_run(mut self, run: Run) -> Paragraph<'a> {
|
||||||
self.runs.push(run);
|
self.children.push(ParagraphChild::Run(run));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_attr(mut self, key: impl Into<String>, val: impl Into<String>) -> Paragraph {
|
pub fn add_insert(mut self, insert: Insert<'a>) -> Paragraph<'a> {
|
||||||
|
self.children.push(ParagraphChild::Insert(insert));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_delete(mut self, delete: Delete<'a>) -> Paragraph<'a> {
|
||||||
|
self.children.push(ParagraphChild::Delete(delete));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_attr(mut self, key: impl Into<String>, val: impl Into<String>) -> Paragraph<'a> {
|
||||||
self.attrs.push((key.into(), val.into()));
|
self.attrs.push((key.into(), val.into()));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn align(mut self, alignment_type: AlignmentType) -> Paragraph {
|
pub fn align(mut self, alignment_type: AlignmentType) -> Paragraph<'a> {
|
||||||
self.property = self.property.align(alignment_type);
|
self.property = self.property.align(alignment_type);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(mut self, size: usize) -> Paragraph {
|
// pub fn size(mut self, size: usize) -> Paragraph<'a> {
|
||||||
self.runs = self.runs.into_iter().map(|r| r.size(size)).collect();
|
// self.children = self.children.into_iter().map(|r| r.size(size)).collect();
|
||||||
self
|
// self
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn style(mut self, style_id: &str) -> Paragraph {
|
pub fn style(mut self, style_id: &str) -> Paragraph<'a> {
|
||||||
self.property = self.property.style(style_id);
|
self.property = self.property.style(style_id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn indent(mut self, left: usize, special_indent: Option<SpecialIndentType>) -> Paragraph {
|
pub fn indent(
|
||||||
|
mut self,
|
||||||
|
left: usize,
|
||||||
|
special_indent: Option<SpecialIndentType>,
|
||||||
|
) -> Paragraph<'a> {
|
||||||
self.property = self.property.indent(left, special_indent);
|
self.property = self.property.indent(left, special_indent);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildXML for Paragraph {
|
impl<'a> BuildXML for Paragraph<'a> {
|
||||||
fn build(&self) -> Vec<u8> {
|
fn build(&self) -> Vec<u8> {
|
||||||
XMLBuilder::new()
|
XMLBuilder::new()
|
||||||
.open_paragraph(&self.attrs)
|
.open_paragraph(&self.attrs)
|
||||||
.add_child(&self.property)
|
.add_child(&self.property)
|
||||||
.add_children(&self.runs)
|
.add_children(&self.children)
|
||||||
.close()
|
.close()
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
@ -86,18 +117,6 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_paragraph_size() {
|
|
||||||
let b = Paragraph::new()
|
|
||||||
.add_run(Run::new().add_text("Hello"))
|
|
||||||
.size(60)
|
|
||||||
.build();
|
|
||||||
assert_eq!(
|
|
||||||
str::from_utf8(&b).unwrap(),
|
|
||||||
r#"<w:p><w:pPr><w:pStyle w:val="Normal" /><w:rPr /></w:pPr><w:r><w:rPr><w:sz w:val="60" /><w:szCs w:val="60" /></w:rPr><w:t xml:space="preserve">Hello</w:t></w:r></w:p>"#
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_custom_attr() {
|
fn test_custom_attr() {
|
||||||
let b = Paragraph::new()
|
let b = Paragraph::new()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{Break, RunProperty, Tab, Text};
|
use super::{Break, DeleteText, RunProperty, Tab, Text};
|
||||||
use crate::documents::BuildXML;
|
use crate::documents::BuildXML;
|
||||||
use crate::types::BreakType;
|
use crate::types::BreakType;
|
||||||
use crate::xml_builder::*;
|
use crate::xml_builder::*;
|
||||||
|
@ -22,6 +22,7 @@ impl Default for Run {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum RunChild {
|
pub enum RunChild {
|
||||||
Text(Text),
|
Text(Text),
|
||||||
|
DeleteText(DeleteText),
|
||||||
Tab(Tab),
|
Tab(Tab),
|
||||||
Break(Break),
|
Break(Break),
|
||||||
}
|
}
|
||||||
|
@ -38,6 +39,11 @@ impl Run {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_delete_text(mut self, text: &str) -> Run {
|
||||||
|
self.children.push(RunChild::Text(Text::new(text)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_tab(mut self) -> Run {
|
pub fn add_tab(mut self) -> Run {
|
||||||
self.children.push(RunChild::Tab(Tab::new()));
|
self.children.push(RunChild::Tab(Tab::new()));
|
||||||
self
|
self
|
||||||
|
@ -81,6 +87,7 @@ impl BuildXML for Run {
|
||||||
for c in &self.children {
|
for c in &self.children {
|
||||||
match c {
|
match c {
|
||||||
RunChild::Text(t) => b = b.add_child(t),
|
RunChild::Text(t) => b = b.add_child(t),
|
||||||
|
RunChild::DeleteText(t) => b = b.add_child(t),
|
||||||
RunChild::Tab(t) => b = b.add_child(t),
|
RunChild::Tab(t) => b = b.add_child(t),
|
||||||
RunChild::Break(t) => b = b.add_child(t),
|
RunChild::Break(t) => b = b.add_child(t),
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,14 @@ use crate::documents::BuildXML;
|
||||||
use crate::xml_builder::*;
|
use crate::xml_builder::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Table {
|
pub struct Table<'a> {
|
||||||
property: TableProperty,
|
property: TableProperty,
|
||||||
rows: Vec<TableRow>,
|
rows: Vec<TableRow<'a>>,
|
||||||
grid: Vec<usize>,
|
grid: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Table {
|
impl<'a> Table<'a> {
|
||||||
pub fn new(rows: Vec<TableRow>) -> Table {
|
pub fn new(rows: Vec<TableRow<'a>>) -> Table<'a> {
|
||||||
let property = TableProperty::new();
|
let property = TableProperty::new();
|
||||||
let grid = vec![];
|
let grid = vec![];
|
||||||
Self {
|
Self {
|
||||||
|
@ -20,13 +20,13 @@ impl Table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_grid(mut self, grid: Vec<usize>) -> Table {
|
pub fn set_grid(mut self, grid: Vec<usize>) -> Table<'a> {
|
||||||
self.grid = grid;
|
self.grid = grid;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildXML for Table {
|
impl<'a> BuildXML for Table<'a> {
|
||||||
fn build(&self) -> Vec<u8> {
|
fn build(&self) -> Vec<u8> {
|
||||||
let grid = TableGrid::new(self.grid.clone());
|
let grid = TableGrid::new(self.grid.clone());
|
||||||
let b = XMLBuilder::new()
|
let b = XMLBuilder::new()
|
||||||
|
|
|
@ -4,40 +4,40 @@ use crate::types::*;
|
||||||
use crate::xml_builder::*;
|
use crate::xml_builder::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TableCell {
|
pub struct TableCell<'a> {
|
||||||
property: TableCellProperty,
|
property: TableCellProperty,
|
||||||
contents: Vec<TableCellContent>,
|
contents: Vec<TableCellContent<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TableCellContent {
|
pub enum TableCellContent<'a> {
|
||||||
Paragraph(Paragraph),
|
Paragraph(Paragraph<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableCell {
|
impl<'a> TableCell<'a> {
|
||||||
pub fn new() -> TableCell {
|
pub fn new() -> TableCell<'a> {
|
||||||
let property = TableCellProperty::new();
|
let property = TableCellProperty::new();
|
||||||
let contents = vec![];
|
let contents = vec![];
|
||||||
Self { property, contents }
|
Self { property, contents }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_paragraph(mut self, p: Paragraph) -> TableCell {
|
pub fn add_paragraph(mut self, p: Paragraph<'a>) -> TableCell<'a> {
|
||||||
self.contents.push(TableCellContent::Paragraph(p));
|
self.contents.push(TableCellContent::Paragraph(p));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vertical_merge(mut self, t: VMergeType) -> TableCell {
|
pub fn vertical_merge(mut self, t: VMergeType) -> TableCell<'a> {
|
||||||
self.property = self.property.vertical_merge(t);
|
self.property = self.property.vertical_merge(t);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grid_span(mut self, v: usize) -> TableCell {
|
pub fn grid_span(mut self, v: usize) -> TableCell<'a> {
|
||||||
self.property = self.property.grid_span(v);
|
self.property = self.property.grid_span(v);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildXML for TableCell {
|
impl<'a> BuildXML for TableCell<'a> {
|
||||||
fn build(&self) -> Vec<u8> {
|
fn build(&self) -> Vec<u8> {
|
||||||
let b = XMLBuilder::new();
|
let b = XMLBuilder::new();
|
||||||
let mut b = b.open_table_cell().add_child(&self.property);
|
let mut b = b.open_table_cell().add_child(&self.property);
|
||||||
|
|
|
@ -3,19 +3,19 @@ use crate::documents::BuildXML;
|
||||||
use crate::xml_builder::*;
|
use crate::xml_builder::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TableRow {
|
pub struct TableRow<'a> {
|
||||||
property: TableRowProperty,
|
property: TableRowProperty,
|
||||||
cells: Vec<TableCell>,
|
cells: Vec<TableCell<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableRow {
|
impl<'a> TableRow<'a> {
|
||||||
pub fn new(cells: Vec<TableCell>) -> TableRow {
|
pub fn new(cells: Vec<TableCell<'a>>) -> TableRow<'a> {
|
||||||
let property = TableRowProperty::new();
|
let property = TableRowProperty::new();
|
||||||
Self { property, cells }
|
Self { property, cells }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildXML for TableRow {
|
impl<'a> BuildXML for TableRow<'a> {
|
||||||
fn build(&self) -> Vec<u8> {
|
fn build(&self) -> Vec<u8> {
|
||||||
let b = XMLBuilder::new()
|
let b = XMLBuilder::new()
|
||||||
.open_table_row()
|
.open_table_row()
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#[allow(unused)]
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
static HISTORY_ID: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
pub trait HistoryId {
|
||||||
|
fn generate(&self) -> String {
|
||||||
|
let id = HISTORY_ID.load(Ordering::Relaxed);
|
||||||
|
HISTORY_ID.store(id + 1, Ordering::Relaxed);
|
||||||
|
format!("{}", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub trait HistoryId {
|
||||||
|
fn generate(&self) -> &str {
|
||||||
|
"123"
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,12 +5,14 @@ mod document;
|
||||||
mod document_rels;
|
mod document_rels;
|
||||||
mod elements;
|
mod elements;
|
||||||
mod font_table;
|
mod font_table;
|
||||||
|
mod history_id;
|
||||||
mod rels;
|
mod rels;
|
||||||
mod settings;
|
mod settings;
|
||||||
mod styles;
|
mod styles;
|
||||||
mod xml_docx;
|
mod xml_docx;
|
||||||
|
|
||||||
pub(crate) use build_xml::*;
|
pub(crate) use build_xml::BuildXML;
|
||||||
|
pub(crate) use history_id::HistoryId;
|
||||||
|
|
||||||
pub use content_types::*;
|
pub use content_types::*;
|
||||||
pub use doc_props::*;
|
pub use doc_props::*;
|
||||||
|
@ -30,7 +32,7 @@ pub struct Docx<'a> {
|
||||||
document_rels: DocumentRels,
|
document_rels: DocumentRels,
|
||||||
doc_props: DocProps<'a>,
|
doc_props: DocProps<'a>,
|
||||||
styles: Styles,
|
styles: Styles,
|
||||||
document: Document,
|
document: Document<'a>,
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
font_table: FontTable,
|
font_table: FontTable,
|
||||||
}
|
}
|
||||||
|
@ -63,12 +65,12 @@ impl<'a> Docx<'a> {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_paragraph(mut self, p: Paragraph) -> Docx<'a> {
|
pub fn add_paragraph(mut self, p: Paragraph<'a>) -> Docx<'a> {
|
||||||
self.document = self.document.add_paragraph(p);
|
self.document = self.document.add_paragraph(p);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_table(mut self, t: Table) -> Docx<'a> {
|
pub fn add_table(mut self, t: Table<'a>) -> Docx<'a> {
|
||||||
self.document = self.document.add_table(t);
|
self.document = self.document.add_table(t);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,19 @@ impl XMLBuilder {
|
||||||
self.writer.write(text).expect(EXPECT_MESSAGE);
|
self.writer.write(text).expect(EXPECT_MESSAGE);
|
||||||
self.close()
|
self.close()
|
||||||
}
|
}
|
||||||
|
// i.e. <w:delText ... >
|
||||||
|
pub(crate) fn delete_text(mut self, text: &str, preserve_space: bool) -> Self {
|
||||||
|
let space = if preserve_space {
|
||||||
|
"preserve"
|
||||||
|
} else {
|
||||||
|
"default"
|
||||||
|
};
|
||||||
|
self.writer
|
||||||
|
.write(XmlEvent::start_element("w:delText").attr("xml:space", space))
|
||||||
|
.expect(EXPECT_MESSAGE);
|
||||||
|
self.writer.write(text).expect(EXPECT_MESSAGE);
|
||||||
|
self.close()
|
||||||
|
}
|
||||||
// i.e. <w:r ... >
|
// i.e. <w:r ... >
|
||||||
opened_el!(open_run, "w:r");
|
opened_el!(open_run, "w:r");
|
||||||
opened_el!(open_run_property, "w:rPr");
|
opened_el!(open_run_property, "w:rPr");
|
||||||
|
@ -148,6 +161,9 @@ impl XMLBuilder {
|
||||||
"w:bottom",
|
"w:bottom",
|
||||||
"w:gutter"
|
"w:gutter"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
opened_el!(open_insert, "w:ins", "w:id", "w:author", "w:data");
|
||||||
|
opened_el!(open_delete, "w:del", "w:id", "w:author", "w:data");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -47,11 +47,7 @@ pub fn size() -> Result<(), DocxError> {
|
||||||
let path = std::path::Path::new("./tests/output/size.docx");
|
let path = std::path::Path::new("./tests/output/size.docx");
|
||||||
let file = std::fs::File::create(&path).unwrap();
|
let file = std::fs::File::create(&path).unwrap();
|
||||||
Docx::new()
|
Docx::new()
|
||||||
.add_paragraph(
|
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello").size(60)))
|
||||||
Paragraph::new()
|
|
||||||
.add_run(Run::new().add_text("Hello"))
|
|
||||||
.size(60),
|
|
||||||
)
|
|
||||||
.add_paragraph(
|
.add_paragraph(
|
||||||
Paragraph::new()
|
Paragraph::new()
|
||||||
.add_run(Run::new().add_text(" Wor").size(50))
|
.add_run(Run::new().add_text(" Wor").size(50))
|
||||||
|
@ -219,3 +215,18 @@ pub fn custom_attr_paragraph() -> Result<(), DocxError> {
|
||||||
.pack(file)?;
|
.pack(file)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn history() -> Result<(), DocxError> {
|
||||||
|
let path = std::path::Path::new("./tests/output/history.docx");
|
||||||
|
let file = std::fs::File::create(&path).unwrap();
|
||||||
|
Docx::new()
|
||||||
|
.add_paragraph(
|
||||||
|
Paragraph::new()
|
||||||
|
.add_insert(Insert::new().run(Run::new().add_text("Hello")))
|
||||||
|
.add_delete(Delete::new().run(Run::new().add_delete_text("World"))),
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
.pack(file)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Override PartName="/_rels/.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/word/_rels/document.xml.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"/><Override PartName="/word/fontTable.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"/><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
|
||||||
|
</Types>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
|
||||||
|
</Relationships>
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><Template></Template><TotalTime>6</TotalTime><Application>LibreOffice/6.0.7.3$Linux_X86_64 LibreOffice_project/00m0$Build-3</Application><Pages>1</Pages><Words>1</Words><Characters>5</Characters><CharactersWithSpaces>5</CharactersWithSpaces><Paragraphs>1</Paragraphs></Properties>
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dcterms:created xsi:type="dcterms:W3CDTF">2019-11-15T14:17:59Z</dcterms:created><dc:creator></dc:creator><dc:description></dc:description><dc:language>ja-JP</dc:language><cp:lastModifiedBy></cp:lastModifiedBy><dcterms:modified xsi:type="dcterms:W3CDTF">2019-11-15T14:46:47Z</dcterms:modified><cp:revision>6</cp:revision><dc:subject></dc:subject><dc:title></dc:title></cp:coreProperties>
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Target="fontTable.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/>
|
||||||
|
</Relationships>
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<w:document xmlns:o="urn:schemas-microsoft-com:office:office"
|
||||||
|
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
xmlns:v="urn:schemas-microsoft-com:vml"
|
||||||
|
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||||
|
xmlns:w10="urn:schemas-microsoft-com:office:word"
|
||||||
|
xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
|
||||||
|
xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"
|
||||||
|
xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
|
||||||
|
xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" mc:Ignorable="w14 wp14">
|
||||||
|
<w:body>
|
||||||
|
<w:p>
|
||||||
|
<w:pPr>
|
||||||
|
<w:pStyle w:val="Normal"/>
|
||||||
|
<w:rPr></w:rPr>
|
||||||
|
</w:pPr>
|
||||||
|
<w:ins w:id="0" w:author="不明な作成者" w:date="2019-11-15T14:19:04Z">
|
||||||
|
<w:r>
|
||||||
|
<w:rPr></w:rPr>
|
||||||
|
<w:t>W</w:t>
|
||||||
|
</w:r>
|
||||||
|
</w:ins>
|
||||||
|
<w:ins w:id="1" w:author="不明な作成者" w:date="2019-11-15T14:19:04Z">
|
||||||
|
<w:r>
|
||||||
|
<w:rPr></w:rPr>
|
||||||
|
<w:t>a</w:t>
|
||||||
|
</w:r>
|
||||||
|
</w:ins>
|
||||||
|
<w:ins w:id="2" w:author="不明な作成者" w:date="2019-11-15T14:19:04Z">
|
||||||
|
<w:r>
|
||||||
|
<w:rPr></w:rPr>
|
||||||
|
<w:t>rld</w:t>
|
||||||
|
</w:r>
|
||||||
|
</w:ins>
|
||||||
|
<w:del w:id="3" w:author="不明な作成者" w:date="2019-11-15T14:19:04Z">
|
||||||
|
<w:r>
|
||||||
|
<w:rPr></w:rPr>
|
||||||
|
<w:delText xml:space="preserve">Hello </w:delText>
|
||||||
|
</w:r>
|
||||||
|
</w:del>
|
||||||
|
</w:p>
|
||||||
|
<w:sectPr>
|
||||||
|
<w:type w:val="nextPage"/>
|
||||||
|
<w:pgSz w:w="11906" w:h="16838"/>
|
||||||
|
<w:pgMar w:left="1134" w:right="1134" w:header="0" w:top="1134" w:footer="0" w:bottom="1134" w:gutter="0"/>
|
||||||
|
<w:pgNumType w:fmt="decimal"/>
|
||||||
|
<w:formProt w:val="false"/>
|
||||||
|
<w:textDirection w:val="lrTb"/>
|
||||||
|
<w:docGrid w:type="default" w:linePitch="100" w:charSpace="0"/>
|
||||||
|
</w:sectPr>
|
||||||
|
</w:body>
|
||||||
|
</w:document>
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<w:fonts xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><w:font w:name="Times New Roman"><w:charset w:val="00"/><w:family w:val="roman"/><w:pitch w:val="variable"/></w:font><w:font w:name="Symbol"><w:charset w:val="02"/><w:family w:val="roman"/><w:pitch w:val="variable"/></w:font><w:font w:name="Arial"><w:charset w:val="00"/><w:family w:val="swiss"/><w:pitch w:val="variable"/></w:font><w:font w:name="Liberation Serif"><w:altName w:val="Times New Roman"/><w:charset w:val="01"/><w:family w:val="roman"/><w:pitch w:val="variable"/></w:font><w:font w:name="Liberation Sans"><w:altName w:val="Arial"/><w:charset w:val="01"/><w:family w:val="roman"/><w:pitch w:val="variable"/></w:font></w:fonts>
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:zoom w:percent="100"/><w:trackRevisions/><w:defaultTabStop w:val="709"/><w:compat><w:doNotExpandShiftReturn/></w:compat><w:compat></w:compat><w:themeFontLang w:val="" w:eastAsia="" w:bidi=""/></w:settings>
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="w14"><w:docDefaults><w:rPrDefault><w:rPr><w:rFonts w:ascii="Liberation Serif" w:hAnsi="Liberation Serif" w:eastAsia="Noto Sans CJK JP" w:cs="Lohit Devanagari"/><w:kern w:val="2"/><w:sz w:val="20"/><w:szCs w:val="24"/><w:lang w:val="en-US" w:eastAsia="ja-JP" w:bidi="hi-IN"/></w:rPr></w:rPrDefault><w:pPrDefault><w:pPr></w:pPr></w:pPrDefault></w:docDefaults><w:style w:type="paragraph" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/><w:pPr><w:widowControl/><w:bidi w:val="0"/><w:jc w:val="left"/></w:pPr><w:rPr><w:rFonts w:ascii="Liberation Serif" w:hAnsi="Liberation Serif" w:eastAsia="Noto Sans CJK JP" w:cs="Lohit Devanagari"/><w:color w:val="auto"/><w:kern w:val="2"/><w:sz w:val="24"/><w:szCs w:val="24"/><w:lang w:val="en-US" w:eastAsia="ja-JP" w:bidi="hi-IN"/></w:rPr></w:style><w:style w:type="paragraph" w:styleId="Style14"><w:name w:val="見出し"/><w:basedOn w:val="Normal"/><w:next w:val="Style15"/><w:qFormat/><w:pPr><w:keepNext w:val="true"/><w:spacing w:before="240" w:after="120"/></w:pPr><w:rPr><w:rFonts w:ascii="Liberation Sans" w:hAnsi="Liberation Sans" w:eastAsia="Noto Sans CJK JP" w:cs="Lohit Devanagari"/><w:sz w:val="28"/><w:szCs w:val="28"/></w:rPr></w:style><w:style w:type="paragraph" w:styleId="Style15"><w:name w:val="Body Text"/><w:basedOn w:val="Normal"/><w:pPr><w:spacing w:lineRule="auto" w:line="276" w:before="0" w:after="140"/></w:pPr><w:rPr></w:rPr></w:style><w:style w:type="paragraph" w:styleId="Style16"><w:name w:val="List"/><w:basedOn w:val="Style15"/><w:pPr></w:pPr><w:rPr><w:rFonts w:cs="Lohit Devanagari"/></w:rPr></w:style><w:style w:type="paragraph" w:styleId="Style17"><w:name w:val="Caption"/><w:basedOn w:val="Normal"/><w:qFormat/><w:pPr><w:suppressLineNumbers/><w:spacing w:before="120" w:after="120"/></w:pPr><w:rPr><w:rFonts w:cs="Lohit Devanagari"/><w:i/><w:iCs/><w:sz w:val="24"/><w:szCs w:val="24"/></w:rPr></w:style><w:style w:type="paragraph" w:styleId="Style18"><w:name w:val="索引"/><w:basedOn w:val="Normal"/><w:qFormat/><w:pPr><w:suppressLineNumbers/></w:pPr><w:rPr><w:rFonts w:cs="Lohit Devanagari"/></w:rPr></w:style></w:styles>
|
Loading…
Reference in New Issue