tty7 had exactly one window, so `main` opened it inline and every app-wide
duty — tray, menus, the quit hook — lived in `Tty7App`'s constructor. This
splits those apart: a *workspace* is the persistent identity (tabs, splits,
cwds, name) and a *window* is a transient view onto exactly one of them.
- `ui::windows` — the app-level window registry and the single place that
opens a window. Exactly one window per workspace is enforced there: the
daemon gives each pane a single subscriber, so a second window on the same
panes would silently steal the first's output. `open` focuses the existing
window instead. New windows cascade so one never lands on top of another.
- `WorkspaceStore` owns session.json, so windows never race each other as
writers. Closing a window *detaches* — panes keep running in the daemon
and the entry stays for the picker; `StopWorkspace` kills the sessions and
keeps the layout; `DeleteWorkspace` also forgets it.
- Window menu lists every workspace with a monogram badge and a liveness
dot, ⌘1–9 for the first nine. Same list in the palette; closed ones also
appear in a home-page picker with a coarse relative age.
- Sidebar collapse and right-panel visibility move onto `Tty7App`, so
toggling one window's chrome leaves the others alone; the config value
becomes what a new window starts with. Panel *width* stays shared — a
width is a preference, not a view state.
- Tray, menus, and the quit hook now walk the registry rather than
belonging to a single window.
Protocol goes to v2: `RemoteKind::Wsl` is a new enum variant, which is not
the additive change it looks like — the enums carry no `#[serde(other)]`, so
a v1 peer fails the whole decode and drops the pane's connection. The
handshake now catches that skew and offers a restart.
Opening a `.rs` file in the code panel silently spawned rust-analyzer,
which then indexed the whole workspace — hundreds of megabytes of RAM and
a busy core — with no setting to turn it off. A terminal emulator should
not do that to its user on a click, and rather than add a flag to disable
something nobody asked for, the integration goes.
Removed: the JSON-RPC client and reader thread (`ui::lsp`), the per-server
registry, the completion / hover / definition providers installed on the
buffer, document sync (didOpen/didChange/didSave/didClose), diagnostics,
Go to Definition (F12), Find References (⇧F12) and its drawer, and the
status bar's server indicator. With them go the `lsp-types`, `ropey` and
`url` dependencies — all three were used only by this code (they remain in
the lock file as transitive deps of gpui-component and gpui, which is
expected).
Kept, and deliberately so:
- **Syntax highlighting**, which is tree-sitter, not LSP: gpui-component's
`tree-sitter-languages` feature, `InputState::code_editor(language)` and
`language_for_path` are all untouched. It is static, in-process, and
costs nothing beyond parsing the open buffer.
- ⌘S save, dirty tracking, the external-change watcher and its conflict
banner, markdown preview, soft wrap, and open-from-the-file-tree.
The module header now records *why* there is no language server, so the
next person to reach for one finds the reasoning instead of a gap.
Net −975 lines.
The branch had `gpui-component` pointed at a sibling checkout by absolute
path, which is why every CI job failed at manifest load. Point it back at
the fork's `tty7` branch (now carrying the custom-button label-color fix
the chrome tiles depend on) with the `tree-sitter-languages` feature, and
re-lock.
Review fixes on top:
- **Changes tab churned.** `right_panel_invalidate` dropped the cached
diff on every `GitStatusCache` notification — including unrelated
repos' — so the list blanked to "Loading…" and spawned a fresh
`git diff` several times a second while a pane produced output.
Replaced by `right_panel_refresh_changes`, which compares branch and
totals first and re-probes in place, mirroring the diff overlay.
- **Changes tab could wedge on "Loading…".** A probe dropped because the
cwd changed mid-flight left `diff_cwd` set and `diff` empty, and the
render path only spawns when the cwd *changes* — so nothing re-probed.
Spawn when nothing is cached and nothing is in flight.
- **Find references blocked the UI thread.** `cx.spawn_in` runs on the
main thread; the up-to-200 `read_to_string`s for the row previews now
run on the background executor, as the comment already claimed.
- **LSP frames could be lost or reordered at startup.** `send` checked
`ready` outside the `queued` lock, so a frame could park behind a
handshake that had just finished and never go out. `ready` now flips
under that lock in `mark_ready_and_flush`.
- `MarkScanner`'s ESC-in-payload branch bypassed the payload cap, so a
stream of bare ESCs inside an unterminated OSC grew the buffer without
bound.
- The file tree's search frontier used `Vec::remove(0)`; a wide tree made
that quadratic. `VecDeque`.
- `procs()` documented a pane check it didn't make; it takes the pane id
and makes it.
- Four doc comments had been orphaned onto newly inserted functions
(`pty`, `smooth_scroll`, `foreground_agent`, `file_expanded`).
Add a right-hand detail column showing what the active pane is, not what
it prints: session facts plus its process tree and listening ports
(daemon-side procinfo, pull-based via QueryProcs), the working-tree diff,
and the file tree. Tab row lives in the title bar, body in right_panel.
Also record OSC 133 command marks client-side so the panel's Outline can
list a pane's commands and scroll back to one, keyed on row text since
absolute scrollback indices drift once history fills.
The panel's open files, tree roots/expansion/selection, and visibility now
live on Tab.code (same contract as Tab.diff_overlay): only the active tab's
panel renders, switching tabs shows that tab's own panel (or none), and
closing the tab drops its state. Hiding via Esc keeps the tab's open files.
Shared infrastructure stays app-global: directory-listing and gitignore
caches (path-keyed, tab-agnostic), the LSP registry, and single watchers
over the union of every tab's roots / open files. External-change reloads
and diagnostics now fan out to every buffer of the path across tabs.
The file tree + editor now render as one overlay covering the terminal
(settings/diff-overlay style): toggling never resizes the terminal (no PTY
resize/reflow) and the editor gets the full body width. The tab sidebar stays
visible and switching tabs re-roots the tree; focus follows the panel.
- Merge ToggleFileTree/ToggleEditor into one ToggleCodePanel action (cmd-shift-e,
Esc closes, palette "Code Panel").
- Add the one on-screen entry point: a title-bar tile next to the overflow
menu, lit while the overlay is up (present in both tab-bar modes).
- Drop the editor width divider and the file tree's standalone open flag.