From e5d86ae5c5f5a21afdcaaa06f05ba4b254cc22df Mon Sep 17 00:00:00 2001 From: alkinun Date: Wed, 6 May 2026 19:03:20 +0300 Subject: [PATCH] Escape markdown special chars in file deletion confirmation dialog (#55697) ## Summary Filenames containing md syntax (e.g. `__somefile__`, `*somefile*`) were being rendered as markdown text in the file deletion confirmation dialog. Fixes #55651 ## Changes Wrapped file paths with `MarkdownEscaped` in the single and multi-file deletion confirmation dialogs in `project_panel.rs`, so special md chars like `_`, `*`, and `[` are escaped before being rendered. ## Testing Created a file named `__somefile__` and tried to delete it, the name now displays literally in the confirmation dialog instead of being rendered as bold text: img Also added `test_delete_prompt_escapes_markdown_in_file_name` in `project_panel_tests.rs` that verifies filenames with markdown special characters render literally in the confirmation dialog. Release Notes: - Fixed file names containing markdown special characters (e.g. `__somefile__`) being rendered as formatted text in the file deletion confirmation dialog. --- crates/project_panel/src/project_panel.rs | 16 ++++++--- .../project_panel/src/project_panel_tests.rs | 36 +++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 1ae5f4248450758d34074977a5af331545bd5426..4f9bc801d63ec565bac2e50f2ee2eaf7fefbfaa3 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -66,7 +66,9 @@ use ui::{ StickyCandidate, Tooltip, WithScrollbar, prelude::*, v_flex, }; use util::{ - ResultExt, TakeUntilExt, TryFutureExt, maybe, + ResultExt, TakeUntilExt, TryFutureExt, + markdown::MarkdownInlineCode, + maybe, paths::{PathStyle, compare_paths}, rel_path::{RelPath, RelPathBuf}, }; @@ -2357,7 +2359,10 @@ impl ProjectPanel { "" }; - format!("{message_start} {path}?{unsaved_warning}") + format!( + "{message_start} {}?{unsaved_warning}", + MarkdownInlineCode(path) + ) } _ => { const CUTOFF_POINT: usize = 10; @@ -2365,7 +2370,7 @@ impl ProjectPanel { let truncated_path_counts = file_paths.len() - CUTOFF_POINT; let mut paths = file_paths .iter() - .map(|(_, _, path)| path.clone()) + .map(|(_, _, path)| MarkdownInlineCode(path).to_string()) .take(CUTOFF_POINT) .collect::>(); paths.truncate(CUTOFF_POINT); @@ -2376,7 +2381,10 @@ impl ProjectPanel { } paths } else { - file_paths.iter().map(|(_, _, path)| path.clone()).collect() + file_paths + .iter() + .map(|(_, _, path)| MarkdownInlineCode(path).to_string()) + .collect() }; let unsaved_warning = if dirty_buffers == 0 { String::new() diff --git a/crates/project_panel/src/project_panel_tests.rs b/crates/project_panel/src/project_panel_tests.rs index 4897b57937d6c66f95776f19922dddbda5a202a5..6722a300dd84932214e6bd7f78df6fe2b877780b 100644 --- a/crates/project_panel/src/project_panel_tests.rs +++ b/crates/project_panel/src/project_panel_tests.rs @@ -10339,3 +10339,39 @@ impl Render for TestProjectItemView { Empty } } + +#[gpui::test] +async fn test_delete_prompt_escapes_markdown_in_file_name(cx: &mut gpui::TestAppContext) { + init_test(cx); + + let fs = FakeFs::new(cx.executor()); + fs.insert_tree( + "/root", + json!({ + "__somefile__": "", + }), + ) + .await; + + let project = Project::test(fs.clone(), ["/root".as_ref()], cx).await; + let window = cx.add_window(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx)); + let workspace = window + .read_with(cx, |mw, _| mw.workspace().clone()) + .unwrap(); + let cx = &mut VisualTestContext::from_window(window.into(), cx); + let panel = workspace.update_in(cx, ProjectPanel::new); + cx.run_until_parked(); + + select_path(&panel, "root/__somefile__", cx); + panel.update_in(cx, |panel, window, cx| { + panel.delete(&Delete { skip_prompt: false }, window, cx) + }); + let (message, _detail) = cx + .pending_prompt() + .expect("delete should show a confirmation prompt"); + + assert_eq!( + message, + "Are you sure you want to permanently delete `__somefile__`?" + ); +}