feat(app): derive dynamic tab title from foreground process and cwd#22
Conversation
When the shell has not set an OSC 0/2 title (and the user has not renamed the tab), fall back to a live title built from the focused pane's foreground process and OSC 7 cwd tail (`cargo — noa`), matching the sidebar card naming via the shared cwd_tail helper. A plain interactive shell collapses to just the cwd tail; with no information the title stays "Noa". User overrides and explicit OSC titles keep their existing priority. Foreground-process changes now request a window redraw when the session delta is applied so the title tracks them even with the sidebar closed; cwd and OSC title changes already ride the io thread's Redraw path.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9299927804
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let focused_process = self | ||
| .windows | ||
| .get(&window_id) | ||
| .map(|state| state.focused_pane) | ||
| .and_then(|pane_id| { | ||
| self.session_store | ||
| .get(&Self::session_card_id(window_id, pane_id)) | ||
| .and_then(|card| card.process.clone()) |
There was a problem hiding this comment.
Keep process title independent of session cards
When a pane has not produced any PTY output yet, such as noa -e sleep 60 or another silent explicit command, no SessionDelta::Upsert has created a SessionCard; SessionStore::apply drops SessionDelta::Process updates for missing cards, and the process poller will not resend the same name. Because the new fallback reads the foreground process only through self.session_store.get(...), the title remains Noa/cwd instead of showing the foreground process until output occurs or the process changes. Store the latest process independently of the card, or let process deltas create/update the card before relying on it for the title.
Useful? React with 👍 / 👎.
Summary
The tab/window title never changed from its initial state unless the shell explicitly set one. When there is no OSC 0/2 title and no user rename, the title now falls back to a live label built from the focused pane's foreground process and OSC 7 cwd tail (
cargo — noa); a plain interactive shell collapses to just the cwd tail, and with no information it stays "Noa". User renames and explicit OSC titles keep their existing priority, and the format mirrors the sidebar card naming via the sharedcwd_tailhelper.Changes
resolved_tab_titlenow takes(override, shell_title, cwd, process)and owns the fallback chain; newdynamic_tab_title/is_plain_shellhelpers ingeometry.rsterm.cwd(already under the terminal lock) and the session-store process name into the title resolutionSessionDelta::Processapplication requests a window redraw so process changes update the title even with the sidebar closed (cwd/OSC-title changes already ride the io thread's Redraw)cwd_tailpromoted topub(crate)and shared with the sidebar to avoid duplicationTest plan
cargo test -p noa-app --offline→ 950 passed, 0 failed (new unit tests: cwd-only / process-only / both / plain-shell collapse incl.-zshand/bin/bash/ no info → "Noa" / OSC title wins / override wins)cargo clippy --workspace --offlineclean (no new warnings),cargo fmt --checkcleancargo run -p noa, startvim— title readsvim — <dir>;cdupdates the tail; OSC 2 and tab rename still take priority