tabwriter

Elastic tabstops for Rust — align tab-delimited text into clean columns.

Library
Cargo
v1.4.1
273stars
Unlicense

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
34/100Needs Attention
Development Activity0
Maintenance0
Community56
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
79/100Good
Architecture80
Code Quality78
Innovation82
Learning Curve75

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 any Write implementation 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 tabwriter CLI binary (in the tabwriter-bin crate) that applies the same alignment to piped stdin.

Common Use Cases

  • Formatting CLI tool output (help text, --list results, 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/tabwriter is used for kubectl/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.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search