Own a bounded Miller-column directory explorer
Canonical Quirl project documentation synced from docs/decisions/2026-09-01_192326140_own-a-bounded-miller-column-directory-explorer.md.
Accepted · 2026-09-01
Context
Changing a shell's working directory cannot be delegated to a child file-manager process: a child can report a path, but it cannot mutate its parent's process state. Quirl therefore needs an explicit handoff between directory navigation, terminal ownership, and the process composition root.
Miller columns provide more spatial context than a flat picker: the parent, current directory, and selected child's preview remain visible together. Existing Rust file explorers demonstrate the interaction well, but importing a complete application would also import its traversal, mutation, preview, dependency, and terminal-lifecycle decisions. Those decisions do not satisfy Quirl's required resource and error contracts without a substantial audit and rewrite.
Decision
The rich surface owns a Quirl-native Miller-column explorer opened with
Alt-Q c. It uses the existing Ratatui/Crossterm stack and the bounded directory
lister in quirl-core. Bundled source grammars come from syntect; bounded
raster decoding comes from image with only GIF, JPEG, PNG, and WebP enabled.
Both are in-process Rust dependencies with unnecessary discovery, encoder,
parallel, and high-cost format features disabled.
Syntect 5.3.0 contributes 75 bundled syntax definitions. Some are embedded
helpers rather than standalone languages, and its bundle does not include TOML,
so Quirl owns a small bounded TOML lexer for previews. Both sources reduce
grammar scopes to semantic roles such as comment, string, number, keyword,
property, operator, and error. Rendering resolves those roles through the active
Quirl theme instead of retaining colors from an unrelated syntax theme; custom
themes and NO_COLOR therefore apply consistently to the editor and explorer.
The explorer is a modal transaction:
- The UI snapshots the current directory and preserves the editor buffer and UTF-8 cursor.
- Left/right navigation changes only explorer-local paths. Syntax-highlighted text, bounded raster images, binary data, metadata, and immediate-child previews are read without executing content.
- Escape discards the explorer. Enter returns a typed path after the rich terminal is released.
quirl-clirestores the editor input and asksquirl-processto commit the directory transition. A failed commit retains the previous process directory and becomes a normal rich diagnostic.
Listings retain at most 4,096 entries and 2 MiB of filename text. Search retains at most 1,024 UTF-8 bytes. Text previews read at most 128 KiB, retain at most 4,096 lines and 32,768 styled spans, and use one process-wide immutable grammar and semantic-scope cache. Binary previews render only the first 4 KiB as hexadecimal. Image previews admit at most 16 MiB of encoded input, reject either dimension above 8,192 pixels, give the decoder a 64 MiB allocation budget, and retain at most a 160×100 RGBA thumbnail. Directory previews are non-recursive and use the same listing bounds. Sorting, hidden-file display, refresh, and navigation rebuild bounded snapshots rather than accumulating prior views.
Image pixels render through Ratatui cells. Unicode terminals use upper-half
blocks for two vertical pixels per cell; the plain-symbol profile uses colored
cell backgrounds. This avoids terminal-specific image escape protocols and
external preview helpers. NO_COLOR keeps metadata visible and suppresses pixel
rendering.
The first version deliberately excludes file mutation. Rename, copy, move, create, and delete require separate collision, symlink, permission, partial-copy, durability, cancellation, and confirmation contracts. They must not be inherited implicitly from an application dependency or hidden behind generic callbacks.
Failure model and invariants
- Browsing, preview failure, refresh failure, and dismissal never change the process working directory.
- The process directory changes only through
quirl-process, after the rich surface has returned a typed path to the composition root. - A failed
set_current_dirleaves the prior directory active and produces an actionableShellError. - Every retained collection and byte buffer in the explorer has a fixed bound. Listings and previews never recurse.
- Filesystem names and error text are escaped before terminal rendering. File contents are data only; no preview handler executes them or dispatches to an external program.
- Text preview requires valid UTF-8 and no NUL byte. Supported raster formats cross encoded-byte, dimension, and allocation checks before pixels are retained. Other data is rendered as a bounded hexadecimal view. No decoded bytes are interpreted as terminal control sequences.
- The preserved editor cursor is validated as an in-bounds UTF-8 boundary before it is accepted for restoration.
- Terminal restoration remains owned by the rich-surface guard on acceptance, dismissal, I/O failure, and unwind.
Individual filesystem calls can still wait on an unresponsive kernel or remote mount; stable Rust does not provide cancellable directory and ordinary-file I/O. The retained work around each call is bounded, and no background thread or child process is leaked when it returns.
Consequences
Quirl gains contextual, keyboard-first directory jumping with highlighted source and portable raster previews while keeping shell state and terminal cleanup explicit. Bundled grammars and four image decoders add binary size and supply-chain review cost; disabling unrelated features and retaining only a small thumbnail bounds that cost at runtime. File mutation remains a follow-up design rather than an accidental expansion of the first release's data-loss surface.
Rust-native releases and runtime assets
Canonical Quirl project documentation synced from docs/decisions/2026-08-18_192326126_rust-native-releases-and-runtime-assets.md.
Codex CLI provides the first hosted command planner
Canonical Quirl project documentation synced from docs/decisions/2026-09-02_192326146_codex-cli-provides-the-first-hosted-command-planner.md.