Skip to content

Commit

Permalink
Show warning when deleting files with unsaved changes
Browse files Browse the repository at this point in the history
  • Loading branch information
rtfeldman committed Nov 4, 2024
1 parent 49a0a11 commit b46634c
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 8 deletions.
15 changes: 15 additions & 0 deletions crates/project/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3959,6 +3959,21 @@ impl Project {
self.worktree_store.read(cx).worktree_metadata_protos(cx)
}

/// Iterator of all open buffers that have unsaved changes
pub fn dirty_buffers<'a>(
&'a self,
cx: &'a AppContext,
) -> impl Iterator<Item = ProjectPath> + 'a {
self.buffer_store.read(cx).buffers().filter_map(|buf| {
let buf = buf.read(cx);
if buf.is_dirty() {
buf.project_path(cx)
} else {
None
}
})
}

fn set_worktrees_from_proto(
&mut self,
worktrees: Vec<proto::WorktreeMetadata>,
Expand Down
34 changes: 26 additions & 8 deletions crates/project_panel/src/project_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1102,13 +1102,17 @@ impl ProjectPanel {
}
let project = self.project.read(cx);
let items_to_delete = self.marked_entries();

let mut dirty_buffers = 0;
let file_paths = items_to_delete
.into_iter()
.filter_map(|selection| {
let project_path = project.path_for_entry(selection.entry_id, cx)?;
dirty_buffers +=
project.dirty_buffers(cx).any(|path| path == project_path) as usize;
Some((
selection.entry_id,
project
.path_for_entry(selection.entry_id, cx)?
project_path
.path
.file_name()?
.to_string_lossy()
Expand All @@ -1121,11 +1125,17 @@ impl ProjectPanel {
}
let answer = if !skip_prompt {
let operation = if trash { "Trash" } else { "Delete" };
let prompt = match file_paths.first() {
Some((_, path)) if file_paths.len() == 1 => {
let unsaved_warning = if dirty_buffers > 0 {
"\n\nIt has unsaved changes, which will be lost."
} else {
""
};

let prompt =
if let Some((_, path)) = file_paths.first().filter(|_| file_paths.len() == 1) {
format!("{operation} {path}?")
} else {
format!("{operation} {path}?{unsaved_warning}")
}
_ => {
const CUTOFF_POINT: usize = 10;
let names = if file_paths.len() > CUTOFF_POINT {
let truncated_path_counts = file_paths.len() - CUTOFF_POINT;
Expand All @@ -1144,14 +1154,22 @@ impl ProjectPanel {
} else {
file_paths.iter().map(|(_, path)| path.clone()).collect()
};
let unsaved_warning = if dirty_buffers == 0 {
String::new()
} else if dirty_buffers == 1 {
"\n\n1 of these has unsaved changes, which will be lost.".to_string()
} else {
format!("\n\n{dirty_buffers} of these have unsaved changes, which will be lost.")
};

format!(
"Do you want to {} the following {} files?\n{}",
"Do you want to {} the following {} files?\n{}{unsaved_warning}",
operation.to_lowercase(),
file_paths.len(),
names.join("\n")
)
};
}
};
Some(cx.prompt(PromptLevel::Info, &prompt, None, &[operation, "Cancel"]))
} else {
None
Expand Down

0 comments on commit b46634c

Please sign in to comment.