diff --git a/CHANGELOG.md b/CHANGELOG.md index 725ea4c7..05231afb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -535,17 +535,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Double-click word/smart-select is unaffected; only link click and hover bridge hard wraps. (by @ayamir in #258) -- **A sidebar title no longer shows "zsh" over your repo name** — pane - titles were allowed to fall back to the foreground process name before - falling back to cwd/repo, but an idle terminal's foreground process is - just the shell itself, so nearly every idle workspace displayed as "zsh" - or "bash" instead of the more useful cwd-derived name — the opposite of - what that fallback chain was for. Bare interactive-shell names (`zsh`, - `bash`, `fish`, `pwsh`, `cmd`, and similar, matched case- and - extension-insensitively) are now skipped when picking a title, so the - process-name fallback only fires for something actually distinctive - (`nvim`, a coding agent) and an idle shell falls all the way through to - the cwd/repo name as intended. (by @ayamir in #285) +- **A workspace title stays tied to the workspace** — foreground process and + agent names no longer replace the workspace title in the sidebar or its + switcher button. An explicit workspace name wins; otherwise the title is + derived from the workspace's repo/cwd, with `Untitled` as the final fallback. - **Fullwidth CJK punctuation no longer overlaps, and prompt-mark scanning is faster** — wide glyphs are now shaped independently instead of being diff --git a/crates/tty7-core/src/core/shells.rs b/crates/tty7-core/src/core/shells.rs index c84bc9cc..f91ab190 100644 --- a/crates/tty7-core/src/core/shells.rs +++ b/crates/tty7-core/src/core/shells.rs @@ -27,37 +27,6 @@ pub struct ShellInventory { pub default_name: String, } -/// Common interactive-shell process names, lowercase and without a -/// platform-specific extension. Anything that lands in here is what a pane -/// looks like at an idle prompt — not distinctive enough to stand in for a -/// pane's cwd/repo name when picking a display title. -const BARE_SHELL_NAMES: &[&str] = &[ - "sh", - "bash", - "zsh", - "fish", - "dash", - "ksh", - "tcsh", - "csh", - "nu", - "elvish", - "xonsh", - "pwsh", - "powershell", - "cmd", - "wsl", -]; - -/// True when `name` is a bare interactive-shell process name (e.g. the -/// foreground process of an idle terminal), so callers that want a -/// *distinctive* title should skip it and fall back to something else. -pub fn is_bare_shell_name(name: &str) -> bool { - let lower = name.trim().to_ascii_lowercase(); - let lower = lower.strip_suffix(".exe").unwrap_or(&lower); - BARE_SHELL_NAMES.contains(&lower) -} - pub fn inventory() -> ShellInventory { let configured = crate::core::config::shell_command(); ShellInventory { @@ -440,16 +409,4 @@ mod tests { assert!(!default_shell_name(None).is_empty()); assert!(!default_shell_name(Some(" ")).is_empty()); } - - #[test] - fn bare_shell_names_are_recognized_case_and_extension_insensitively() { - assert!(is_bare_shell_name("zsh")); - assert!(is_bare_shell_name("bash")); - assert!(is_bare_shell_name("PowerShell")); - assert!(is_bare_shell_name("pwsh.exe")); - assert!(is_bare_shell_name("CMD.EXE")); - assert!(!is_bare_shell_name("nvim")); - assert!(!is_bare_shell_name("claude")); - assert!(!is_bare_shell_name("")); - } } diff --git a/src/ui/machine_mirror.rs b/src/ui/machine_mirror.rs index 012fc902..4de95a64 100644 --- a/src/ui/machine_mirror.rs +++ b/src/ui/machine_mirror.rs @@ -257,9 +257,6 @@ pub fn display_name_of(ws: &Workspace, panes: &[PaneRecord]) -> String { if let Some(name) = ws.name.as_deref().map(str::trim).filter(|n| !n.is_empty()) { return name.to_string(); } - if let Some(title) = pane_title_of(ws, panes) { - return title.to_string(); - } subject_path_of(ws, panes) .and_then(|path| { std::path::Path::new(&path) @@ -270,15 +267,6 @@ pub fn display_name_of(ws: &Workspace, panes: &[PaneRecord]) -> String { .unwrap_or_else(|| "Untitled".to_string()) } -fn pane_title_of<'a>(ws: &Workspace, panes: &'a [PaneRecord]) -> Option<&'a str> { - ws.tabs - .iter() - .flat_map(|t| t.root.pane_ids()) - .filter_map(|id| panes.iter().find(|p| p.id == id)) - .map(|p| p.title.trim()) - .find(|title| !title.is_empty() && !tty7_core::core::shells::is_bare_shell_name(title)) -} - pub fn subject_path_of(ws: &Workspace, panes: &[PaneRecord]) -> Option { let mut counts: Vec<(&str, usize)> = Vec::new(); for group in ws.tabs.iter().filter_map(|t| t.sidebar_group.as_deref()) { @@ -521,20 +509,17 @@ mod tests { assert_eq!(display_name_of(&ws, &panes), "scratch"); panes[0].title = "nvim".into(); - assert_eq!(display_name_of(&ws, &panes), "nvim"); + assert_eq!( + display_name_of(&ws, &panes), + "scratch", + "a pane's process title must not rename its workspace" + ); ws.tabs[0].sidebar_group = Some("/repo/tty7".into()); - assert_eq!( - display_name_of(&ws, &panes), - "nvim", - "a live process name is more distinctive than the cwd group" - ); - - panes[0].title = "zsh".into(); assert_eq!( display_name_of(&ws, &panes), "tty7", - "an idle shell prompt is not distinctive — cwd/repo name should win" + "the repo group wins over the raw cwd" ); ws.name = Some(" Release prep ".into()); diff --git a/src/ui/tab_strip.rs b/src/ui/tab_strip.rs index 4326ec97..e473c129 100644 --- a/src/ui/tab_strip.rs +++ b/src/ui/tab_strip.rs @@ -232,11 +232,7 @@ impl Tty7App { } crate::terminal::pane_liveness::sweep(cx); - let current = self - .tabs - .get(self.active) - .and_then(|tab| workspace_osc_title(tab, cx).or_else(|| workspace_agent_title(tab, cx))) - .or_else(|| crate::ui::machine_mirror::display_name_for(cx, self.workspace)) + let current = crate::ui::machine_mirror::display_name_for(cx, self.workspace) .unwrap_or_else(|| "tty7".to_string()); let monogram: String = current .chars() @@ -1086,19 +1082,6 @@ impl Tty7App { } } -fn workspace_osc_title(tab: &Tab, cx: &App) -> Option { - let title = tab.leaf_title(None, cx); - let title = title.trim(); - if title.is_empty() || title == "tty7" || title.starts_with("tty7 — ") { - return None; - } - Some(title.to_string()) -} - -fn workspace_agent_title(tab: &Tab, cx: &App) -> Option { - tab.agent(cx).map(|agent| agent.display_name().to_string()) -} - #[cfg(test)] mod tests { use super::*;