Switch from delete file by default to trash file by default (#10875)

TODO:

- [x] Don't immediately seg fault
- [x] Implement for directories 
- [x] Add cmd-delete to remove files
- [ ] ~~Add setting for trash vs. delete~~ You can just use keybindings
to change the behavior.

fixes https://github.com/zed-industries/zed/issues/7228
fixes https://github.com/zed-industries/zed/issues/5094

Release Notes:

- Added a new `project_panel::Trash` action and changed the default
behavior for `backspace` and `delete` in the project panel to send a
file to the systems trash, instead of permanently deleting it
([#7228](https://github.com/zed-industries/zed/issues/7228),
[#5094](https://github.com/zed-industries/zed/issues/5094)). The
original behavior can be restored by adding the following section to
your keybindings:

```json5
[
// ...Other keybindings...
  {
    "context": "ProjectPanel",
    "bindings": {
        "backspace": "project_panel::Delete",
        "delete": "project_panel::Delete",
    }
  }
]
This commit is contained in:
Mikayla Maki 2024-04-26 17:43:50 -07:00 committed by GitHub
parent 5dbd23f6b0
commit d2569afe66
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 99 additions and 22 deletions

View file

@ -111,7 +111,13 @@ pub struct Delete {
pub skip_prompt: bool,
}
impl_actions!(project_panel, [Delete]);
#[derive(PartialEq, Clone, Default, Debug, Deserialize)]
pub struct Trash {
#[serde(default)]
pub skip_prompt: bool,
}
impl_actions!(project_panel, [Delete, Trash]);
actions!(
project_panel,
@ -880,16 +886,25 @@ impl ProjectPanel {
}
}
fn trash(&mut self, action: &Trash, cx: &mut ViewContext<Self>) {
self.remove(true, action.skip_prompt, cx);
}
fn delete(&mut self, action: &Delete, cx: &mut ViewContext<Self>) {
self.remove(false, action.skip_prompt, cx);
}
fn remove(&mut self, trash: bool, skip_prompt: bool, cx: &mut ViewContext<'_, ProjectPanel>) {
maybe!({
let Selection { entry_id, .. } = self.selection?;
let path = self.project.read(cx).path_for_entry(entry_id, cx)?.path;
let file_name = path.file_name()?;
let answer = (!action.skip_prompt).then(|| {
let operation = if trash { "Trash" } else { "Delete" };
let answer = (!skip_prompt).then(|| {
cx.prompt(
PromptLevel::Destructive,
&format!("Delete {file_name:?}?"),
&format!("{operation:?} {file_name:?}?",),
None,
&["Delete", "Cancel"],
)
@ -903,7 +918,7 @@ impl ProjectPanel {
}
this.update(&mut cx, |this, cx| {
this.project
.update(cx, |project, cx| project.delete_entry(entry_id, cx))
.update(cx, |project, cx| project.delete_entry(entry_id, trash, cx))
.ok_or_else(|| anyhow!("no such entry"))
})??
.await
@ -1808,6 +1823,7 @@ impl Render for ProjectPanel {
.on_action(cx.listener(Self::new_directory))
.on_action(cx.listener(Self::rename))
.on_action(cx.listener(Self::delete))
.on_action(cx.listener(Self::trash))
.on_action(cx.listener(Self::cut))
.on_action(cx.listener(Self::copy))
.on_action(cx.listener(Self::paste))