project panel: Persist full filename when renaming auto-folded entries (#19728)

This fixes a debug-only panic when processing filenames. The underflow
that happens in Preview/Stable shouldn't cause any issues (other than
maybe unmarking an entry in the project panel).

/cc @notpeter

Closes #ISSUE

Release Notes:

- N/A
This commit is contained in:
Piotr Osiewicz 2024-10-25 13:47:01 +02:00 committed by GitHub
parent 0173479d18
commit 5769065f27
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -94,12 +94,18 @@ pub struct ProjectPanel {
struct EditState { struct EditState {
worktree_id: WorktreeId, worktree_id: WorktreeId,
entry_id: ProjectEntryId, entry_id: ProjectEntryId,
is_new_entry: bool, leaf_entry_id: Option<ProjectEntryId>,
is_dir: bool, is_dir: bool,
depth: usize, depth: usize,
processing_filename: Option<String>, processing_filename: Option<String>,
} }
impl EditState {
fn is_new_entry(&self) -> bool {
self.leaf_entry_id.is_none()
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum ClipboardEntry { enum ClipboardEntry {
Copied(BTreeSet<SelectedEntry>), Copied(BTreeSet<SelectedEntry>),
@ -824,10 +830,10 @@ impl ProjectPanel {
cx.focus(&self.focus_handle); cx.focus(&self.focus_handle);
let worktree_id = edit_state.worktree_id; let worktree_id = edit_state.worktree_id;
let is_new_entry = edit_state.is_new_entry; let is_new_entry = edit_state.is_new_entry();
let filename = self.filename_editor.read(cx).text(cx); let filename = self.filename_editor.read(cx).text(cx);
edit_state.is_dir = edit_state.is_dir edit_state.is_dir = edit_state.is_dir
|| (edit_state.is_new_entry && filename.ends_with(std::path::MAIN_SEPARATOR)); || (edit_state.is_new_entry() && filename.ends_with(std::path::MAIN_SEPARATOR));
let is_dir = edit_state.is_dir; let is_dir = edit_state.is_dir;
let worktree = self.project.read(cx).worktree_for_id(worktree_id, cx)?; let worktree = self.project.read(cx).worktree_for_id(worktree_id, cx)?;
let entry = worktree.read(cx).entry_for_id(edit_state.entry_id)?.clone(); let entry = worktree.read(cx).entry_for_id(edit_state.entry_id)?.clone();
@ -858,7 +864,6 @@ impl ProjectPanel {
if path_already_exists(new_path.as_path()) { if path_already_exists(new_path.as_path()) {
return None; return None;
} }
edited_entry_id = entry.id; edited_entry_id = entry.id;
edit_task = self.project.update(cx, |project, cx| { edit_task = self.project.update(cx, |project, cx| {
project.rename_entry(entry.id, new_path.as_path(), cx) project.rename_entry(entry.id, new_path.as_path(), cx)
@ -1013,7 +1018,7 @@ impl ProjectPanel {
self.edit_state = Some(EditState { self.edit_state = Some(EditState {
worktree_id, worktree_id,
entry_id: directory_id, entry_id: directory_id,
is_new_entry: true, leaf_entry_id: None,
is_dir, is_dir,
processing_filename: None, processing_filename: None,
depth: 0, depth: 0,
@ -1047,12 +1052,12 @@ impl ProjectPanel {
}) = self.selection }) = self.selection
{ {
if let Some(worktree) = self.project.read(cx).worktree_for_id(worktree_id, cx) { if let Some(worktree) = self.project.read(cx).worktree_for_id(worktree_id, cx) {
let entry_id = self.unflatten_entry_id(entry_id); let sub_entry_id = self.unflatten_entry_id(entry_id);
if let Some(entry) = worktree.read(cx).entry_for_id(entry_id) { if let Some(entry) = worktree.read(cx).entry_for_id(sub_entry_id) {
self.edit_state = Some(EditState { self.edit_state = Some(EditState {
worktree_id, worktree_id,
entry_id, entry_id: sub_entry_id,
is_new_entry: false, leaf_entry_id: Some(entry_id),
is_dir: entry.is_dir(), is_dir: entry.is_dir(),
processing_filename: None, processing_filename: None,
depth: 0, depth: 0,
@ -1835,7 +1840,7 @@ impl ProjectPanel {
let mut new_entry_parent_id = None; let mut new_entry_parent_id = None;
let mut new_entry_kind = EntryKind::Dir; let mut new_entry_kind = EntryKind::Dir;
if let Some(edit_state) = &self.edit_state { if let Some(edit_state) = &self.edit_state {
if edit_state.worktree_id == worktree_id && edit_state.is_new_entry { if edit_state.worktree_id == worktree_id && edit_state.is_new_entry() {
new_entry_parent_id = Some(edit_state.entry_id); new_entry_parent_id = Some(edit_state.entry_id);
new_entry_kind = if edit_state.is_dir { new_entry_kind = if edit_state.is_dir {
EntryKind::Dir EntryKind::Dir
@ -2351,7 +2356,7 @@ impl ProjectPanel {
}; };
if let Some(edit_state) = &self.edit_state { if let Some(edit_state) = &self.edit_state {
let is_edited_entry = if edit_state.is_new_entry { let is_edited_entry = if edit_state.is_new_entry() {
entry.id == NEW_ENTRY_ID entry.id == NEW_ENTRY_ID
} else { } else {
entry.id == edit_state.entry_id entry.id == edit_state.entry_id
@ -2369,10 +2374,41 @@ impl ProjectPanel {
if is_edited_entry { if is_edited_entry {
if let Some(processing_filename) = &edit_state.processing_filename { if let Some(processing_filename) = &edit_state.processing_filename {
details.is_processing = true; details.is_processing = true;
details.filename.clear(); if let Some(ancestors) = edit_state
details.filename.push_str(processing_filename); .leaf_entry_id
.and_then(|entry| self.ancestors.get(&entry))
{
let position = ancestors.ancestors.iter().position(|entry_id| *entry_id == edit_state.entry_id).expect("Edited sub-entry should be an ancestor of selected leaf entry") + 1;
let all_components = ancestors.ancestors.len();
let prefix_components = all_components - position;
let suffix_components = position.checked_sub(1);
let mut previous_components =
Path::new(&details.filename).components();
let mut new_path = previous_components
.by_ref()
.take(prefix_components)
.collect::<PathBuf>();
if let Some(last_component) =
Path::new(processing_filename).components().last()
{
new_path.push(last_component);
previous_components.next();
}
if let Some(_) = suffix_components {
new_path.push(previous_components);
}
if let Some(str) = new_path.to_str() {
details.filename.clear();
details.filename.push_str(str);
}
} else {
details.filename.clear();
details.filename.push_str(processing_filename);
}
} else { } else {
if edit_state.is_new_entry { if edit_state.is_new_entry() {
details.filename.clear(); details.filename.clear();
} }
details.is_editing = true; details.is_editing = true;
@ -2571,6 +2607,7 @@ impl ProjectPanel {
comp_str comp_str
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let components_len = components.len(); let components_len = components.len();
let active_index = components_len let active_index = components_len
- 1 - 1