Rust API
Crates
| Crate | Purpose |
|---|---|
gridwell-ir |
IR types, parsing, validation |
gridwell-core |
Shared utilities (colors, lengths, font sizes, XML escaping) |
gridwell-layout |
The resolved table every writer renders: visible grid, spans, style cascade |
gridwell-ooxml |
Deterministic zip packaging for the DOCX/XLSX/PPTX writers |
gridwell-render |
The format registry: Writer trait, every format by name, options as JSON |
gridwell-writer-html |
HTML renderer |
gridwell-writer-latex |
LaTeX renderer |
gridwell-writer-typst |
Typst renderer |
gridwell-writer-rtf |
RTF renderer |
gridwell-writer-svg |
SVG renderer |
gridwell-writer-ansi |
Terminal renderer |
gridwell-writer-pandoc |
Pandoc AST renderer |
gridwell-writer-quarto |
Quarto renderer |
gridwell-writer-docx |
Word renderer |
gridwell-writer-xlsx |
Excel renderer |
gridwell-writer-pptx |
PowerPoint renderer |
Parsing
use gridwell_ir::Table;
let json = std::fs::read_to_string("table.json")?;
let table = Table::from_json(&json)?;Validation
let errors = table.validate();
if errors.is_empty() {
println!("Table is valid");
} else {
for err in &errors {
eprintln!("Validation error: {err}");
}
}Rendering by format name
The registry validates the table, looks up the format, and checks the options. This is what the CLI and the C, Python and R bindings use.
use gridwell_render::{render, Output, REGISTRY};
let options = serde_json::json!({ "inline_styles": true });
match render(&table, "html", Some(&options))? {
Output::Text(html) => println!("{html}"),
Output::Binary(bytes) => std::fs::write("out.bin", bytes)?,
}
// Every format, with its metadata and default options
for w in REGISTRY {
println!("{} (.{}): {}", w.name(), w.extension(), w.default_options());
}Saving to a file
save() renders and writes the bytes unchanged. With no format it is inferred from the extension (format_for_path()); options are a JSON string, with file defaults on top (ansi writes plain text unless color is set). It returns the writer used.
use std::path::Path;
use gridwell_render::{format_for_path, save};
save(&table, Path::new("table.rtf"), None, None)?;
save(&table, Path::new("table.json"), Some("quarto"), Some(r#"{"table_id": "t1"}"#))?;
assert_eq!(format_for_path(Path::new("T.DOCX"))?.name(), "docx");Errors are one gridwell_render::RenderError: UnknownFormat, WrongKind, InvalidTable, InvalidOptions or Writer, and from save()/format_for_path() NoExtension, UnknownExtension, AmbiguousExtension (.json is pandoc and quarto) or Io (with the path).
Using a writer directly
Each writer crate can also be used on its own. Its functions take a &Table and assume it is valid: call table.validated() (or validate()) first.
use gridwell_writer_html::{render_html, HtmlWriter, HtmlWriterConfig};
// Default settings
let html = render_html(&table)?;
// Custom config
let config = HtmlWriterConfig {
inline_styles: true,
pretty_print: false,
class_prefix: "my-table".to_string(),
};
let writer = HtmlWriter::with_config(config);
let html = writer.render(&table)?;All Text Writers
gridwell_writer_html::render_html(&table)?;
gridwell_writer_latex::render_latex(&table)?;
gridwell_writer_typst::render_typst(&table)?;
gridwell_writer_rtf::render_rtf(&table)?;
gridwell_writer_svg::render_svg(&table)?;
gridwell_writer_ansi::render_ansi(&table)?;
gridwell_writer_pandoc::render_pandoc(&table)?;
gridwell_writer_quarto::render_quarto(&table)?;Binary Rendering
use gridwell_writer_docx::render_docx;
use gridwell_writer_xlsx::render_xlsx;
use gridwell_writer_pptx::render_pptx;
let docx_bytes = render_docx(&table)?;
std::fs::write("output.docx", &docx_bytes)?;Error Handling
use gridwell_ir::{Table, ParseError};
match Table::from_json(input) {
Ok(table) => { /* use table */ },
Err(ParseError::Json(e)) => eprintln!("Invalid JSON: {e}"),
}