tabwriter
Elastic tabstops for Rust — align tab-delimited text into clean columns.
Repository Health
Technical Analysis
tabwriter is a Rust crate that implements elastic tabstops, a text-alignment algorithm that automatically pads tab-separated columns based on the content of contiguous lines. It wraps any std::io::Write implementation, buffering writes internally and re-aligning columns whenever a block of tab-delimited lines is flushed.
The crate ports the design of Go’s text/tabwriter package to Rust, exposing a small, dependency-light API (TabWriter::new, .minwidth(), .padding(), .alignment(), .ansi()) for formatting CLI output, debug dumps, and generated reports as neatly aligned tables without hand-rolling column-width math.
What You Get
- A
TabWriter<W>type that wraps anyWriteimplementation and transparently aligns tab-delimited output on flush. - Configurable minimum column width, inter-column padding, and left/center/right cell alignment via a builder-style API.
- Optional ANSI escape-code awareness so colored terminal output still aligns correctly on visible character width.
- A companion
tabwriterCLI binary (in thetabwriter-bincrate) that applies the same alignment to piped stdin.
Common Use Cases
- Formatting CLI tool output (help text,
--listresults, diagnostic tables) into aligned columns without manual padding. - Pretty-printing debug or log output where tab-separated fields need consistent visual alignment.
- Building command-line report or table renderers, similar to how Go’s
text/tabwriteris used forkubectl/docker-style output.
Under The Hood
Architecture: The core is TabWriter<W>, which implements io::Write and buffers incoming bytes into an internal Cursor<Vec<u8>> while tracking per-line Cell structs (start, width, size) in self.lines: Vec<Vec<Cell>>. Each call to write() scans the input for \t/\n, terminating the current cell at each delimiter via term_curcell(), which computes display width using count_columns_noansi or count_columns_ansi. A line with only a single cell (no tabs) breaks all contiguous column blocks and triggers an automatic flush. flush() computes per-column widths across contiguous lines with cell_widths() (claimed O(nm) rather than the naive O(n²m)), then rewrites every buffered cell to the underlying writer with left/right/center padding before resetting state.
Tech Stack: Pure Rust (edition 2021), with a single external dependency, unicode-width 0.2.0, used to compute correct display width for Unicode characters. No async runtime, no unsafe blocks in the reviewed source, and a documented MSRV policy (Rust 1.67.0+). The workspace also contains a separate tabwriter-bin crate that adds docopt and serde to expose the same alignment logic as a standalone CLI binary.
Code Quality: src/test.rs (~265 lines) provides table-driven tests via an iseq helper that compares expected vs. actual aligned output across alignment modes, padding settings, ANSI stripping, and tab-indent behavior. The crate enables #![deny(missing_docs)], forcing every public item to carry documentation. Errors surface through standard std::io::Result, with a dedicated IntoInnerError type wrapping flush failures from into_inner(), mirroring the pattern used by std::io::BufWriter.
API Design: Configuration is exposed as chainable builder methods (.minwidth(), .padding(), .alignment(), .ansi(), .tab_indent()) off TabWriter::new(w). Because TabWriter itself implements io::Write, it composes directly with write!/writeln! and any code already targeting a generic writer, keeping the integration surface minimal. Top-level doc comments include runnable doctest examples, and into_inner() provides a familiar way to reclaim the wrapped writer after a final flush.