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.
This commit is contained in:
Mikayla Maki 2025-03-26 14:15:24 -07:00 committed by GitHub
parent 999ad77a59
commit 9e02fee98d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 93 additions and 10 deletions

View file

@ -754,8 +754,11 @@
"escape": "git_panel::ToggleFocus", "escape": "git_panel::ToggleFocus",
"ctrl-enter": "git::Commit", "ctrl-enter": "git::Commit",
"alt-enter": "menu::SecondaryConfirm", "alt-enter": "menu::SecondaryConfirm",
"shift-delete": "git::RestoreFile", "delete": ["git::RestoreFile", { "skip_prompt": false }],
"ctrl-delete": "git::RestoreFile" "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 }]
} }
}, },
{ {

View file

@ -803,7 +803,10 @@
"shift-tab": "git_panel::FocusEditor", "shift-tab": "git_panel::FocusEditor",
"escape": "git_panel::ToggleFocus", "escape": "git_panel::ToggleFocus",
"cmd-enter": "git::Commit", "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 }]
} }
}, },
{ {

View file

@ -11,7 +11,9 @@ use anyhow::{anyhow, Context as _, Result};
pub use git2 as libgit; pub use git2 as libgit;
use gpui::action_with_deprecated_aliases; use gpui::action_with_deprecated_aliases;
use gpui::actions; use gpui::actions;
use gpui::impl_action_with_deprecated_aliases;
pub use repository::WORK_DIRECTORY_REPO_PATH; pub use repository::WORK_DIRECTORY_REPO_PATH;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::ffi::OsStr; use std::ffi::OsStr;
use std::fmt; 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, Restore, ["editor::RevertSelectedHunks"]);
action_with_deprecated_aliases!(git, Blame, ["editor::ToggleGitBlame"]); action_with_deprecated_aliases!(git, Blame, ["editor::ToggleGitBlame"]);

View file

@ -935,14 +935,49 @@ impl GitPanel {
fn revert_selected( fn revert_selected(
&mut self, &mut self,
_: &git::RestoreFile, action: &git::RestoreFile,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
maybe!({ maybe!({
let skip_prompt = action.skip_prompt;
let list_entry = self.entries.get(self.selected_entry?)?.clone(); let list_entry = self.entries.get(self.selected_entry?)?.clone();
let entry = list_entry.status_entry()?; let entry = list_entry.status_entry()?.to_owned();
self.revert_entry(&entry, window, cx);
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(()) Some(())
}); });
} }
@ -3460,7 +3495,7 @@ impl GitPanel {
context_menu context_menu
.context(self.focus_handle.clone()) .context(self.focus_handle.clone())
.action(stage_title, ToggleStaged.boxed_clone()) .action(stage_title, ToggleStaged.boxed_clone())
.action(restore_title, git::RestoreFile.boxed_clone()) .action(restore_title, git::RestoreFile::default().boxed_clone())
.separator() .separator()
.action("Open Diff", Confirm.boxed_clone()) .action("Open Diff", Confirm.boxed_clone())
.action("Open File", SecondaryConfirm.boxed_clone()) .action("Open File", SecondaryConfirm.boxed_clone())

View file

@ -375,16 +375,50 @@ macro_rules! action_with_deprecated_aliases {
$name, $name,
$name, $name,
fn build( fn build(
_: gpui::private::serde_json::Value, value: gpui::private::serde_json::Value,
) -> gpui::Result<::std::boxed::Box<dyn gpui::Action>> { ) -> gpui::Result<::std::boxed::Box<dyn gpui::Action>> {
Ok(Box::new(Self)) Ok(Box::new(Self))
}, },
fn action_json_schema( fn action_json_schema(
generator: &mut gpui::private::schemars::gen::SchemaGenerator, generator: &mut gpui::private::schemars::gen::SchemaGenerator,
) -> Option<gpui::private::schemars::schema::Schema> { ) -> Option<gpui::private::schemars::schema::Schema> {
None 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<dyn gpui::Action>> {
Ok(std::boxed::Box::new(gpui::private::serde_json::from_value::<Self>(value)?))
},
fn action_json_schema(
generator: &mut gpui::private::schemars::gen::SchemaGenerator,
) -> Option<gpui::private::schemars::schema::Schema> {
Some(<Self as gpui::private::schemars::JsonSchema>::json_schema(
generator,
))
},
fn deprecated_aliases() -> &'static [&'static str] { fn deprecated_aliases() -> &'static [&'static str] {
&[ &[
$($alias),* $($alias),*