Cargo.lock 🔗
@@ -37,6 +37,7 @@ dependencies = [
"terminal",
"ui",
"url",
+ "urlencoding",
"util",
"uuid",
"watch",
Daiki Takagi created
## Summary
This fixes a minor bug I found #44981
- Fix percent-encoded filenames appearing in agent mentions after
message submission.
- Decode file:// paths in MentionUri::parse using the existing
urlencoding crate (already used elsewhere in the codebase).
- Add tests for non-ASCII file URIs.
## Screenshots
<img width="409" height="116" alt="image"
src="https://github.com/user-attachments/assets/32ef033b-6232-47c5-80c7-d5247d5dae88"
/>
Cargo.lock | 1 +
crates/acp_thread/Cargo.toml | 1 +
crates/acp_thread/src/mention.rs | 19 ++++++++++++++++++-
3 files changed, 20 insertions(+), 1 deletion(-)
@@ -37,6 +37,7 @@ dependencies = [
"terminal",
"ui",
"url",
+ "urlencoding",
"util",
"uuid",
"watch",
@@ -46,6 +46,7 @@ url.workspace = true
util.workspace = true
uuid.workspace = true
watch.workspace = true
+urlencoding.workspace = true
[dev-dependencies]
env_logger.workspace = true
@@ -4,12 +4,14 @@ use file_icons::FileIcons;
use prompt_store::{PromptId, UserPromptId};
use serde::{Deserialize, Serialize};
use std::{
+ borrow::Cow,
fmt,
ops::RangeInclusive,
path::{Path, PathBuf},
};
use ui::{App, IconName, SharedString};
use url::Url;
+use urlencoding::decode;
use util::paths::PathStyle;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
@@ -74,11 +76,13 @@ impl MentionUri {
let path = url.path();
match url.scheme() {
"file" => {
- let path = if path_style.is_windows() {
+ let normalized = if path_style.is_windows() {
path.trim_start_matches("/")
} else {
path
};
+ let decoded = decode(normalized).unwrap_or(Cow::Borrowed(normalized));
+ let path = decoded.as_ref();
if let Some(fragment) = url.fragment() {
let line_range = parse_line_range(fragment)?;
@@ -406,6 +410,19 @@ mod tests {
assert_eq!(parsed.to_uri().to_string(), selection_uri);
}
+ #[test]
+ fn test_parse_file_uri_with_non_ascii() {
+ let file_uri = uri!("file:///path/to/%E6%97%A5%E6%9C%AC%E8%AA%9E.txt");
+ let parsed = MentionUri::parse(file_uri, PathStyle::local()).unwrap();
+ match &parsed {
+ MentionUri::File { abs_path } => {
+ assert_eq!(abs_path, Path::new(path!("/path/to/日本語.txt")));
+ }
+ _ => panic!("Expected File variant"),
+ }
+ assert_eq!(parsed.to_uri().to_string(), file_uri);
+ }
+
#[test]
fn test_parse_untitled_selection_uri() {
let selection_uri = uri!("zed:///agent/untitled-buffer#L1:10");