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
//! Excel rich cell data: dates, booleans, formulas (plain, array, and
//! shared), multi-run rich text, hyperlinks, and comments. One tab per
//! feature.
//!
//! Run with: `cargo run -p office-toolkit --example xlsx_rich_data`

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

use office_toolkit::SaveToFile;
use office_toolkit::excel::{Cell, CellComment, CellHyperlink, ExcelDateTime, RichTextRun, Sheet};
use office_toolkit::prelude::*;

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

    let dates_and_booleans_sheet = Sheet::new("Dates and booleans")
        .with_row(Row::new().with_cell(Cell::date(ExcelDateTime::date(2026, 7, 21))))
        .with_row(Row::new().with_cell(Cell::date(
            ExcelDateTime::date(2026, 7, 21).with_time(14, 30, 0),
        )))
        .with_row(
            Row::new()
                .with_cell(Cell::boolean(true))
                .with_cell(Cell::boolean(false)),
        );

    // An array/shared formula's `ref` must be a range whose top-left cell
    // is the cell the `<f t="array"|"shared">` element actually sits in —
    // `with_cell` fills a row left-to-right starting at column A, so each
    // formula cell below is positioned to land exactly on its own `ref`'s
    // first cell, with plain cached-value cells (no `<f>`) filling out the
    // rest of the declared range, matching how Excel itself writes a
    // multi-cell array/shared formula. The previous version declared
    // ranges like "D1:D3"/"E1:E3" while the formula cells actually landed
    // in column A — a real cell/range mismatch Excel refuses to open
    // without repairing.
    let formulas_sheet = Sheet::new("Formulas")
        .with_row(
            Row::new()
                .with_cell(Cell::number(10.0))
                .with_cell(Cell::number(20.0))
                .with_cell(Cell::formula("A1+B1").with_cached_value(30.0)),
        )
        .with_row(
            Row::new()
                .with_cell(Cell::array_formula("A1:A3*2", "A2:C2").with_cached_value(20.0))
                .with_cell(Cell::number(40.0))
                .with_cell(Cell::number(60.0)),
        )
        .with_row(
            Row::new()
                .with_cell(Cell::shared_formula("A1+1", 0, "A3:C3").with_cached_value(11.0))
                .with_cell(Cell::shared_formula_follower(0).with_cached_value(21.0))
                .with_cell(Cell::shared_formula_follower(0).with_cached_value(31.0)),
        );

    let rich_text_sheet =
        Sheet::new("Rich text").with_row(Row::new().with_cell(Cell::rich_text(vec![
        RichTextRun::new("Bold red, ").with_bold(true).with_font_color("FFC00000"),
        RichTextRun::new("then italic blue.").with_italic(true).with_font_color("FF2E74B5"),
    ])));

    let hyperlinks_sheet = Sheet::new("Hyperlinks")
        .with_row(
            Row::new()
                .with_text("Visit Rust")
                .with_text("Jump to C1")
                .with_text("You've arrived"),
        )
        .with_hyperlink(
            CellHyperlink::external("A1", "https://www.rust-lang.org")
                .with_tooltip("Opens in your browser"),
        )
        .with_hyperlink(CellHyperlink::internal("B1", "'Hyperlinks'!C1"));

    let comments_sheet = Sheet::new("Comments")
        .with_row(
            Row::new()
                .with_text("Hover B1 for a comment")
                .with_text("Reviewed"),
        )
        .with_comment(CellComment::new(
            "A1",
            "Reviewer",
            "Double-check this figure before publishing.",
        ))
        .with_comment(
            CellComment::new("B1", "Reviewer", "Looks correct.")
                .with_rich_text(vec![RichTextRun::new("Looks correct.").with_bold(true)]),
        );

    let workbook = Workbook::new()
        .with_sheet(dates_and_booleans_sheet)
        .with_sheet(formulas_sheet)
        .with_sheet(rich_text_sheet)
        .with_sheet(hyperlinks_sheet)
        .with_sheet(comments_sheet);

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

/// 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)
}