rusty-figlet 0.3.1

Render ASCII-art banners from text — a Rust port of cmatsuoka's `figlet(6)` v2.2.5 with an in-house FIGfont 2.0 parser, all six horizontal smush rules + universal, 12 bundled `.flf` fonts via `include_bytes!`, terminal-width-aware layout, color/rainbow output, byte-equal Strict-mode upstream compatibility, and a typed library API. v0.2: feature layout reorganized — see CHANGELOG. v0.3: toilet feature parity — TLF parser, 10 filters, HTML/IRC/SVG export, truecolor — see CHANGELOG.
Documentation
rusty-figlet-0.3.1 has been yanked.

rusty-figlet

BREAKING (v0.3.0): Toilet feature parity added. TLF parser, 10 filters, HTML/IRC/SVG export. See CHANGELOG for migration.

crates.io docs.rs CI MSRV license: MIT OR Apache-2.0

Render ASCII-art banners from text. Rust port of cmatsuoka's figlet(6) v2.2.5 & Sam Hocevar's toilet(1) v0.3-1.

Ships 12 bundled .flf fonts + 3 .tlf fonts via include_bytes!. Six horizontal smush rules. Terminal-width-aware layout. 16-color, 256-color, & 24-bit truecolor output. The 10 toilet filters (crop, gay, metal, flip, flop, 180, left, right, border, nothing) composable into pipelines. HTML, IRC mIRC, & SVG export. Byte-equal strict-compat modes for both figlet 2.2.5 & toilet 0.3-1.

Every capability sits behind a Cargo feature. default-features = false strips the entire CLI surface back to the in-house FIGfont parser; pulls only thiserror.

Part of the Rusty portfolio.

Install

cargo install rusty-figlet
# or, with prebuilt binaries:
cargo binstall rusty-figlet
# or, download directly from GitHub Releases:
# https://github.com/jsh562/rusty-figlet/releases

Usage

# Default font (standard.flf)
rusty-figlet "Hello"

# Strict-compat (byte-equal upstream figlet v2.2.5 stdout)
rusty-figlet --strict "Hello"

# Font selection (-f <name> | <path>)
rusty-figlet -f slant "Title"
rusty-figlet -f ./my.flf "Hello"
rusty-figlet -d ./fonts -f mycustom "Hello"

# Output width
rusty-figlet -w 120 "wide banner"
rusty-figlet -t "use terminal width"  # auto-applied in Default if stdout is a tty

# Justification (last-wins)
rusty-figlet -c "centered"
rusty-figlet -l "left"
rusty-figlet -r "right"

# Layout overrides (last layout-class flag wins)
rusty-figlet -k "kerning"          # -k
rusty-figlet -W "full width"        # -W
rusty-figlet -S "force smush"       # -S
rusty-figlet -s "font smush"        # -s
rusty-figlet -o "overlap"           # -o
rusty-figlet -m 24 "explicit"       # -m N

# Color + rainbow
rusty-figlet --color=always "color"
rusty-figlet --rainbow "rainbow"   # per-column HSV gradient (toilet-style)

# 24-bit truecolor / 256-color output (auto-detect via COLORTERM, or force)
rusty-figlet --truecolor "vivid"   # \x1b[38;2;R;G;Bm sequences
rusty-figlet --ansi256 "256-color" # \x1b[38;5;Nm sequences

# Background color (named ANSI or #RRGGBB hex)
rusty-figlet --background=blue "blue bg"
rusty-figlet --background=#1A2B3C --truecolor "custom"

# Toilet filter pipeline (-F filter1:filter2:... left-to-right)
rusty-figlet "Hello" -F crop                  # trim surrounding blanks
rusty-figlet "Hello" -F gay                   # per-column rainbow
rusty-figlet "Hello" -F metal                 # blue/gray metallic gradient
rusty-figlet "Hello" -F border                # box-drawing border around output
rusty-figlet "Hello" -F flip                  # mirror horizontally
rusty-figlet "Hello" -F flop                  # mirror vertically
rusty-figlet "Hello" -F 180                   # rotate 180°
rusty-figlet "Hello" -F left                  # rotate 90° CCW
rusty-figlet "Hello" -F right                 # rotate 90° CW
rusty-figlet "Hello" -F crop:metal:border     # chain, applied left-to-right
rusty-figlet "Hello" -F gay -F border         # multi-flag also concatenates

