diff --git a/CHANGELOG.md b/CHANGELOG.md index 59039984..c1745700 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -163,6 +163,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 involved something in the Wayland presentation path, were not reproducible on macOS and are not claimed to be confirmed. (#243) +- **Return no longer confirms the file tree's delete prompt** — it was the only + destructive prompt in tty7 with the destructive action first, and on macOS + (NSAlert) and Windows (TaskDialog) the first button is the Return-key + default, so pressing Return deleted — recursive folder deletion included. The + buttons now put the safe option first, matching every other destructive + prompt, with Escape still cancelling. Linux uses gpui's click-only fallback + dialog, so the swap only reorders the buttons there. + +- **"Finder" is no longer named on Linux and Windows** — the file-tree context + menu and the SFTP job list's reveal tooltip hardcoded Finder-flavoured + labels on every platform; only the Info row's button was conditional. All + three sites now share that one conditional, so the action reads "Reveal in + Finder" on macOS and "Open Folder" everywhere else. On macOS the SFTP + tooltip's "Show in Finder" becomes "Reveal in Finder" too, retiring a third + name for the same action. + +- **Grok Build turns up in settings search** — the agent renders a Settings → + Agents row but had no search-index entry, so searching could never surface + it. The other five agent entries had drifted from what their rows actually + say ("Claude Code hooks" for a row titled "Claude Code"), as had "Option + acts as Meta" from the rendered "Option (⌥) acts as Meta"; the index titles + now match the rows, the mechanism words (hooks / plugin / extension) stay + behind as search keywords, and a test derives the Agents index from the + agent list so a future agent can't ship unsearchable. + ## [26.7.6] - 2026-07-28 ### Added diff --git a/src/ui/file_tree.rs b/src/ui/file_tree.rs index 3c01a1a7..09475437 100644 --- a/src/ui/file_tree.rs +++ b/src/ui/file_tree.rs @@ -1602,11 +1602,14 @@ impl Tty7App { PromptLevel::Warning, &format!("Delete \"{name}\"?"), Some(detail), - &["Delete", "Cancel"], + // Safe option first: the leading button is the Return-key default on + // macOS (NSAlert) and Windows (TaskDialog); "Cancel" is what gpui maps + // to the Escape key. + &["Cancel", "Delete"], cx, ); cx.spawn_in(window, async move |app, cx| { - let Ok(0) = answer.await else { return }; + let Ok(1) = answer.await else { return }; let _ = app.update_in(cx, |app, window, cx| { let Some(host) = app.active_host(cx) else { return; @@ -2055,12 +2058,14 @@ impl Tty7App { cx.write_to_clipboard(gpui::ClipboardItem::new_string(p.display().to_string())); } })) - .item(PopupMenuItem::new("Reveal in Finder").on_click({ - let p = p.clone(); - move |_, _window, cx| { - cx.reveal_path(&p); - } - })); + .item( + PopupMenuItem::new(crate::ui::right_panel::reveal_label()).on_click({ + let p = p.clone(); + move |_, _window, cx| { + cx.reveal_path(&p); + } + }), + ); menu = menu.separator().item(dotfiles_menu_item(show_hidden, app)); diff --git a/src/ui/right_panel.rs b/src/ui/right_panel.rs index 88e10be5..9df59afe 100644 --- a/src/ui/right_panel.rs +++ b/src/ui/right_panel.rs @@ -706,11 +706,7 @@ impl Tty7App { /// clipboard. An "open in $EDITOR" button would need a picker, a stored /// choice and a settings page to change it; that's a feature, not a row. fn cwd_actions(&self, cwd: PathBuf, cx: &mut Context) -> AnyElement { - let reveal_label = if cfg!(target_os = "macos") { - "Reveal in Finder" - } else { - "Open Folder" - }; + let reveal_label = reveal_label(); h_flex() .gap(px(2.)) .px(px(tile_trailing_inset_sm())) @@ -1477,6 +1473,18 @@ pub(crate) fn info_chip( .into_any_element() } +/// The label for revealing a path in the OS file manager: only macOS has a +/// "Finder", so everywhere else it's the generic "Open Folder". Shared by the +/// Info row, the file-tree context menu and the SFTP job list so the action +/// carries one name per platform. +pub fn reveal_label() -> &'static str { + if cfg!(target_os = "macos") { + "Reveal in Finder" + } else { + "Open Folder" + } +} + /// The one-word status the Info row shows next to the agent's name. fn agent_status_label(status: crate::core::cli_agent::AgentStatus) -> &'static str { use crate::core::cli_agent::AgentStatus::*; diff --git a/src/ui/settings.rs b/src/ui/settings.rs index f7bd3c7e..cd494207 100644 --- a/src/ui/settings.rs +++ b/src/ui/settings.rs @@ -270,8 +270,8 @@ fn settings_search_entries() -> &'static [SearchEntry] { }, SearchEntry { section: Input, - title: "Option acts as Meta", - keywords: "alt keyboard modifier escape macos option meta", + title: "Option (⌥) acts as Meta", + keywords: "alt keyboard modifier escape macos option meta option acts as meta", }, SearchEntry { section: Input, @@ -311,30 +311,38 @@ fn settings_search_entries() -> &'static [SearchEntry] { keywords: "ssh tunnel local remote dynamic socks forward rule", }, // ── Agents ────────────────────────────────────────────────────────── + // Titles mirror `HookAgent::display_name()`, which is what each row is + // rendered with; the mechanism word (hooks/plugin/extension) lives in + // `keywords`. Pinned by `agent_rows_are_in_the_search_index`. SearchEntry { section: Agents, - title: "Claude Code hooks", - keywords: "agent integration install uninstall status rich session working waiting tab bar sidebar badge claude", + title: "Claude Code", + keywords: "agent integration hooks install uninstall status rich session working waiting tab bar sidebar badge claude", }, SearchEntry { section: Agents, - title: "Codex hooks", - keywords: "agent integration install openai codex", + title: "Codex", + keywords: "agent integration hooks install openai codex", }, SearchEntry { section: Agents, - title: "Copilot CLI hooks", - keywords: "agent integration install github copilot", + title: "Copilot CLI", + keywords: "agent integration hooks install github copilot", }, SearchEntry { section: Agents, - title: "OpenCode plugin", - keywords: "agent integration install opencode", + title: "OpenCode", + keywords: "agent integration plugin install opencode", }, SearchEntry { section: Agents, - title: "Pi extension", - keywords: "agent integration install pi", + title: "Pi", + keywords: "agent integration extension install pi", + }, + SearchEntry { + section: Agents, + title: "Grok Build", + keywords: "agent integration hooks install xai grok build", }, // ── Window & Tabs ─────────────────────────────────────────────────── SearchEntry { @@ -5625,6 +5633,7 @@ mod tests { "Tab completion", "History search", "Dim inactive panes", + "Option (⌥) acts as Meta", ] { assert!( settings_search_entries().iter().any(|e| e.title == title), @@ -5633,6 +5642,25 @@ mod tests { } } + /// The Agents rows are titled by [`HookAgent::display_name`], so the index + /// is derived rather than pinned: every hook-capable agent must have an + /// Agents-section entry under exactly that name. Adding an agent to + /// `HookAgent::ALL` without indexing it — how Grok Build became + /// unsearchable — fails here, as does renaming an agent without moving its + /// index entry. + #[test] + fn agent_rows_are_in_the_search_index() { + for agent in crate::core::agent_hooks::HookAgent::ALL { + assert!( + settings_search_entries().iter().any( + |e| e.section == SettingsSection::Agents && e.title == agent.display_name() + ), + "no Agents index entry titled {:?}", + agent.display_name() + ); + } + } + #[test] fn humanize_action_splits_on_capitals() { assert_eq!(humanize_action("NewTab"), "New Tab"); diff --git a/src/ui/sftp.rs b/src/ui/sftp.rs index c639456c..85b6ee02 100644 --- a/src/ui/sftp.rs +++ b/src/ui/sftp.rs @@ -1816,7 +1816,7 @@ impl Tty7App { .icon(IconName::FolderOpen) .xsmall() .ghost() - .tooltip("Show in Finder") + .tooltip(crate::ui::right_panel::reveal_label()) .on_click(cx.listener(move |this, _, _w, cx| { this.sftp_reveal_download(local.clone(), cx) })),