Skip to main content

docx_navigation_and_annotations/
docx_navigation_and_annotations.rs

1//! Word navigation and annotation features: hyperlinks (external and
2//! internal, with a bookmark target), comments, footnotes/endnotes, and a
3//! structured document tag (content control). One page per feature.
4//!
5//! Run with: `cargo run -p office-toolkit --example docx_navigation_and_annotations`
6
7use std::path::{Path, PathBuf};
8
9use office_toolkit::SaveToFile;
10use office_toolkit::prelude::*;
11use office_toolkit::word::{
12    Bookmark, Comment, Hyperlink, Note, NoteReference, Run, StructuredDocumentTag,
13};
14
15fn main() -> office_toolkit::Result<()> {
16    let path = output_path("docx_navigation_and_annotations.docx");
17
18    let document =
19        Document::new()
20            .with_paragraph(heading(
21                "Hyperlinks: external, and internal to a bookmark",
22                false,
23            ))
24            .with_paragraph(
25                Paragraph::new()
26                    .with_run(Run::new("Visit the ").with_hyperlink(Hyperlink::External(
27                        "https://www.rust-lang.org".to_string(),
28                    )))
29                    .with_run(Run::new("or jump ").with_hyperlink(Hyperlink::External(
30                        "https://www.rust-lang.org".to_string(),
31                    )))
32                    .with_run(
33                        Run::new("down to the bookmark")
34                            .with_hyperlink(Hyperlink::Internal("Target".to_string())),
35                    ),
36            )
37            .with_paragraph(
38                Paragraph::new()
39                    .with_run(Run::new("Here is ").with_bookmark(Bookmark::new(0, "Target")))
40                    .with_run(
41                        Run::new("the bookmarked text.").with_bookmark(Bookmark::new(0, "Target")),
42                    ),
43            )
44            .with_paragraph(heading("Comments", true))
45            .with_paragraph(
46                Paragraph::new()
47                    .with_run(Run::new("This sentence "))
48                    .with_run(Run::new("needs a second look").with_comment(0))
49                    .with_run(Run::new(" before it ships.")),
50            )
51            .with_comment(
52                Comment::with_text(0, "Please double-check this claim.")
53                    .with_author("Reviewer")
54                    .with_initials("RV"),
55            )
56            .with_paragraph(heading("Footnotes and endnotes", true))
57            .with_paragraph(
58                Paragraph::with_text("A claim that needs a footnote")
59                    .with_run(Run::with_note_reference(NoteReference::Footnote(1)))
60                    .with_run(Run::new(", and another that needs an endnote"))
61                    .with_run(Run::with_note_reference(NoteReference::Endnote(1))),
62            )
63            .with_footnote(Note::footnote_with_text(
64                1,
65                "The footnote's own explanatory text.",
66            ))
67            .with_endnote(Note::endnote_with_text(
68                1,
69                "The endnote's own explanatory text.",
70            ))
71            .with_paragraph(heading("A structured document tag (content control)", true))
72            .with_paragraph(Paragraph::with_text("Before the content control:"))
73            .with_structured_document_tag(
74                StructuredDocumentTag::new()
75                    .with_id(42)
76                    .with_tag("CustomerName")
77                    .with_alias("Customer name")
78                    .with_paragraph(Paragraph::with_text("Acme Corp.")),
79            );
80
81    document.save_to_file(&path)?;
82    println!("Wrote {}", path.display());
83    Ok(())
84}
85
86fn heading(text: &str, new_page: bool) -> Paragraph {
87    Paragraph::new()
88        .with_run(Run::new(text).with_bold(true).with_font_size(28))
89        .with_page_break_before(new_page)
90}
91
92/// Every example in this directory writes its output under
93/// `tests-data/output/`, resolved relative to this crate's own manifest so
94/// it works no matter what directory `cargo run` was invoked from.
95fn output_path(filename: &str) -> PathBuf {
96    Path::new(env!("CARGO_MANIFEST_DIR"))
97        .join("../../tests-data/output")
98        .join(filename)
99}