project_panel: Do not allow creating empty file/dir or file/dir with only whitespaces (#28240)

- Do not allow creating empty file or empty directory.
- Do not allow creating file or directory with just whitespace.
- Show error only in case whitespace.

<img width="352" alt="image"
src="https://github.com/user-attachments/assets/f6040332-59a6-4d09-bf07-2b4b1b8b9e03"
/>

Release Notes:

- N/A
This commit is contained in:
Smit Barmase 2025-04-08 18:00:01 +05:30 committed by GitHub
parent c21fdd212b
commit 7ee9109ade
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 66 additions and 16 deletions

View file

@ -1150,9 +1150,7 @@ impl ProjectPanel {
Some(state) => state, Some(state) => state,
None => return, None => return,
}; };
let filename = self.filename_editor.read(cx).text(cx); let filename = self.filename_editor.read(cx).text(cx);
if !filename.is_empty() { if !filename.is_empty() {
if let Some(worktree) = self if let Some(worktree) = self
.project .project
@ -1160,6 +1158,7 @@ impl ProjectPanel {
.worktree_for_id(edit_state.worktree_id, cx) .worktree_for_id(edit_state.worktree_id, cx)
{ {
if let Some(entry) = worktree.read(cx).entry_for_id(edit_state.entry_id) { if let Some(entry) = worktree.read(cx).entry_for_id(edit_state.entry_id) {
let mut already_exists = false;
if edit_state.is_new_entry() { if edit_state.is_new_entry() {
let new_path = entry.path.join(filename.trim_start_matches('/')); let new_path = entry.path.join(filename.trim_start_matches('/'));
if worktree if worktree
@ -1167,12 +1166,7 @@ impl ProjectPanel {
.entry_for_path(new_path.as_path()) .entry_for_path(new_path.as_path())
.is_some() .is_some()
{ {
edit_state.validation_state = ValidationState::Error(format!( already_exists = true;
"File or directory '{}' already exists at location. Please choose a different name.",
filename
));
cx.notify();
return;
} }
} else { } else {
let new_path = if let Some(parent) = entry.path.clone().parent() { let new_path = if let Some(parent) = entry.path.clone().parent() {
@ -1183,18 +1177,28 @@ impl ProjectPanel {
if let Some(existing) = worktree.read(cx).entry_for_path(new_path.as_path()) if let Some(existing) = worktree.read(cx).entry_for_path(new_path.as_path())
{ {
if existing.id != entry.id { if existing.id != entry.id {
edit_state.validation_state = ValidationState::Error( already_exists = true;
"File or directory already exists".to_string(),
);
cx.notify();
return;
} }
} }
}; };
if already_exists {
edit_state.validation_state = ValidationState::Error(format!(
"File or directory '{}' already exists at location. Please choose a different name.",
filename
));
cx.notify();
return;
}
} }
} }
let trimmed_filename = filename.trim();
if filename.trim() != filename { if trimmed_filename.is_empty() {
edit_state.validation_state =
ValidationState::Error("File or directory name cannot be empty.".to_string());
cx.notify();
return;
}
if trimmed_filename != filename {
edit_state.validation_state = ValidationState::Warning( edit_state.validation_state = ValidationState::Warning(
"File or directory name contains leading or trailing whitespace.".to_string(), "File or directory name contains leading or trailing whitespace.".to_string(),
); );
@ -1202,7 +1206,6 @@ impl ProjectPanel {
return; return;
} }
} }
edit_state.validation_state = ValidationState::None; edit_state.validation_state = ValidationState::None;
cx.notify(); cx.notify();
} }
@ -1216,6 +1219,9 @@ impl ProjectPanel {
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);
if filename.trim().is_empty() {
return None;
}
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
let filename_indicates_dir = filename.ends_with("/"); let filename_indicates_dir = filename.ends_with("/");
// On Windows, path separator could be either `/` or `\`. // On Windows, path separator could be either `/` or `\`.

View file

@ -766,6 +766,50 @@ async fn test_editing_files(cx: &mut gpui::TestAppContext) {
" .dockerignore", " .dockerignore",
] ]
); );
// Test empty filename and filename with only whitespace
panel.update_in(cx, |panel, window, cx| panel.new_file(&NewFile, window, cx));
assert_eq!(
visible_entries_as_strings(&panel, 0..10, cx),
&[
"v root1",
" > .git",
" > a",
" v b",
" > 3",
" > 4",
" > new-dir",
" [EDITOR: ''] <== selected",
" a-different-filename.tar.gz",
" > C",
]
);
panel.update_in(cx, |panel, window, cx| {
panel.filename_editor.update(cx, |editor, cx| {
editor.set_text("", window, cx);
});
assert!(panel.confirm_edit(window, cx).is_none());
panel.filename_editor.update(cx, |editor, cx| {
editor.set_text(" ", window, cx);
});
assert!(panel.confirm_edit(window, cx).is_none());
panel.cancel(&menu::Cancel, window, cx)
});
assert_eq!(
visible_entries_as_strings(&panel, 0..10, cx),
&[
"v root1",
" > .git",
" > a",
" v b",
" > 3",
" > 4",
" > new-dir",
" a-different-filename.tar.gz <== selected",
" > C",
" .dockerignore",
]
);
} }
#[gpui::test(iterations = 10)] #[gpui::test(iterations = 10)]