Skip to main content

docx_styles_and_lists/
docx_styles_and_lists.rs

1//! Word named styles and lists: paragraph/character styles declared once
2//! and referenced by id, plus bulleted/numbered/custom multi-level lists.
3//! One page per feature.
4//!
5//! Run with: `cargo run -p office-toolkit --example docx_styles_and_lists`
6
7use std::path::{Path, PathBuf};
8
9use office_toolkit::SaveToFile;
10use office_toolkit::prelude::*;
11use office_toolkit::word::{ListLevel, NumberFormat, NumberingDefinition, Run, Style, StyleKind};
12
13fn main() -> office_toolkit::Result<()> {
14    let path = output_path("docx_styles_and_lists.docx");
15
16    let heading_style = Style::new("Heading1", "Heading 1", StyleKind::Paragraph)
17        .with_bold(true)
18        .with_font_size(32);
19    let emphasis_style = Style::new("StrongEmphasis", "Strong Emphasis", StyleKind::Character)
20        .with_bold(true)
21        .with_color("C00000");
22
23    let bulleted = NumberingDefinition::bullet(1);
24    let numbered = NumberingDefinition::decimal(2);
25    let custom = NumberingDefinition::new(
26        3,
27        vec![
28            ListLevel::new(NumberFormat::UpperRoman, "%1.", 720, 360),
29            ListLevel::new(NumberFormat::LowerLetter, "%2)", 1440, 360),
30        ],
31    );
32
33    let document = Document::new()
34        .with_style(heading_style)
35        .with_style(emphasis_style)
36        .with_numbering_definition(bulleted)
37        .with_numbering_definition(numbered)
38        .with_numbering_definition(custom)
39        .with_paragraph(heading("Named paragraph and character styles", false))
40        .with_paragraph(
41            Paragraph::with_text("This paragraph uses the Heading 1 style.")
42                .with_style_id("Heading1"),
43        )
44        .with_paragraph(
45            Paragraph::new()
46                .with_run(Run::new("Plain text, then "))
47                .with_run(Run::new("some strongly emphasized text").with_style_id("StrongEmphasis"))
48                .with_run(Run::new(", then plain text again.")),
49        )
50        .with_paragraph(heading("Bulleted list", true))
51        .with_paragraph(Paragraph::with_text("First item").with_numbering(1, 0))
52        .with_paragraph(Paragraph::with_text("Second item").with_numbering(1, 0))
53        .with_paragraph(Paragraph::with_text("A sub-item, one level deeper").with_numbering(1, 1))
54        .with_paragraph(heading("Numbered list", true))
55        .with_paragraph(Paragraph::with_text("First step").with_numbering(2, 0))
56        .with_paragraph(Paragraph::with_text("Second step").with_numbering(2, 0))
57        .with_paragraph(
58            Paragraph::with_text("A sub-step, cumulatively numbered").with_numbering(2, 1),
59        )
60        .with_paragraph(heading(
61            "Custom multi-level list (roman numerals, then letters)",
62            true,
63        ))
64        .with_paragraph(Paragraph::with_text("First top-level item").with_numbering(3, 0))
65        .with_paragraph(Paragraph::with_text("A lettered sub-item").with_numbering(3, 1))
66        .with_paragraph(Paragraph::with_text("Second top-level item").with_numbering(3, 0));
67
68    document.save_to_file(&path)?;
69    println!("Wrote {}", path.display());
70    Ok(())
71}
72
73fn heading(text: &str, new_page: bool) -> Paragraph {
74    Paragraph::new()
75        .with_run(Run::new(text).with_bold(true).with_font_size(28))
76        .with_page_break_before(new_page)
77}
78
79/// Every example in this directory writes its output under
80/// `tests-data/output/`, resolved relative to this crate's own manifest so
81/// it works no matter what directory `cargo run` was invoked from.
82fn output_path(filename: &str) -> PathBuf {
83    Path::new(env!("CARGO_MANIFEST_DIR"))
84        .join("../../tests-data/output")
85        .join(filename)
86}