# Multi-format export (-E html | irc | svg), safe-to-embed XSS-defended
rusty-figlet "Hello" -E html > banner.html    # HTML5 fragment with inline CSS
rusty-figlet "Hello" -E svg  > banner.svg     # SVG 1.1 with <text> + fill attrs
rusty-figlet "Hello" -E irc  > banner.irc     # mIRC ^C color codes
rusty-figlet "Hi" -F gay:border -E html > rainbow-bordered.html

# Toilet-strict-compat (byte-equal upstream toilet 0.3-1 stdout)
rusty-figlet --strict "Hello" -F gay          # 16-color floor, byte-equal toilet

# Suppress downgrade warning when truecolor is requested but unsupported
rusty-figlet --truecolor --no-downgrade-warning "quiet"

# Paragraph mode (preserve newlines vs collapse)
rusty-figlet -p "paragraph"
rusty-figlet -n "normal"

# Control files (Default: accepted-but-ignored with one-time warning)
rusty-figlet -C custom.flc "Hello"
rusty-figlet -N "Hello"

# Figlet-strict mode rejects color flags + control files + completions subcommand
rusty-figlet --strict --color=always "X"   # → exit 2, unrecognized option (figlet 2.2.5 contract)

Library API

Plain figlet rendering (v0.1.x surface, unchanged)

use rusty_figlet::{FigletBuilder, Font};

let figlet = FigletBuilder::new()
    .font(Font::Standard)
    .width(80)
    .build()
    .unwrap();

let banner = figlet.render("X").unwrap();
print!("{banner}");

TLF font loading (v0.3.0, tlf-parser leaf)

# #[cfg(feature = "tlf-parser")]
# {
use rusty_figlet::Figlet;

let figlet = Figlet::from_tlf("assets/fonts/mono9.tlf").unwrap();
let banner = figlet.render("X").unwrap();
print!("{banner}");
# }

Programmatic filter chain (v0.3.0, filter-* leaves)

# #[cfg(all(feature = "filter-crop", feature = "filter-border"))]
# {
use rusty_figlet::{FigletBuilder, filter::{Filter, FilterChain}};

let figlet = FigletBuilder::new().build().unwrap();
let grid = figlet.layout_render("Hello").unwrap();

let chain = FilterChain::new()
    .push(Filter::Crop)
    .push(Filter::Border);
let transformed = chain.apply(grid).unwrap();
# }

Multi-format export (v0.3.0, output-* leaves)

# #[cfg(feature = "output-html")]
# {
use rusty_figlet::export::{write_export, ExportFormat};
# let grid = unimplemented!();

let html_bytes = write_export(&grid, ExportFormat::Html).unwrap();
std::fs::write("banner.html", html_bytes).unwrap();
# }

For library-only consumers without CLI deps, see the Cargo Features section below.

Cargo Features

default enables full which composes every leaf; figlet-classic reproduces v0.1.x bare-port behavior matching upstream figlet 2.2.5 1:1. To strip it down use default-features = false or --no-default-features and then add the features you want.

Feature matrix

