office-toolkit 1.0.0

A Rust library to create, read, and modify Microsoft Office documents (Word/Excel/PowerPoint) in the modern Open XML (OOXML) format.
Documentation
//! Word tables: a plain grid, a table with merged cells (horizontal span
//! and vertical merge), and a table with borders/shading/column widths.
//! One page per feature.
//!
//! Run with: `cargo run -p office-toolkit --example docx_tables`

use std::path::{Path, PathBuf};

use office_toolkit::SaveToFile;
use office_toolkit::prelude::*;
use office_toolkit::word::{Run, Table, TableCell, TableRow, VerticalMerge};

fn main() -> office_toolkit::Result<()> {
    let path = output_path("docx_tables.docx");

    let plain_table = Table::new()
        .with_row(
            TableRow::new()
                .with_cell(TableCell::with_text("Name"))
                .with_cell(TableCell::with_text("Score")),
        )
        .with_row(
            TableRow::new()
                .with_cell(TableCell::with_text("Alice"))
                .with_cell(TableCell::with_text("92")),
        )
        .with_row(
            TableRow::new()
                .with_cell(TableCell::with_text("Bob"))
                .with_cell(TableCell::with_text("87")),
        );

    let merged_table = Table::new()
        .with_row(
            TableRow::new()
                .with_repeat_as_header_row(true)
                .with_cell(TableCell::with_text("Quarterly report").with_horizontal_span(3)),
        )
        .with_row(
            TableRow::new()
                .with_cell(
                    TableCell::with_text("Region").with_vertical_merge(VerticalMerge::Restart),
                )
                .with_cell(TableCell::with_text("Q1"))
                .with_cell(TableCell::with_text("Q2")),
        )
        .with_row(
            TableRow::new()
                .with_cell(TableCell::new().with_vertical_merge(VerticalMerge::Continue))
                .with_cell(TableCell::with_text("1,200"))
                .with_cell(TableCell::with_text("1,350")),
        );

    let styled_table = Table::new()
        .with_column_widths(vec![3_000, 3_000, 3_000])
        .with_border_color("2E74B5")
        .with_indent_twips(360)
        .with_row(
            TableRow::new()
                .with_height_twips(500)
                .with_cell(TableCell::with_text("Header A").with_shading_color("D9E2F3"))
                .with_cell(TableCell::with_text("Header B").with_shading_color("D9E2F3"))
                .with_cell(TableCell::with_text("Header C").with_shading_color("D9E2F3")),
        )
        .with_row(
            TableRow::new()
                .with_cant_split(true)
                .with_cell(TableCell::with_text("1").with_border(true))
                .with_cell(TableCell::with_text("2").with_border(true))
                .with_cell(TableCell::with_text("3").with_border(true)),
        );

    let document = Document::new()
        .with_paragraph(heading("A plain table", false))
        .with_table(plain_table)
        .with_paragraph(heading(
            "Merged cells: a spanning header row and a vertically merged column",
            true,
        ))
        .with_table(merged_table)
        .with_paragraph(heading(
            "Column widths, border color, shading and indentation",
            true,
        ))
        .with_table(styled_table);

    document.save_to_file(&path)?;
    println!("Wrote {}", path.display());
    Ok(())
}

fn heading(text: &str, new_page: bool) -> Paragraph {
    Paragraph::new()
        .with_run(Run::new(text).with_bold(true).with_font_size(28))
        .with_page_break_before(new_page)
}

/// Every example in this directory writes its output under
/// `tests-data/output/`, resolved relative to this crate's own manifest so
/// it works no matter what directory `cargo run` was invoked from.
fn output_path(filename: &str) -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("../../tests-data/output")
        .join(filename)
}