YS-L/csvlens
Command line csv viewer
Healthy across all four use cases
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 6w ago
- ✓6 active contributors
- ✓MIT licensed
Show all 6 evidence items →Show less
- ✓CI configured
- ✓Tests present
- ⚠Single-maintainer risk — top contributor 83% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/ys-l/csvlens)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/ys-l/csvlens on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: YS-L/csvlens
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/YS-L/csvlens shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- Last commit 6w ago
- 6 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Single-maintainer risk — top contributor 83% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live YS-L/csvlens
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/YS-L/csvlens.
What it runs against: a local clone of YS-L/csvlens — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in YS-L/csvlens | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 69 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of YS-L/csvlens. If you don't
# have one yet, run these first:
#
# git clone https://github.com/YS-L/csvlens.git
# cd csvlens
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of YS-L/csvlens and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "YS-L/csvlens(\\.git)?\\b" \\
&& ok "origin remote is YS-L/csvlens" \\
|| miss "origin remote is not YS-L/csvlens (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "src/main.rs" \\
&& ok "src/main.rs" \\
|| miss "missing critical file: src/main.rs"
test -f "src/app.rs" \\
&& ok "src/app.rs" \\
|| miss "missing critical file: src/app.rs"
test -f "src/ui.rs" \\
&& ok "src/ui.rs" \\
|| miss "missing critical file: src/ui.rs"
test -f "src/csv.rs" \\
&& ok "src/csv.rs" \\
|| miss "missing critical file: src/csv.rs"
test -f "src/input.rs" \\
&& ok "src/input.rs" \\
|| miss "missing critical file: src/input.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 69 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~39d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/YS-L/csvlens"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
csvlens is a terminal UI CSV viewer written in Rust using ratatui that provides vim-like navigation and interactive features (search, filter, sort, column freezing, line wrapping) for inspecting CSV files. It functions as a pager specifically optimized for tabular data—like less but with CSV-aware features such as regex-based row/column filtering, natural sort order, and cell-level selection modes. Monolithic single-binary design: src/main.rs is the entry point, with core logic split by feature (src/ui.rs for ratatui rendering, src/csv.rs for parsing, src/find.rs for search, src/columns_filter.rs and src/sort.rs for filtering/sorting). State management is procedural (src/app.rs likely holds app state), and src/input.rs handles crossterm event routing. Tests live in tests/data/ with unit/integration tests throughout.
👥Who it's for
Data analysts and engineers who work with CSV files in the terminal and want fast, responsive exploration without leaving the shell. Users familiar with vim keybindings who need to quickly search, filter, and navigate large tabular datasets without opening Excel or Python notebooks.
🌱Maturity & risk
Actively maintained and production-ready. The project is at version 0.15.1 with a detailed CHANGELOG.md, comprehensive GitHub Actions CI/CD (test.yml, lint.yml, release.yml), and structured test data in tests/data/. The codebase shows thoughtful feature evolution (0.14.0 demos for filter improvements, natural sort) and Rust 1.88 minimum MSRV suggests active maintenance.
Low to moderate risk: single-author repo (YS-L) with no visible org backing, which creates succession risk if unmaintained. Dependency footprint is moderate (~15 direct deps) with stable libraries (ratatui, crossterm, csv, regex). No obvious security red flags, but clipboard feature (arboard) is optional and platform-specific (wayland-data-control on Linux). No visible breaking changes in recent CHANGELOG.
Active areas of work
Recent work focused on filter UI polish (0.14.0 flicker fixes in demos/0.14.0-filter-flicker.tape) and natural sort feature (0.14.0-natural-sort.tape/.png). Active GitHub Actions workflows confirm ongoing CI/CD. No visible PR or milestone data, but structured demo assets suggest feature-driven development with visual validation.
🚀Get running
git clone https://github.com/YS-L/csvlens.git
cd csvlens
cargo build --release
./target/release/csvlens tests/data/cities.csv
Daily commands:
cargo build
cargo run -- tests/data/cities.csv
# Or from released binary:
csvlens <file.csv>
# With options:
csvlens file.csv -d '\t' --ignore-case --filter 'value1|value2'
🗺️Map of the codebase
src/main.rs— Entry point that initializes the CLI application and orchestrates the main event loop for CSV viewing.src/app.rs— Core application state machine managing user interactions, view positioning, and state transitions during CSV navigation.src/ui.rs— Ratatui-based UI rendering engine responsible for drawing tables, headers, and visual feedback to the terminal.src/csv.rs— CSV parsing and record iteration logic; handles delimiter detection and data normalization for display.src/input.rs— Key event handling and command parsing layer that translates user input into application actions.src/view.rs— View model logic for calculating visible window, cell positioning, and scroll state based on terminal dimensions.
🧩Components & responsibilities
- Input Handler (input.rs) (Crossterm, clap (optional)) — Translates raw Crossterm key events into high-level commands (scroll, filter, find, goto-line).
- Failure mode: Unrecognized key sequence ignored; user sees no response. Unexpected input can cause command ambiguity (e.g., '/' could mean find or filter).
- App State Machine (app.rs) (Rust struct with mutable state) — Central hub managing CSV data, cursor position, filters, sort order, selection; executes all user commands.
- Failure mode: Invalid state transitions (e.g., scroll beyond file end) not caught; can panic or show incorrect data.
- CSV Parser (csv.rs) — Wraps csv c
🛠️How to make changes
Add a new keyboard shortcut
- Define the key binding constant and action enum variant in src/common.rs (
src/common.rs) - Add input parsing logic in src/input.rs to map the key to the action (
src/input.rs) - Implement the action handler in src/app.rs (add to handle_command or similar) (
src/app.rs) - Document the key binding in src/help.rs help text (
src/help.rs)
Add a new filtering or search feature
- Create a new module (e.g., src/my_filter.rs) with the filter logic (
src/lib.rs) - Add filter state to the App struct in src/app.rs (
src/app.rs) - Integrate filter application in src/csv.rs record iteration or src/view.rs viewport calc (
src/csv.rs) - Add UI rendering in src/ui.rs to display filter status or results (
src/ui.rs)
Add a new display option or theme
- Add a new configuration field to src/app.rs or create a settings struct (
src/app.rs) - Define color/style rules in src/theme.rs (
src/theme.rs) - Apply the theme in src/ui.rs when rendering table cells and widgets (
src/ui.rs) - Add a toggle command in src/input.rs to switch the option at runtime (
src/input.rs)
🔧Why these technologies
- Ratatui — Provides cross-platform TUI widgets and layout management without heavy dependencies; integrates seamlessly with Crossterm for event handling.
- Crossterm — Cross-platform terminal event capture (Windows, macOS, Linux) with low latency; enables raw mode and key event detection.
- csv crate — Robust RFC 4180 CSV parsing with configurable delimiters; handles edge cases like CRLF and embedded quotes efficiently.
- regex — Enables powerful row/column filtering and find functionality with minimal code; users can apply arbitrary pattern matching.
- Rust — Memory safety and single-threaded event loop prevent crashes; fast native compilation suitable for CLI distribution; minimal runtime overhead.
⚖️Trade-offs already made
-
Load entire CSV into memory vs. streaming
- Why: Streaming would support arbitrarily large files but complicates random-access navigation (Go to line N, sort, filter).
- Consequence: csvlens can handle CSV files up to available RAM; very large files (>1GB) may be slow or OOM. Supports standard workflows (100KB–100MB files) efficiently.
-
Single-threaded event loop vs. multi-threaded architecture
- Why: Simpler event handling, no race conditions, easier to reason about state consistency; all logic runs on one thread.
- Consequence: Heavy operations (sort, large regex search) block the UI briefly; no async parallelism but avoids mutex contention.
-
Real-time syntax highlighting vs. deferred rendering
- Why: Ratatui renders on every event; display updates immediately but may stutter under high input frequency.
- Consequence: Responsive feel; users see changes instantly. CPU usage spikes during rapid key presses.
-
In-memory record cache vs. re-parse on every action
- Why: CSV is parsed once at startup; all state modifications (filter, sort) operate on the parsed record set.
- Consequence: Fast interactive response; no I/O overhead. Memory footprint grows with file size.
🚫Non-goals (don't propose these)
- Does not provide distributed or network CSV viewing; CSV must be accessible on local filesystem or stdin.
- Not a CSV editor; read-only viewer with no write or cell edit capabilities.
- Does not handle 1GB+ CSV files efficiently; targeting typical analytical workflows (<500MB).
- No built-in plotting, aggregation, or statistical analysis; purely a pager.
- Not a data validation or schema enforcement tool; displays data as-is.
- Does not support hierarchical or nested data structures; flat tabular data only.
🪤Traps & gotchas
Feature flag requirement: CLI is optional; building without --features cli loses clap parsing (affects MSRV and distributable builds). Clipboard feature: optional arboard crate is Linux-specific (wayland-data-control), may fail silently on headless systems. Stdin handling: watches for both file and piped input (src/watch.rs); mixing --file + stdin may have undefined behavior. CRLF handling: tests/data/cell_with_crlf.csv suggests special handling for Windows line endings—check src/csv.rs for edge cases. Edition 2024: rare Rust edition; ensure Rust 1.88+ (MSRV).
🏗️Architecture
💡Concepts to learn
- Record Iterator (csv crate) — csvlens pipes CSV records lazily without loading entire file into memory; understanding the iterator pattern in src/csv.rs is key to avoiding performance cliffs on large files (benchmarked in benches/record_iterator.rs)
- Crossterm Event Loop (non-blocking I/O) — The TUI must respond instantly to keypresses while also rendering frames; src/input.rs uses crossterm's event API to multiplex stdin and handle raw terminal mode without blocking
- ratatui Constraint-based Layout — Column widths and table cell sizing in src/ui.rs use ratatui's Constraint enum (Percentage, Length, Min, Max) to handle responsive terminal resizing without manual pixel math
- Regex Anchoring & Filtering (Row/Column Selection) — src/find.rs, src/columns_filter.rs, and the & (row filter) keybinding all use regex matching; understanding anchoring (^/$ vs substring match) is critical for user expectations and performance on large datasets
- Natural Sort Order (Lexicographic vs Numeric) — Ctrl+j triggers natural sort in src/sort.rs; distinguishing 'file2' < 'file10' requires numeric-aware comparison, not byte-by-byte lexicographic ordering
- Rust Feature Flags (Conditional Compilation) — Cargo.toml defines optional features (clipboard, cli, bench); understanding #[cfg(feature = ...)] is essential for maintaining distributable binaries and supporting platforms (e.g., headless Linux without arboard)
- ANSI Color & Terminal Theme Abstraction — src/theme.rs + ansi-to-tui dependency bridge ANSI escape codes to ratatui Style objects; critical for syntax highlighting search matches and respecting terminal color schemes
🔗Related repos
BurntSushi/xsv— CLI CSV processing tool with search/select commands; complementary to csvlens for batch operations on CSV filesmitsuhiko/percol— Interactive filter/pager for piped data; similar event-driven TUI architecture and vim keybinding philosophydandavison/delta— TUI pager for diffs using crossterm; shares terminal rendering stack (ratatui ecosystem pattern) and similar build/release workflowgetzola/zola— Rust static site generator also using Cargo feature flags and release CI/CD; reference for production Rust TUI packagingratatui/ratatui— Core dependency; csvlens is a major consumer/showcase of ratatui's table widget and event handling
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for filter and sort functionality in tests/integration_tests.rs
The repo has comprehensive test data files (tests/data/) including filter.csv and natural_sort.csv, but there are no visible integration tests exercising the filter and sort features end-to-end. The src/columns_filter.rs and src/sort.rs modules lack corresponding test coverage. Adding integration tests would catch regressions in these core features and serve as documentation for expected behavior.
- [ ] Create tests/integration_tests.rs with tests for column filtering using filter.csv
- [ ] Add tests for natural sort order using natural_sort.csv (matching the feature demo in .github/demos/0.14.0-natural-sort.tape)
- [ ] Add tests for combined filter+sort operations to ensure they work together correctly
- [ ] Run tests with
cargo testto verify they pass
Add GitHub Actions workflow for clippy linting in .github/workflows/clippy.yml
The repo has lint.yml and test.yml workflows but no dedicated clippy linting workflow. Clippy catches common Rust mistakes and style issues. Given the codebase has 15+ modules in src/, implementing clippy checks in CI would improve code quality and catch issues before review.
- [ ] Create .github/workflows/clippy.yml with
cargo clippy --all-targets --all-featuresjob - [ ] Configure it to fail on warnings with
RUSTFLAGS='-D warnings' - [ ] Run on pull requests and main branch pushes
- [ ] Reference the existing Rust version requirement from Cargo.toml (1.88)
Add edge case tests for CSV parsing in tests/csv_parsing_tests.rs
The test data directory contains several edge case CSV files (bad_73.csv, bad_double_quote.csv, multi_lines_carriage_return.csv, irregular_last_row.csv, starts_with_newline.csv) but no explicit tests validating how src/csv.rs handles these cases. Adding tests would document expected behavior for malformed input and prevent regressions.
- [ ] Create tests/csv_parsing_tests.rs to test CSV parsing with edge case files
- [ ] Add tests for irregular field counts (using irregular.csv and irregular_more_fields.csv)
- [ ] Add tests for carriage return handling (using multi_lines_carriage_return.csv)
- [ ] Add tests for double quote handling (using good_double_quote.csv and bad_double_quote.csv)
- [ ] Verify tests pass with
cargo test csv_parsing_tests
🌿Good first issues
- Add integration tests for column width persistence (src/app.rs state) across filter/sort operations. Currently benches/record_iterator.rs only benchmarks parsing; no test suite validates that custom widths (> and < keybindings) survive filter resets.: easy
- Document the distinction between row/column/cell selection modes (TAB keybinding) in help.rs. The README lists modes but src/help.rs may not explain which features apply to each mode (e.g., #-highlight only in cell mode).: easy
- Extend src/sort.rs to support multi-column sort (e.g., sort by col A, then col B). Current implementation (shift+down) appears single-column only; adding rank-based sorting would improve usability for tie-breaking.: medium
⭐Top contributors
Click to expand
Top contributors
- @YS-L — 83 commits
- @jqnatividad — 12 commits
- @giantatwork — 2 commits
- @henrebotha — 1 commits
- @starsep — 1 commits
📝Recent commits
Click to expand
Recent commits
6491a73— Bump ratatui version to 0.30 (YS-L)6742a8e— Update build_bench_data.rs for rand 0.10.0 (YS-L)3383c07— deps: Bump dependencies (#196) (jqnatividad)18fa5ff— deps: bump csv nose to 0.8.0; update lock file (#195) (jqnatividad)2d80ed6— Fix typo (#194) (henrebotha)c76aaa5— deps: replace qsv-sniffer with csv-nose (#191) (jqnatividad)1698ec7— Specify include list for package (YS-L)6b58904— Update help text and README for exporting marked rows (YS-L)5df8087— Export/print marks to stdout (#187) (giantatwork)a5bd632— Release v0.15.1 (YS-L)
🔒Security observations
The csvlens codebase demonstrates generally good security practices with proper use of safe Rust dependencies and no obvious hardcoded secrets or injection vulnerabilities. However, there are several areas for improvement: the Cargo.toml uses an invalid Rust edition (2024), loose dependency version constraints that could allow vulnerable versions, and missing security documentation. The application's regex-based find functionality warrants additional input validation testing to prevent ReDoS attacks. Overall security posture is moderate with manageable risks that can be addressed through configuration updates and documentation additions.
- Medium · Edition field uses invalid value '2024' —
Cargo.toml (line: edition = "2024"). The Cargo.toml specifies edition = '2024', which is not a valid Rust edition. Valid editions are 2015, 2018, and 2021. This will cause build failures and prevents proper edition-specific compiler behavior for security features. Fix: Change edition to a valid value, preferably '2021' for latest language features and security improvements. - Medium · Deprecated regex crate version constraint —
Cargo.toml (dependencies section). The dependency specification 'regex = "1"' uses a loose version constraint that could allow installation of any regex 1.x version, including versions with known vulnerabilities. Current recommendation is to use more specific version pinning or use MSRV-tested versions. Fix: Update to 'regex = "1.11"' or later, and consider using more specific version constraints like '~1.11' for better control over updates. - Low · Unspecified MSRV consistency —
Cargo.toml (rust-version = "1.88"). The rust-version is set to '1.88', but this is a very recent nightly version. Ensure this MSRV is intentional and documented, as it may limit compatibility for users with older stable Rust versions. Fix: Verify that MSRV 1.88 is intentional. Consider using a stable release version (e.g., 1.70) unless the latest features are required. Document the MSRV requirement in README. - Low · Optional clipboard feature with platform-specific considerations —
Cargo.toml (arboard dependency with wayland-data-control feature). The arboard dependency for clipboard functionality is optional but has platform-specific features (wayland-data-control). While optional, ensure users are aware of clipboard feature permissions and data exposure risks. Fix: Document clipboard feature behavior and privacy implications in README. Consider adding a security advisory about clipboard data access. - Low · Development dependencies include rand without restriction —
Cargo.toml (dev-dependencies section). The rand crate is included in dev-dependencies without tight version constraints (rand = "0.10"). While this is for benchmarking/testing only, ensure test data generation doesn't introduce non-deterministic behavior in security-sensitive tests. Fix: Document the use of rand in benchmarks. Consider using deterministic seeds for reproducible test results if security properties are being tested. - Low · Missing security policy documentation —
Repository root. No SECURITY.md or security policy file is visible in the repository structure. This makes it difficult for security researchers to report vulnerabilities responsibly. Fix: Create a SECURITY.md file with responsible disclosure guidelines and contact information for reporting security issues. - Low · Limited input validation context —
src/find.rs, src/csv.rs. The application handles CSV parsing and regex-based filtering. Without reviewing source code, potential regex DoS (ReDoS) vulnerabilities could exist if user-supplied regex patterns are not validated or sandboxed. Fix: Implement regex pattern validation with timeouts. Consider using regex crate's recommended patterns to prevent ReDoS attacks. Add tests for malicious regex patterns.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.