CSV mode: csvlens and tidy-viewer-core as alternatives to xan
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
Research direction
Start with the CSV-mode spike in #288 and compare the two approaches described here: a foreground handoff to csvlens and an in-pager mode using the csv crate with tidy-viewer-core formatting. The issue does not name implementation files or tests; first inspect the pager’s rendering, input, and effect flow and check the dependencies’ APIs and packaging constraints. Done means returning a concrete comparison and recommendation that addresses the listed trade-offs.
Written by the indexing model from the issue text.
Description
Problem / motivation
Companion to #288 (CSV mode in the pager — evaluate xan as the engine). That
issue lands on "xan is a binary-only crate, so it's an upstream ask, a vendor,
or roll-our-own." Before committing to any of those, the two obvious
alternatives deserve the same look — and both turn out to answer the question
better than xan does, in opposite ways.
Filing separately so the spike in #288 has something concrete to compare
against rather than a one-line "worth a look" bullet.
Proposed solution
Evaluate YS-L/csvlens and
alexhallam/tv (tidy-viewer) as the CSV
engine. Summary of what's actually in the manifests:
| xan (#288) | csvlens | tidy-viewer-core | |
|---|---|---|---|
| Library target | ❌ bin only | ✅ src/lib.rs, documented |
✅ purpose-built core crate |
| On crates.io | ✅ | ✅ 0.15.1 |
❌ publish = false |
| License | Unlicense OR MIT | MIT | Unlicense OR MIT |
| ratatui | 0.29 | 0.30 (our version) | n/a (emits strings) |
| crossterm | n/a | 0.29 (our version) | n/a |
| Direct deps | ~90 | ~16 | 5 |
| Maintained | active | active (2026-07) | last push 2025-08 |
| Shape | CLI subcommands | self-driving TUI | pure formatter |
csvlens — the best feature answer, the wrong architecture.
It is genuinely a library (src/lib.rs opens with "This crate allows you to
use csvlens as a library"), MIT, and its stack is an exact match for ours:
ratatui 0.30, crossterm 0.29, ansi-to-tui 8, arboard 3 — all versions spyc
already carries. Feature-wise it's everything #288 asks for and more: find,
sort, column filter, wrap modes, sticky header, --watch live reload, themes.
The catch is the public API:
pub fn run_csvlens(args: &[&str]) -> Result<Option<String>>;
pub fn run_csvlens_with_options(opts: CsvlensOptions) -> Result<Option<String>>;
That's it (plus errors and a cfg-gated bench_api). It takes over the
terminal, runs its own event loop, and returns the selected cell — the
internals that would actually render into a PagerView (view, wrap, ui,
csv) are all private mod, not pub mod. So it's not a renderer we can call
from a pure &self draw pass; it's an application. That collides head-on with
the MVU invariants — one update entry, one message channel, Effect as the
sole executor — and it reads from /dev/tty directly (crossterm's
use-dev-tty), which has to be reasoned about against our input-reader thread
and the pty pane.
Which leaves two shapes for it:
- Foreground handoff — treat it exactly like the
v→$EDITORpath:
suspend the loop, hand over the terminal, take back the selected cell on
exit. Cheap to build, enormous feature win, and the returned cell is a nice
hook (yank it, filter on it). But it's a modal escape hatch, not "an entry
into the file": its keymap, not ours; nogf, no buffer history, no vsplit
preview, no theme integration. - Upstream ask to make the rendering internals public — same shape of
problem as xan's missing[lib], just a smaller ask.
Also worth weighing: arrow 59 is a direct dependency, which is a lot of crate
family to take on for a viewer, though default-features = false +
features = ["csv"] trims it. The cli and clipboard features are both
optional and we'd drop both.
tidy-viewer-core — the best architectural fit, with a packaging problem.
tv is a workspace, and tidy-viewer-core is a deliberately extracted library
("shared between the CLI and Python bindings"). It is tiny — five
dependencies (lazy_static, regex, unicode-truncate, unicode-width,
itertools) — and it is pure formatting logic with exactly the signature shape
our renderers want:
format_strings(&data, min_col_width, max_col_width, sig_figs, preserve_scientific, max_decimal_width) -> Vec<String>
calculate_column_width(&formatted, min, max) -> usize
is_na(&str) -> bool
No terminal, no event loop, no ratatui — Vec<String> in, Vec<String> out.
That drops straight into model + &Theme -> Vec<Line> with no adaptation, and
it brings the one thing neither xan nor csvlens gives us for free: datatype
inference with significant-figure numeric formatting, which is most of what
makes tv's output readable.
Blockers:
publish = false— it is not on crates.io. A git dependency is not an
option: crates.io rejects published crates that carry them, and spyc ships
viacargo install spyc. So this is vendor-with-attribution (license
permits) or an upstream ask to publish the core crate.- Repo last pushed 2025-08; the CLI crate carries deprecated/unmaintained
deps (structopt,atty→ RUSTSEC-2021-0145, crossterm 0.22, arrow/parquet
56). None of that is incore, so the blast radius is limited if we only
take core — but it is a maintenance signal, andaudit.ymlwould see it if
we ever pulled the workspace. unicode-width0.1 vs our 0.2 — a duplicate in the tree, and width
agreement is load-bearing for us (see the grapheme-cluster note in
Cargo.toml).
Where this points. These two aren't really competing — they're
complementary, and the spike in #288 should probably come back with both:
- A. Foreground handoff to csvlens as the power view (an
o-style verb,
or its own key), for when you want to search/sort/filter a CSV — accepting
that it's a separate application with its own keymap. - B. An in-pager CSV mode for
Enter, built on thecsvcrate plus
tidy-viewer-core's formatting (vendored or upstream-published), keeping
gf/ buffer history / vsplit preview / our theme.
B is the one that closes #288's actual complaint. A is a large win for
comparatively little work and could land first.
Alternatives considered
- xan — #288. Binary-only, ~90 direct deps; strictly worse on both axes
than the two above, though itsflattenview is still nice prior art. - visidata — Python, so out of scope as a library; worth reading purely
for UX prior art on column navigation. - Roll our own end to end (
csvcrate + our own width/format logic) —
still viable, and note that option B above is only a short step from it:
tidy-viewer-core is small enough that "vendor it" and "write it" are closer
in cost than they look. The significant-figure formatting is the part worth
not reinventing.
- Dominant language
- Rust
- Stars
- 17
- Forks
- 2
- Avg merge
- 35m
- Merged PRs (30d)
- 413
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Tripstack-Corp/spyc
-
area:pager area:ui idea needs-design
Difficulty 4/5 3-5 days Newbie friendliness 52/100
Tripstack-Corp/spyc#1078 ·
Maintainers usually reply within 1 day
-
area:agent type:fix
Difficulty 4/5 3-5 days Newbie friendliness 45/100
Tripstack-Corp/spyc#1000 ·
Maintainers usually reply within 1 day
-
area:build-ci type:chore
Difficulty 3/5 1-2 days Newbie friendliness 45/100
Tripstack-Corp/spyc#933 ·
Maintainers usually reply within 1 day
-
area:ui type:feat
Difficulty 4/5 3-5 days Newbie friendliness 42/100
Tripstack-Corp/spyc#932 ·
Maintainers usually reply within 1 day
-
area:build-ci type:chore
Difficulty 4/5 3-5 days Newbie friendliness 35/100
Tripstack-Corp/spyc#930 ·
Maintainers usually reply within 1 day
All issues in Tripstack-Corp/spyc
Similar issues
-
area:models enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
bug frontend ui
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
aosama/astronomical#1973 ·
Maintainers usually reply within 1 day