git_ui: Escape markdown in discard confirmation dialog (#56197)

alkinun created

## Summary

Filenames containing markdown syntax (e.g. `__somefile__`, `*somefile*`)
were being rendered as formatted text in the git discard confirmation
dialog.

Follow-up to #55697 for the git discard confirmation path mentioned in
#53060.

## Changes

Wrapped the git discard confirmation filename with `MarkdownInlineCode`
in `git_panel.rs`, so special markdown characters like `_`, `*`, and `[`
render literally.

## Testing

Added `test_discard_prompt_escapes_markdown_in_file_name` in
`git_panel.rs` to verify filenames with markdown special characters
render literally in the discard confirmation dialog.

Run:
```bash
cargo test -p git_ui test_discard_prompt_escapes_markdown_in_file_name
```

Release Notes:

- Fixed file names containing markdown special characters (e.g.
`__somefile__`) being rendered as formatted text in the git discard
confirmation dialog.

Change summary

crates/git_ui/src/git_panel.rs | 78 +++++++++++++++++++++++++++++++++--
1 file changed, 73 insertions(+), 5 deletions(-)

Detailed changes

crates/git_ui/src/git_panel.rs 🔗

@@ -76,7 +76,7 @@ use ui::{
     prelude::*,
 };
 use util::paths::PathStyle;
-use util::{ResultExt, TryFutureExt, maybe, rel_path::RelPath};
+use util::{ResultExt, TryFutureExt, markdown::MarkdownInlineCode, maybe, rel_path::RelPath};
 use workspace::SERIALIZATION_THROTTLE_TIME;
 use workspace::{
     Workspace,
@@ -1421,10 +1421,12 @@ impl GitPanel {
                     PromptLevel::Warning,
                     &format!(
                         "Are you sure you want to discard changes to {}?",
-                        entry
-                            .repo_path
-                            .file_name()
-                            .unwrap_or(entry.repo_path.display(path_style).as_ref()),
+                        MarkdownInlineCode(
+                            entry
+                                .repo_path
+                                .file_name()
+                                .unwrap_or(entry.repo_path.display(path_style).as_ref())
+                        ),
                     ),
                     None,
                     &["Discard Changes", "Cancel"],
@@ -7097,6 +7099,72 @@ mod tests {
         );
     }
 
+    #[gpui::test]
+    async fn test_discard_prompt_escapes_markdown_in_file_name(cx: &mut TestAppContext) {
+        init_test(cx);
+        let fs = FakeFs::new(cx.background_executor.clone());
+        fs.insert_tree(
+            "/root",
+            json!({
+                "project": {
+                    ".git": {},
+                    "__somefile__": "modified\n",
+                },
+            }),
+        )
+        .await;
+
+        fs.set_status_for_repo(
+            Path::new(path!("/root/project/.git")),
+            &[("__somefile__", StatusCode::Modified.worktree())],
+        );
+
+        let project = Project::test(fs.clone(), [Path::new(path!("/root/project"))], cx).await;
+        let window_handle =
+            cx.add_window(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
+        let workspace = window_handle
+            .read_with(cx, |mw, _| mw.workspace().clone())
+            .unwrap();
+        let cx = &mut VisualTestContext::from_window(window_handle.into(), cx);
+
+        cx.read(|cx| {
+            project
+                .read(cx)
+                .worktrees(cx)
+                .next()
+                .unwrap()
+                .read(cx)
+                .as_local()
+                .unwrap()
+                .scan_complete()
+        })
+        .await;
+
+        cx.executor().run_until_parked();
+
+        let panel = workspace.update_in(cx, GitPanel::new);
+
+        let handle = cx.update_window_entity(&panel, |panel, _, _| {
+            std::mem::replace(&mut panel.update_visible_entries_task, Task::ready(()))
+        });
+        cx.executor().advance_clock(2 * UPDATE_DEBOUNCE);
+        handle.await;
+
+        panel.update_in(cx, |panel, window, cx| {
+            panel.selected_entry = Some(1);
+            panel.revert_selected(&git::RestoreFile::default(), window, cx);
+        });
+
+        let (message, _detail) = cx
+            .pending_prompt()
+            .expect("discard should show a confirmation prompt");
+
+        assert_eq!(
+            message,
+            "Are you sure you want to discard changes to `__somefile__`?"
+        );
+    }
+
     #[gpui::test]
     async fn test_bulk_staging(cx: &mut TestAppContext) {
         use GitListEntry::*;