l0ng-ai 9ffd1f89ef fix(diff): bound the untracked list and stop a moving default flipping toggles
Five findings from the review of the previous commit, all confirmed against the
source before acting.

The untracked list escaped every bound the previous commit added. `git ls-files
--others` reports the whole tree of anything not yet ignored, so a fresh clone
before `node_modules` / `target` / `.venv` reach `.gitignore` answers with tens
of thousands of paths — read through the buffering helper, retained without a
cap, ignored by `oversized()`, and rendered one non-virtualized row each. That
reaches the overlay without going through the diff at all, which is why the diff
budget never saw it. It is now streamed through `git_lines`, capped at
`MAX_UNTRACKED`, counted toward the oversized threshold, and rendered at most
`MAX_RENDERED_FILES` rows with a "… and N more" tail. The reported count stays
the true total via `untracked_total` — same split the diff side already makes
between what is retained and what is counted, because a count that shrank with
the budget would read as files having disappeared.

The overlay's expand state was an inversion set — "files flipped away from their
default" — which was correct while the default was per-file and stable. The
repo-wide `collapse_all` moves the default for every file at once, so any
refresh crossing the oversized threshold inverted every explicit choice
simultaneously: the two files the user had opened snapped shut and the rest
sprang open. It now stores absolute intent (`HashMap<String, bool>`), answered
before the default is even computed, so nothing about the snapshot can reach it.
Covered by a test that asserts an explicitly opened and an explicitly closed
file both survive a transition in either direction while an untouched file
follows the default.

The Changes panel dropped freshly landed snapshots. `install_diff_snapshot` only
wrote `right_panel.diff` when the panel was the one waiting, so a probe the
overlay started was discarded even when the panel sat on that exact repo — the
overlay rendered the new snapshot while the panel kept the old one, same window,
same repo. The wait (`diff_pending`) and the data (`diff_cwd`) are now claimed
separately: with probes deduped per cwd there is at most one in flight, so there
is no out-of-order overwrite to guard against.

The oversized banner reported `retained_lines()` as "diff lines", which after
the budget fires is what was kept, not what changed — it read "20000 diff lines"
directly under a header showing the exact +90000/-0. It now states
loaded-of-total and names which cap ate the difference, and lists each axis that
tripped the threshold so a big untracked list never reads as a claim that the
diff is big.

And the Changes panel deep-copied every untracked path String on every frame, on
the UI thread, for two `len()`/`is_empty()` reads — the same cost class the
`Arc` switch removed from the probe path.

995 tests pass, fmt clean, no new clippy warnings. The app was not built,
launched, or driven; visual acceptance is the owner's.

Refs #239.
2026-07-29 16:10:46 +08:00

tty7

tty7

A terminal workbench: shells, sessions, SSH, coding agents.

Pure Rust · GPU rendering on Zed's gpui · VT core from Alacritty


CI Version License Discord

English · 简体中文

Why

  • Fast — ~2× the throughput of Alacritty, Ghostty, or Kitty (benchmarks)
  • Sessions persist — quit or reboot; your shells keep running, no tmux
  • Editor-grade input — completion, syntax highlighting, history search built in; zero config for zsh, bash, fish, PowerShell
  • Agent-aware — recognizes Claude Code & co. in a pane: status, notifications, session resume

Install

Native builds for each platform on Releases:

macOS …-macos-arm64.dmg · …-x86_64.dmg drag into Applications
Windows …-setup.exe · portable ….zip
Linux …-x86_64.AppImage chmod +x and run — x11/wayland libs bundled

What's inside

Input ghost suggestions from history · explained tab completion · syntax highlighting · multi-line editing · click places the caret · ⌃ R fuzzy history
Window tabs & splits · ⌘ P palette · ⌘ F scrollback search · nine themes · IME
Coding agents per-pane agent detection (~17 CLIs): status dot, notifications, branch + diff, resume after reboot, tray icon that signals "needs your input"
SSH native russh stack: profiles with keychain secrets, SFTP panel, port forwarding, jump hosts

Details for every row: docs/features.md. Keybindings: ⌘ , opens Settings — browse and remap everything, tmux preset included (full list).

Benchmarks

Same machine, same day, same 155×40 grid — Apple M1 Pro, macOS 26.3.1, five-run averages (2026-07-04):

tty7 Alacritty Ghostty Kitty
Plaintext IO — 11 MB cat (lower = better) 95 ms 239 ms 179 ms 185 ms
DOOM-fire frame rate (higher = better) 888 fps 485 fps 552 fps 617 fps
Cold-launch memory 116 MB¹ 105 MB 128 MB 130 MB

¹ GUI 105 MB + the persistent daemon 11 MB.

Methodology and one-command reproduction: scripts/bench/.


S
Description
A terminal workbench in pure Rust: shells, persistent sessions, SSH, coding agents. GPU-rendered on Zed's gpui, VT core from Alacritty.
Readme Apache-2.0
34 MiB
Languages
Rust 99.1%
Shell 0.5%
PowerShell 0.2%
Inno Setup 0.1%