All notable changes to batty are documented here. The format follows
Keep a Changelog, and the project
adheres to Semantic Versioning.
While at 0.x:
0.x.y → 0.(x+1).0for any new feature or breaking change.0.x.y → 0.x.(y+1)for bug fixes only.
0.15.0 — 2026-07-01
.jsonl/.ndjsonfiles are highlighted with the JSON grammar.- Prettified JSONL view: each line is expanded to multi-line, indented,
highlighted JSON. Auto-on for
.jsonl/.ndjson;--prettyforces it on any file,--no-pretty(configpretty/no-pretty) opts out. Interactivepkey toggles raw↔pretty with scroll position preserved; malformed/blank lines pass through dimmed; the gutter shows source-line numbers.
batty file.jsonlnow prettifies by default instead of printing raw lines (use--no-prettyfor the old behavior).
0.14.0 — 2026-06-18
- Interactive (
-i) and live (--live) modes can now soft-wrap long lines. Presswto toggle wrapping on/off live; overflow continues on the next visual row with a blank line-number gutter, the top row stays a numbered source line, and nothing scrolls off-screen. The initial state follows the raw--wrapvalue (character/wordstart wrapped;auto/never— the default — start in the existing truncate-at-edge mode).--wrap=wordselects word-boundary breaks; otherwisewuses character breaks. The status bar shows awraptag while on.
--wrapis no longer forced toneverin interactive/live mode; the raw value seeds the initial wrap state.
0.13.2 — 2026-06-17
--live(and--interactive): long lines no longer push the top rows off the screen. Interactive and live modes forcewrap=Never, whose job is to keep one source line on one visual row — butNeveremits each line in full, so any line wider than the terminal was soft-wrapped by the terminal onto extra rows. Those extra rows overflowed past the status bar and scrolled the alt-screen up, so with three wrapped lines near the top the first visible line became line 4. Each body line is now truncated to the terminal width (ANSI-aware, never splitting a wide char, re-emittingRESETwhen color is cut) before it's drawn, so the one-line-one-row viewport invariant holds.
0.13.1 — 2026-05-25
--live(and--interactive): eliminate visible flicker. Each frame used to issueClear(ClearType::All)followed by separateexecute!calls for the body and status bar; becauseexecute!flushes after every call, the terminal briefly showed a fully cleared screen before the new content arrived. Frames are now built withqueue!and a single trailing flush, so clear + body + status bar reach the terminal as one atomic write. Additionally, the loop no longer re-renders on 200 ms idle ticks — aneeds_renderflag gates the redraw, so the screen is only touched on key events, resize, file reload, or when the[live · reloaded]flash expires.
0.13.0 — 2026-05-25
--live(andlive = truein config): new alt-screen TUI mode that re-renders the file whenever its contents change. Same keybindings as--interactive(j/k, g/G, Ctrl-d/u, PgUp/PgDn, m, n, +/-, q). Cursor and scroll position are preserved across reloads (clamped if the file shrinks). Mutually exclusive with--interactiveand--follow; single-file only; no stdin. Change detection uses an mtime+len fast path followed by a byte compare, sotouchandvim :won an unchanged buffer do not cause spurious redraws. Status bar shows[live], flashing[live · reloaded]for 1.5 s after each reload. Add--no-liveto overridelive = truein config.
0.12.0 — 2026-05-24
--wrap=word(andwrap = "word"in config): new wrap mode that breaks at whitespace boundaries (char::is_whitespace) instead of column boundaries. Words longer than the wrap width fall back to character-break automatically, so the output never overflows the terminal. ANSI color escapes and persistent SGR attributes (e.g. the INVERT used for highlighted lines) are preserved across word breaks exactly as in--wrap=character.--wrap=autois unchanged — still resolves tocharacteron a TTY andneveroff — so users opt into word-wrap explicitly.
0.11.0 — 2026-05-24
--wrap=auto(the default) is now TTY-aware: when stdout is not a terminal (piped to a file or another command), batty no longer inserts line breaks or continuation prefixes. Matchesbat's long-standing behavior. Explicit--wrap=charactercontinues to wrap regardless of stdout type;--wrap=neveris unchanged.- Rhai single-quoted character literals now carry the more specific
TextMate scope
string.quoted.single.char.rhai(wasstring.quoted.single.rhai). Prefix matching means every existing theme rule that styledstring.quoted.singlestill applies — no visible change in the bundled themes — but custom themes can now specialize on char literals.
0.10.1 — 2026-05-22
- Crate-root
#![doc = include_str!("../README.md")]so docs.rs renders the full README on the crate landing page instead of a bare module list. No behavior change to the binary.
0.10.0 — 2026-05-19
- Colorized
--examplesflag: curated, copy-pasteable usage scenarios for every common flag. Mirrors the pattern used incodedeviate/reconfor cross-repo uniformity. HonorsNO_COLORand TTY detection; short-circuits before pager / file validation so it works without any arguments. - Hand-written man page at
man/batty.1covering every CLI flag, the interactive keybindings, the config schema, and the environment variables. Install instructions added to the README. - CLAUDE.md conventions requiring both
man/batty.1andsrc/examples.rsto stay in sync withsrc/cli.rson every change.
0.9.1 — 2026-05-17
- Published to crates.io as
batty-cat(thebattyname was taken). The binary, repo, and Homebrew formula all remainbatty; only the crate name on crates.io differs. - Added shields.io badge header (GitHub, latest release, crates.io, Homebrew tap, Rust edition / MSRV, license) to README.md for cross-repo uniformity.
0.9.0 — Earlier
--encodingflag (alsoencoding = "..."in config) selecting how file/stdin bytes are decoded. Values:auto(default; tries UTF-8, falls back to ISO-8859-1 on decode failure),utf-8(strict — errors with a hint on invalid sequences),iso-8859-1/latin1(every byte0x00–0xFF→U+0000–U+00FF). Decoder is dependency-free.
- Reads are now always done as bytes via
fs::read+input::decode, notfs::read_to_string.
- Default
autoencoding means older files that happened to be Latin-1 now open silently instead of erroring with a UTF-8 decode error.
- Markdown gutter: source-line numbers (and optional grid bar) next to
rendered blocks. New
markdown::render_with_gutterreuses the 0.7.0 source map — each block's first rendered row carries its source line; continuation rows are blank in the number column with the grid bar repeating. Static path honors--style=numbers,grid(and--no-gutterstrips). Interactive markdown view honors the liventoggle.
- Row-counting bug in
render_with_mapthat over-counted rows when a block-render ended in\n, miscalculating later block-start indices.
- Diff markers and the
▶cursor glyph remain absent in markdown view (block-granular mapping doesn't make them meaningful).
- Markdown rendering truncated documents containing inline tags
(
**bold**,*emph*,`code`). The block-walker was decrementing depth on everyEndevent including inline ones but only incrementing on block-levelStarts, so inline tags would unbalance the counter and prematurely close the outer paragraph. Regression test added.
- Source-line ↔ rendered-line mapping in markdown view (per-block
rendering via
pulldown-cmark+termimad), som-toggle in interactive mode preserves scroll position both directions. Status bar showsrendered N/M ↔ src K. - New
--gutter/--no-gutterflag and matchingnkey in interactive mode to live-toggle the gutter (line numbers + cursor glyph). - Added
pulldown-cmarkas a direct dep (already transitive viatermimad).
--markdown-on-extension(andmarkdown-on-extension = trueconfig key): renders.md/.markdown/.mdown/.mkdfiles as markdown automatically while leaving source files raw. Precedence:--no-markdown>--markdown>--markdown-on-extension> default.
- Live
+/-keys in interactive mode adjust--top-padon the fly. Useful when a terminal (Warp) overlays UI on the alt-screen's top rows and the right pad value varies tab-to-tab or after pane resizes. Status bar showspad=Nwhen nonzero.
--helpflags are now alphabetical by long-flag name.Clistruct insrc/cli.rsreordered to match; convention captured in CLAUDE.md.
--wrapactually wraps.character/autobreak long lines at the terminal-width boundary with a continuation prefix that keeps the gutter intact.- ANSI escape sequences tracked across breaks so colors /
INVERTresume on each continuation. - Wide CJK / emoji chars count via
unicode-width. - Forced to
neverin interactive mode (viewport math assumes 1 source line = 1 visual row).
- Users on the default
--wrap=autonow get proper wrapping (with gutter) rather than terminal-level overflow.
- Rhai grammar polish: backtick template strings with
${expr}interpolation,#{}map-literal prefix,??/?.operators,::module accessor, leading-dot floats, expanded builtin list (Fn,call,curry,is_def_var,is_def_fn,is_shared,eval,parse_int,parse_float,to_int,to_float,to_blob,to_array,to_map). Function-name scope no longer includes trailing whitespace.
--follow/-ftail mode (tail -fsemantics with highlighting).--tail-linesfor count,--no-followopt-out,follow = trueconfig key.
ruleandsnipstyle components now functional (previously parsed but inert).expand_tabshonors Unicode column width.- Rhai grammar gains range / bitwise / nested-block-comment support.
- Internal cleanup: dropped
Cli::parse_from_args,StyleFlags::anyiscfg(test)-gated,term_widthusescrossterm::terminal::size, SIGPIPE reset on Unix.
- Scrolling works in interactive markdown view (j/k/g/G/Ctrl-d/u/PgUp/
PgDn). Independent rendered-row scroll counter; status bar shows
rendered N/M.
OUT-OF-SCOPE.md.
--markdown/-mrenders Markdown to terminal escapes (viatermimad).--no-markdownopt-out.markdown = trueconfig key.mkey toggles raw ↔ rendered in interactive mode (status bar shows[md]).
--paging=neveralso disables interactive mode (treats--pagingas a global flat-output signal).
--no-interactiveshows in short help (-h), not just long help.
- Duplicate-flag conflict when config + CLI overlap.
--no-interactiveto override config.--list-*short-circuits before interactive.BATTY_CONFIG_PATHenv var.
- Interactive TUI (
-i). - Relative line numbers.
--top-pad.- TOML config at
~/.config/batty/config.toml.
- TOML config replaces the previous line-based config format.
- Initial release: full
bat-parity (highlighting, git diff, pager, config, themes), bundled Rhai grammar, 36 tests, 2.5 MB binary.