From 9e02fee98d0a7e55cbcc77082097b677a5706879 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 26 Mar 2025 14:15:24 -0700 Subject: [PATCH] Align project panel and git panel deletion behavior (#27525) This change makes the git panel and project panel behave the same, on Linux and macOS, and adds prompts. Release Notes: - Changed the git panel to prompt before restoring a file. --- assets/keymaps/default-linux.json | 7 +++-- assets/keymaps/default-macos.json | 5 +++- crates/git/src/git.rs | 10 ++++++- crates/git_ui/src/git_panel.rs | 43 ++++++++++++++++++++++++++++--- crates/gpui/src/action.rs | 38 +++++++++++++++++++++++++-- 5 files changed, 93 insertions(+), 10 deletions(-) diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json index ee507aa45f..7c84cf035e 100644 --- a/assets/keymaps/default-linux.json +++ b/assets/keymaps/default-linux.json @@ -754,8 +754,11 @@ "escape": "git_panel::ToggleFocus", "ctrl-enter": "git::Commit", "alt-enter": "menu::SecondaryConfirm", - "shift-delete": "git::RestoreFile", - "ctrl-delete": "git::RestoreFile" + "delete": ["git::RestoreFile", { "skip_prompt": false }], + "backspace": ["git::RestoreFile", { "skip_prompt": false }], + "shift-delete": ["git::RestoreFile", { "skip_prompt": false }], + "ctrl-backspace": ["git::RestoreFile", { "skip_prompt": false }], + "ctrl-delete": ["git::RestoreFile", { "skip_prompt": false }] } }, { diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index 3cd69d1444..b6c04ca8b0 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -803,7 +803,10 @@ "shift-tab": "git_panel::FocusEditor", "escape": "git_panel::ToggleFocus", "cmd-enter": "git::Commit", - "cmd-backspace": "git::RestoreFile" + "backspace": ["git::RestoreFile", { "skip_prompt": false }], + "delete": ["git::RestoreFile", { "skip_prompt": false }], + "cmd-backspace": ["git::RestoreFile", { "skip_prompt": true }], + "cmd-delete": ["git::RestoreFile", { "skip_prompt": true }] } }, { diff --git a/crates/git/src/git.rs b/crates/git/src/git.rs index bc1605a87b..aeb075c1fe 100644 --- a/crates/git/src/git.rs +++ b/crates/git/src/git.rs @@ -11,7 +11,9 @@ use anyhow::{anyhow, Context as _, Result}; pub use git2 as libgit; use gpui::action_with_deprecated_aliases; use gpui::actions; +use gpui::impl_action_with_deprecated_aliases; pub use repository::WORK_DIRECTORY_REPO_PATH; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::ffi::OsStr; use std::fmt; @@ -54,7 +56,13 @@ actions!( ] ); -action_with_deprecated_aliases!(git, RestoreFile, ["editor::RevertFile"]); +#[derive(Clone, Debug, Default, PartialEq, Deserialize, JsonSchema)] +pub struct RestoreFile { + #[serde(default)] + pub skip_prompt: bool, +} + +impl_action_with_deprecated_aliases!(git, RestoreFile, ["editor::RevertFile"]); action_with_deprecated_aliases!(git, Restore, ["editor::RevertSelectedHunks"]); action_with_deprecated_aliases!(git, Blame, ["editor::ToggleGitBlame"]); diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 833fc3b5f3..ed326cf6fc 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -935,14 +935,49 @@ impl GitPanel { fn revert_selected( &mut self, - _: &git::RestoreFile, + action: &git::RestoreFile, window: &mut Window, cx: &mut Context, ) { maybe!({ + let skip_prompt = action.skip_prompt; let list_entry = self.entries.get(self.selected_entry?)?.clone(); - let entry = list_entry.status_entry()?; - self.revert_entry(&entry, window, cx); + let entry = list_entry.status_entry()?.to_owned(); + + let prompt = if skip_prompt { + Task::ready(Ok(0)) + } else { + let prompt = window.prompt( + PromptLevel::Warning, + &format!( + "Are you sure you want to restore {}?", + entry + .worktree_path + .file_name() + .unwrap_or(entry.worktree_path.as_os_str()) + .to_string_lossy() + ), + None, + &["Restore", "Cancel"], + cx, + ); + cx.background_spawn(prompt) + }; + + let this = cx.weak_entity(); + window + .spawn(cx, async move |cx| { + if prompt.await? != 0 { + return anyhow::Ok(()); + } + + this.update_in(cx, |this, window, cx| { + this.revert_entry(&entry, window, cx); + })?; + + Ok(()) + }) + .detach(); Some(()) }); } @@ -3460,7 +3495,7 @@ impl GitPanel { context_menu .context(self.focus_handle.clone()) .action(stage_title, ToggleStaged.boxed_clone()) - .action(restore_title, git::RestoreFile.boxed_clone()) + .action(restore_title, git::RestoreFile::default().boxed_clone()) .separator() .action("Open Diff", Confirm.boxed_clone()) .action("Open File", SecondaryConfirm.boxed_clone()) diff --git a/crates/gpui/src/action.rs b/crates/gpui/src/action.rs index 1cec009e85..9eab4a4ee1 100644 --- a/crates/gpui/src/action.rs +++ b/crates/gpui/src/action.rs @@ -375,16 +375,50 @@ macro_rules! action_with_deprecated_aliases { $name, $name, fn build( - _: gpui::private::serde_json::Value, + value: gpui::private::serde_json::Value, ) -> gpui::Result<::std::boxed::Box> { Ok(Box::new(Self)) }, + fn action_json_schema( generator: &mut gpui::private::schemars::gen::SchemaGenerator, ) -> Option { None - }, + + fn deprecated_aliases() -> &'static [&'static str] { + &[ + $($alias),* + ] + } + ); + + gpui::register_action!($name); + }; +} + +/// Defines and registers a unit struct that can be used as an action, with some deprecated aliases. +#[macro_export] +macro_rules! impl_action_with_deprecated_aliases { + ($namespace:path, $name:ident, [$($alias:literal),* $(,)?]) => { + gpui::__impl_action!( + $namespace, + $name, + $name, + fn build( + value: gpui::private::serde_json::Value, + ) -> gpui::Result<::std::boxed::Box> { + Ok(std::boxed::Box::new(gpui::private::serde_json::from_value::(value)?)) + }, + + fn action_json_schema( + generator: &mut gpui::private::schemars::gen::SchemaGenerator, + ) -> Option { + Some(::json_schema( + generator, + )) + }, + fn deprecated_aliases() -> &'static [&'static str] { &[ $($alias),*