Skip to content

csvlens

csvlens is a command-line CSV viewer that behaves like less but knows it’s looking at tabular data. You pipe or pass it a CSV and it renders rows and columns inside a scrolling viewport with a header row pinned at top and a status bar at the bottom that doubles as the mode indicator and the command-entry line. It is deliberately read-only — there’s no cell editing — which keeps the whole surface focused on one job: navigating, searching, filtering, and selecting inside a large grid that doesn’t fit on screen. It ships as both a binary and a Rust library, so the table-rendering core can be embedded in another app.

The interaction model is vim-modal-lite: hjkl / arrows scroll, Ctrl+f/Ctrl+b page, g/G jump to top/bottom, and a single TAB key cycles the selection mode between row, column, and cell. That one-key mode cycle is the entry’s strongest idea — the same viewport reinterprets the cursor depending on mode, and the status bar tells you which mode you’re in.

  • Data-table rendering in a fixed grid is a v0.1-adjacent NoshAPI gap. KN-86 carts that present tabular content — mission boards, faction rosters, price tables, dispatch logs — need exactly what csvlens does: a header row, a scrolling body, column-width budgeting against a hard column count, and a status line. csvlens is the cleanest minimal reference because it strips out editing and keeps only the viewing problem, which is the problem KN-86 carts actually have. The 80-column budget (Rows 1–23 content area per CLAUDE.md Canonical Hardware Specification) is tighter than a typical terminal, so its column-fitting logic is directly relevant.
  • TAB-to-cycle-selection-mode is a borrowable input idiom. Row / column / cell as three reinterpretations of one cursor, cycled by a single key, with the current mode named in a status strip. KN-86’s input budget is small (34-key Ferris Sweep), so cycling a mode rather than dedicating three keys to it is the right ergonomic. Maps onto the input-dispatch hold/cycle model. The current selection mode would render in Row 0 (status bar) or on the CIPHER-LINE Row 1 status strip.
  • Column-width-aware rendering under a hard width. csvlens truncates and lets you grow/shrink the selected column with > / <, plus freeze columns from the left with f<n> so the leftmost N columns stay pinned while the rest scroll horizontally. Frozen columns are the answer to “the row-label column must always be visible” — directly applicable to a KN-86 roster where the handle/name column must stay on-screen while stats scroll. Worth lifting wholesale.
  • Regex search + filter as distinct operations on distinct axes. /<regex> searches (jump-to-match with n/N), &<regex> filters rows, *<regex> filters columns (fuzzy-ish column narrowing). The axis-split — rows vs columns get different filter operators — is a clean mental model for any KN-86 cart that needs to narrow a large table to the relevant subset. The Lisp angle (below) makes this especially attractive.
  • Cell-anchored operations. In cell mode, # finds other rows matching the selected cell, @ filters by the selected cell’s value, Enter emits the cell to stdout, y yanks it. “Use the cell under the cursor as the query” is a tidy interaction — no typing a query, just point at an example value. Strong fit for a controller-grade input device with no comfortable text entry.

csvlens is already nearly monochrome-safe: its structure is carried by position and character, not color. The header row is positional (top), column boundaries are drawn with whitespace/separators, and the cursor is the only thing that conventionally uses color. Reframing for amber-on-black:

  • Selection cursor → inversion. The selected row/column/cell renders as amber-on-black inverted to black-on-amber (the standard KN-86 highlight primitive). No hue needed; the inverted block is the cursor. Mode (row vs column vs cell) changes the shape of the inverted region — full-width bar for row, full-height bar for column, single cell for cell — so the mode is legible from the highlight geometry alone.
  • Frozen-column boundary → a box-drawing rule. A vertical (CP437 box-drawing, in the KN-86 Code Page per character-set) between the frozen columns and the scrolling region marks the freeze line without color.
  • Match highlighting → inversion or bracket glyphs. Search hits invert, or get bracketed with ▸ ◂ markers, rather than colored. Filtered-away rows simply don’t render (filter is subtractive, not a color dim), which is inherently monochrome-clean.
  • Status-bar mode indicator → a literal text token. ROW / COL / CELL spelled out in Row 0, plus the active count (12/4096 rows). Text, not a colored pill.

The only thing csvlens uses color for that KN-86 can’t replicate is incidental syntax tinting; everything load-relevant survives the monochrome reframe via inversion + position + box-drawing.

The &<regex> row-filter / *<regex> column-filter split maps naturally onto a Fe-VM predicate model: a KN-86 table cart could let a filter be a Lisp predicate over the row ((lambda (row) (> (field row 'latency) 500))) instead of (or alongside) a regex, evaluated per-row by the cart’s Fe VM. The @-filter-by-cell-value idiom becomes “build a predicate from the example cell.” This is the same query-as-Lisp-expression idea that loglens-core reaches for from the engine side — csvlens shows the interaction end (point at a cell, get a filter) that a Lisp predicate engine would back.

  • Batch 8. The data/grid/table cluster’s cleanest minimal reference — read-only, single-purpose, modal-lite.
  • Frozen columns (f<n>) + TAB-cycle selection modes are the two single-most-borrowable ideas; both survive the monochrome reframe intact.
  • Cross-link sc-im.md — the editing counterpart. csvlens is “view a grid,” sc-im is “edit a grid”; together they bracket the table-cart design space.
  • Cross-link visidata.md — VisiData generalizes csvlens’s filter/search into a whole transformation pipeline; csvlens is the stripped-down “just the viewport” version of the same lineage.
  • Cross-link l123.md and visicalc-archive.md for the spreadsheet-lineage aesthetic; csvlens is the modern Rust/TUI read-only descendant.
  • Embeddable-library shape (run_csvlens_with_options(), CsvlensOptions) echoes the core/UI split called out in loglens-core — the table engine is separable from the binary.