URL-encode the image paths in Markdown so that images with filenames (#41788)

aohanhongzhi created

Closes https://github.com/zed-industries/zed/issues/41786

Release Notes:

- markdown preview: Fixed an issue where path urls would not be parsed
correctly when containing URL-encoded characters

<img width="1680" height="1126"
alt="569415cb-b3e8-4ad6-b31c-a1898ec32085"
src="https://github.com/user-attachments/assets/7de8a892-ff01-4e00-a28c-1c5e9206ce3a"
/>

Change summary

Cargo.lock                                       |  1 +
crates/markdown_preview/Cargo.toml               |  1 +
crates/markdown_preview/src/markdown_elements.rs | 10 ++++++++--
3 files changed, 10 insertions(+), 2 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -9680,6 +9680,7 @@ dependencies = [
  "settings",
  "theme",
  "ui",
+ "urlencoding",
  "util",
  "workspace",
 ]

crates/markdown_preview/Cargo.toml 🔗

@@ -31,6 +31,7 @@ pulldown-cmark.workspace = true
 settings.workspace = true
 theme.workspace = true
 ui.workspace = true
+urlencoding.workspace = true
 util.workspace = true
 workspace.workspace = true
 

crates/markdown_preview/src/markdown_elements.rs 🔗

@@ -4,6 +4,7 @@ use gpui::{
 };
 use language::HighlightId;
 use std::{fmt::Display, ops::Range, path::PathBuf};
+use urlencoding;
 
 #[derive(Debug)]
 #[cfg_attr(test, derive(PartialEq))]
@@ -278,7 +279,12 @@ impl Link {
             return Some(Link::Web { url: text });
         }
 
-        let path = PathBuf::from(&text);
+        // URL decode the text to handle spaces and other special characters
+        let decoded_text = urlencoding::decode(&text)
+            .map(|s| s.into_owned())
+            .unwrap_or(text);
+
+        let path = PathBuf::from(&decoded_text);
         if path.is_absolute() && path.exists() {
             return Some(Link::Path {
                 display_path: path.clone(),
@@ -288,7 +294,7 @@ impl Link {
 
         if let Some(file_location_directory) = file_location_directory {
             let display_path = path;
-            let path = file_location_directory.join(text);
+            let path = file_location_directory.join(decoded_text);
             if path.exists() {
                 return Some(Link::Path { display_path, path });
             }