Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Bidirectional Child to Hyperlink #30

Merged
merged 2 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
**/*.rs.bk
*.docx
Cargo.lock
.DS_Store

# IDE
.vscode/
Expand All @@ -10,4 +11,4 @@ Cargo.lock

# Test
tests/bbb
tests/aaa/aa/
tests/aaa/aa/
57 changes: 57 additions & 0 deletions src/document/bidir.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use hard_xml::{XmlRead, XmlWrite};
use std::borrow::Cow;

use crate::{__setter, __xml_test_suites, document::Run};

/// A bidirectional embedding, which can nest to more bidirectional embeddings
#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
#[cfg_attr(test, derive(PartialEq))]
#[xml(tag = "w:dir")]
pub struct BidirectionalEmbedding<'a> {
// A BidirectionalEmbedding can have a number of rich text runs
#[xml(child = "w:r")]
pub runs: Vec<Run<'a>>,
// A BidirectionalEmbedding can include nested embedding layers
#[xml(child = "w:dir")]
pub nested_levels: Vec<BidirectionalEmbedding<'a>>,
}

impl<'a> BidirectionalEmbedding<'a> {
__setter!(runs: Vec<Run<'a>>);
__setter!(nested_levels: Vec<BidirectionalEmbedding<'a>>);

pub fn iter_text(&self) -> Box<dyn Iterator<Item = &Cow<'a, str>> + '_> {
Box::new(
self.runs.iter().flat_map(|run| run.iter_text()).chain(
self.nested_levels
.iter()
.flat_map(|nested| nested.iter_text()),
),
)
}

pub fn iter_text_mut(&mut self) -> Box<dyn Iterator<Item = &mut Cow<'a, str>> + '_> {
Box::new(
self.runs
.iter_mut()
.flat_map(|run| run.iter_text_mut())
.chain(
self.nested_levels
.iter_mut()
.flat_map(|nested| nested.iter_text_mut()),
),
)
}
}

__xml_test_suites!(
BidirectionalEmbedding,
BidirectionalEmbedding::default(),
r#"<w:dir/>"#,
BidirectionalEmbedding::default().runs(vec![Run::default(), Run::default().push_text("text")]),
r#"<w:dir><w:r/><w:r><w:t>text</w:t></w:r></w:dir>"#,
BidirectionalEmbedding::default().nested_levels(vec![
BidirectionalEmbedding::default().runs(vec![Run::default()])
]),
r#"<w:dir><w:dir><w:r/></w:dir></w:dir>"#,
);
47 changes: 41 additions & 6 deletions src/document/hyperlink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use hard_xml::{XmlRead, XmlWrite};
use std::borrow::Cow;

use crate::{__setter, __xml_test_suites, document::Run};
use crate::{__setter, __xml_test_suites, document::bidir::BidirectionalEmbedding, document::Run};

/// The root element of a hyperlink within the paragraph
#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
Expand All @@ -18,21 +18,56 @@ pub struct Hyperlink<'a> {
pub anchor: Option<Cow<'a, str>>,
#[xml(child = "w:r")]
/// Link content
pub content: Run<'a>,
pub content: Option<Run<'a>>,
#[xml(child = "w:dir")]
// Link can contain a bi-directional embedding layer
pub bidirectional_embedding: Option<BidirectionalEmbedding<'a>>,
}

impl<'a> Hyperlink<'a> {
__setter!(id: Option<Cow<'a, str>>);
__setter!(anchor: Option<Cow<'a, str>>);
__setter!(content: Run<'a>);
__setter!(content: Option<Run<'a>>);

pub fn text(&self) -> String {
self.iter_text()
.map(|c| c.to_string())
.collect::<Vec<_>>()
.join("")
}

pub fn iter_text(&self) -> Box<dyn Iterator<Item = &Cow<'a, str>> + '_> {
Box::new(
self.content.iter().flat_map(|run| run.iter_text()).chain(
self.bidirectional_embedding
.iter()
.flat_map(|bidi| bidi.iter_text()),
),
)
}

pub fn iter_text_mut(&mut self) -> Box<dyn Iterator<Item = &mut Cow<'a, str>> + '_> {
Box::new(
self.content
.iter_mut()
.flat_map(|run| run.iter_text_mut())
.chain(
self.bidirectional_embedding
.iter_mut()
.flat_map(|bidi| bidi.iter_text_mut()),
),
)
}
}

__xml_test_suites!(
Hyperlink,
Hyperlink::default(),
r#"<w:hyperlink><w:r/></w:hyperlink>"#,
r#"<w:hyperlink/>"#,
Hyperlink::default().id("id"),
r#"<w:hyperlink r:id="id"><w:r/></w:hyperlink>"#,
r#"<w:hyperlink r:id="id"/>"#,
Hyperlink::default().anchor("anchor"),
r#"<w:hyperlink w:anchor="anchor"><w:r/></w:hyperlink>"#,
r#"<w:hyperlink w:anchor="anchor"/>"#,
Hyperlink::default().content(Run::default()),
r#"<w:hyperlink><w:r/></w:hyperlink>"#,
);
1 change: 1 addition & 0 deletions src/document/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod bidir;
mod body;
mod bookmark_end;
mod bookmark_start;
Expand All @@ -5,7 +6,7 @@
mod comment_range;
mod comments;
mod date;
mod document;

Check warning on line 9 in src/document/mod.rs

View workflow job for this annotation

GitHub Actions / test

module has the same name as its containing module
mod drawing;
mod endnotes;
mod field_char;
Expand Down
6 changes: 3 additions & 3 deletions src/document/paragraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
.iter()
.filter_map(|content| match content {
ParagraphContent::Run(run) => Some(run.iter_text()),
ParagraphContent::Link(link) => Some(link.content.iter_text()),
ParagraphContent::Link(link) => Some(link.iter_text()),
ParagraphContent::SDT(sdt) => Some(sdt.iter_text()),
_ => None,
})
Expand All @@ -104,7 +104,7 @@
.iter_mut()
.filter_map(|content| match content {
ParagraphContent::Run(run) => Some(run.iter_text_mut()),
ParagraphContent::Link(link) => Some(link.content.iter_text_mut()),
ParagraphContent::Link(link) => Some(link.iter_text_mut()),
_ => None,
})
.flatten()
Expand All @@ -117,7 +117,7 @@
I: Borrow<(S, S)>,
{
for content in self.content.iter_mut() {
match content {

Check warning on line 120 in src/document/paragraph.rs

View workflow job for this annotation

GitHub Actions / test

you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
ParagraphContent::Run(r) => {
r.replace_text(dic)?;
}
Expand Down Expand Up @@ -156,7 +156,7 @@
Paragraph::default().push(Run::default()),
r#"<w:p><w:r/></w:p>"#,
Paragraph::default().push(Hyperlink::default()),
r#"<w:p><w:hyperlink><w:r/></w:hyperlink></w:p>"#,
r#"<w:p><w:hyperlink/></w:p>"#,
Paragraph::default().push(BookmarkStart::default()),
r#"<w:p><w:bookmarkStart/></w:p>"#,
Paragraph::default().push(BookmarkEnd::default()),
Expand Down
6 changes: 3 additions & 3 deletions src/document/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@
}))
}

pub fn iter_text_mut(&mut self) -> impl Iterator<Item = &mut Cow<'a, str>> {
self.content.iter_mut().filter_map(|content| match content {
pub fn iter_text_mut(&mut self) -> Box<dyn Iterator<Item = &mut Cow<'a, str>> + '_> {
Box::new(self.content.iter_mut().filter_map(|content| match content {
RunContent::Text(Text { text, .. }) => Some(text),
RunContent::InstrText(InstrText { text, .. }) => Some(text),
RunContent::Break(_) => None,
Expand All @@ -144,7 +144,7 @@
RunContent::CarriageReturn(_) => None,
RunContent::Drawing(_) => None,
_ => None,
})
}))
}

pub fn replace_text_simple<S>(&mut self, old: S, new: S)
Expand All @@ -161,7 +161,7 @@
I: Borrow<(S, S)>,
{
for c in self.content.iter_mut() {
match c {

Check warning on line 164 in src/document/run.rs

View workflow job for this annotation

GitHub Actions / test

you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
RunContent::Text(t) => {
let mut tc = t.text.to_string();
for p in dic {
Expand All @@ -180,7 +180,7 @@
/// A set of elements that can be contained as the content of a run.
#[derive(Debug, From, XmlRead, XmlWrite, Clone)]
#[cfg_attr(test, derive(PartialEq))]
pub enum RunContent<'a> {

Check warning on line 183 in src/document/run.rs

View workflow job for this annotation

GitHub Actions / test

large size difference between variants
#[xml(tag = "w:br")]
Break(Break),
#[xml(tag = "w:t")]
Expand Down
Binary file not shown.
Loading