Feature Description Umbrella(s)
color ANSI/SGR color writer (`--color=auto always
rainbow Per-column HSV rainbow gradient (--rainbow, toilet-style). Implies color. full, figlet-color, figlet-toilet-compat
terminal-width -t auto-detect via terminal_size. Without this leaf only an explicit -w value (or the 80-col fallback) applies. full
completions completions <shell> subcommand emitting bash/zsh/fish/powershell scripts. Pulls clap_complete. full
strict-compat Hand-rolled upstream-byte-equal getopt parser + --strict dispatch path (figlet 2.2.5 target). full, figlet-classic
tlf-parser TheLetter (.tlf) font-format parser per tlf2a magic. Adds Figlet::from_tlf + Figlet::from_tlf_bytes. full, figlet-toilet-compat
filter-crop Filter::Crop. Trim all-blank rows & cols. full, figlet-toilet-compat
filter-gay Filter::Gay. Per-column rainbow palette sweep (toilet --gay). full, figlet-toilet-compat
filter-metal Filter::Metal. Blue/gray metallic gradient. full, figlet-toilet-compat
filter-flip Filter::Flip. Horizontal mirror (reverse each row). full, figlet-toilet-compat
filter-flop Filter::Flop. Vertical mirror (reverse row order). full, figlet-toilet-compat
filter-rotate Filter::Rotate180, RotateLeft, RotateRight. Three rotations share one leaf. full, figlet-toilet-compat
filter-border Filter::Border. Unicode box-drawing wrap. full, figlet-toilet-compat
color-truecolor 24-bit SGR emission (\x1b[38;2;R;G;Bm). Implies color. Enables --truecolor. full
color-256 256-color SGR emission (\x1b[38;5;Nm). Implies color. Enables --ansi256. full
output-html HTML5 export with inline-CSS spans (-E html). Safe-to-embed: 4-char XSS escape applied to all text + double-quoted attributes per spec Security Posture. full
output-irc mIRC ^C color code export (-E irc). C0/C1 non-printables stripped per FR-015. full
output-svg SVG 1.1 <text> export (-E svg). Safe-to-embed: same 4-char XSS escape table as output-html; no <script>/<foreignObject>/xlink:href/href emission. full
toilet-strict-compat Byte-equal-to-toilet-0.3-1 strict-render path (--strict). 16-color floor; same XSS / IRC-strip defenses as the default path. full

Preset bundles

Bundle Composition Use case
figlet-classic cli + strict-compat Drop-in upstream figlet 2.2.5 replacement. No color, no rainbow, no terminal-width auto-detect, no completions subcommand.
figlet-minimal cli Bare-bones binary, no Strict mode, no extras. Smallest functional CLI.
figlet-color cli + color + rainbow Modern figlet with color + per-column gradient output; no Strict mode or -t auto-detect. Retained at v0.2.x semantics per AD-010 for users who relied on the v0.2.x figlet-toilet-compat deprecated alias.
figlet-toilet-compat (v0.3.0 BREAKING) cli + color + rainbow + tlf-parser + filter-crop + filter-gay + filter-metal + filter-flip + filter-flop + filter-rotate + filter-border v0.3.0 semantics restored. Actual toilet capability parity: TLF font loading, all 10 filters, color, rainbow. v0.2.x users who relied on this name as a figlet-color alias should switch to figlet-color (unchanged). HTML, IRC, & SVG export, truecolor, & toilet-strict-compat are opt-in separately. They aren't bundled here so users pick which output paths to ship.

Safe-to-embed HTML/SVG output

The output-html & output-svg backends apply a hand-rolled 4-character escape to every text-content byte & every double-quoted attribute value: <&lt;, >&gt;, &&amp;, "&quot;. The SVG backend never emits <script>, <foreignObject>, href, xlink:href, or <image href=...>. A user-controlled byte cannot reach a script-execution context.

The --background CLI flag accepts only the 16 named ANSI colors or #RRGGBB hex. Newlines, ANSI escape bytes, shell metacharacters, & partial hex are rejected at parse time before any export emission.

Implementations: src/export/html.rs, src/export/svg.rs. XSS-payload, UTF-8, & bidirectional-script test coverage: tests/export_integration.rs.

Keep-list workaround (Cargo features are union-only)

Cargo features cannot subtract from default. To get "everything except a specific leaf," disable defaults and enumerate the features you want:

cargo install rusty-figlet --no-default-features --features "cli color rainbow"
# → CLI + color + rainbow, but NO terminal-width auto-detect, NO completions,
#   NO strict-compat path.

For the common cases the named preset bundles above are usually sufficient.

Library-only consumers

[dependencies]
rusty-figlet = { version = "0.2", default-features = false }

This strips clap, clap_complete, anstyle, termcolor, & terminal_size. The resulting build pulls only thiserror & the in-house FIGfont parser. The CI test-no-default job runs cargo tree --no-default-features on every PR & fails the build if any CLI-only dep leaks back in.

Convention authority

This layout follows the portfolio-wide Cargo Features Convention. The "why" lives in ADR-0006 (option analysis & rationale); the "what" lives in project-instructions.md §Cargo Feature Surface (canonical rules per port). Every Rusty port from v0.2 onward exposes the same umbrella set (default/full/cli/<port>-classic), per-port leaves named in kebab-case, & 2 to 4 preset bundles.

Compatibility

rusty-figlet has two modes:

  • Default mode. clap-styled flag parser. UTF-8 input. --color & --rainbow enabled. -C/-N accepted-but-ignored with a one-time stderr warning. -t auto-applied when stdout is a tty AND -w is not set. completions subcommand emits shell tab-completion scripts.
  • Strict mode (activated by --strict, the RUSTY_FIGLET_STRICT=1 env var, or invoking the binary as figlet/figlet-alias). Byte-equal stdout against upstream figlet 2.2.5 for documented diagnostics. Latin-1 input clamp. Last-wins flag resolution. Rejects -C, -N, --color, --rainbow, & completions with upstream-format getopt errors (short: invalid option -- '<char>'; long: unrecognized option '--<name>'). No -t auto-apply.

Precedence for Strict activation: --strict > RUSTY_FIGLET_STRICT env > argv[0]. --no-strict overrides every lower-precedence source; if --strict and --no-strict both appear on the command line, last-wins on the command line per upstream getopt convention.

What's not shipped

  • Vertical smushing. Rarely exercised. Deferred.
  • Control files (.flc). -C/-N are accepted-but-ignored in Default mode with a one-time warning. Strict mode rejects them.
  • Right-to-left rendering (-L/-R). Niche. Deferred.
  • Font-info dump (-I <code>). Debug-only. Deferred.
  • Non-Latin bundled fonts (ivrit, smtengwar, smscript, smshadow, smslant, mnemonic, term). Low signal for the Latin/English 99% target. Users add their own via -d <dir>.
  • Toilet TLF fonts beyond the 3 bundled placeholders (mono9.tlf, future.tlf, pagga.tlf). The TLF parser ships in v0.3.0 via the tlf-parser leaf; the bundled fonts are placeholder glyphs pending a Linux-host capture pass for real upstream toilet bytes.

Excluded flags in Strict mode (upstream-format diagnostics)

Flag Type Strict-mode diagnostic Exit
-L, -R short rusty-figlet: invalid option -- '<L|R>' 2
-I short rusty-figlet: invalid option -- 'I' 2
-N short rusty-figlet: invalid option -- 'N' 2
-C short rusty-figlet: invalid option -- 'C' 2
--color long rusty-figlet: unrecognized option '--color' 2
--rainbow long rusty-figlet: unrecognized option '--rainbow' 2
--info-dump long rusty-figlet: unrecognized option '--info-dump' 2
--no-controlfile long rusty-figlet: unrecognized option '--no-controlfile' 2
completions <shell> subcommand rejected as unknown positional (exit 2) 2

The program-name token is substituted figlet:rusty-figlet: per tests/common/mod.rs::strip_for_snapshot; the format of the diagnostic mirrors upstream figlet 2.2.5 getopt byte-for-byte.

BREAKING-CHANGE vs upstream

  • stdin 1 MiB cap. rusty-figlet buffers stdin to a 1 MiB hard ceiling; upstream buffers unbounded. One-time stderr warning per process invocation when the cap is hit.
  • -C/-N Default behavior. Default mode accepts the flags & emits a one-time control files not yet implemented; ignoring -C/-N stderr warning, then renders the input as-is (no transliteration). Strict mode rejects with upstream-format invalid option -- 'C' / unrecognized option.
  • UTF-8 input in Default. Default mode accepts UTF-8 bytes (Latin-1 + multibyte codepoints) & falls back to the font's missing-character glyph + a one-time stderr warning when a codepoint isn't in the font's <hexcode> table. Strict mode clamps input to Latin-1 (ISO-8859-1) bytes-as-codepoints so the upstream byte-equal contract is preserved.
  • -t Default auto-apply. Default mode auto-applies -t when stdout is a tty AND -w is not set. Strict mode does NOT auto-apply -t (preserves byte-equal output at width 80).

See docs/COMPATIBILITY.md for the full per-flag matrix.

Lockstep SemVer

rusty-figlet follows the Rusty portfolio SemVer policy:

  • MAJOR: change Strict-mode byte-exact output format; change FigletError variant payload signatures; change the SemVer surface of FigletBuilder / Figlet / Banner.
  • MINOR: add a new FigletError variant via #[non_exhaustive]; add a new bundled font; add a new CLI flag; add a new FigletBuilder setter.
  • PATCH: bug fixes; performance improvements; doc-only changes.

MSRV

Rust 1.85 (edition 2024). Re-verified against the portfolio's stable-minus-two policy at each release.

License

Dual-licensed under MIT or Apache-2.0 at your option. The 12 bundled .flf fonts under assets/fonts/ are redistributed under the Artistic License as preserved in each font's .flf comment header; per-font attribution lives in THIRD_PARTY.md and the Artistic License is compatible with MIT/Apache-2.0 redistribution.