Skip to content

Commit 245c589

Browse files
committed
Fix file URI encoding
1 parent 1f5a4f0 commit 245c589

4 files changed

Lines changed: 58 additions & 12 deletions

File tree

anycode-backend/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

anycode-backend/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ rust-embed = { version = "8", features = ["include-exclude"] }
3737
mime_guess = "2"
3838
dirs = "6"
3939
lsp-types = "0.97"
40+
url = "2.5"
4041
similar = "2"
4142
agent-client-protocol = { version = "0.11", features = ["unstable_session_close", "unstable_session_resume", "unstable_session_usage"] }
4243
agent-client-protocol-schema = { version = "0.12", features = ["unstable_session_usage"] }

anycode-backend/src/utils.rs

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -283,20 +283,64 @@ pub fn path_to_uri(path: &str) -> anyhow::Result<Uri> {
283283
.canonicalize()
284284
.unwrap_or_else(|_| path_obj.to_path_buf());
285285

286-
let path_str = canonical_path.to_string_lossy().replace('\\', "/");
287-
288-
let uri_str = if path_str.len() > 2 && &path_str[1..2] == ":" {
289-
// Windows path like C:/... -> file:///C:/...
290-
format!("file:///{}", path_str)
291-
} else if path_str.starts_with('/') {
292-
// Unix absolute path /path -> file:///path
293-
format!("file://{}", path_str)
286+
let absolute_path = if canonical_path.is_absolute() {
287+
canonical_path
294288
} else {
295-
// Relative path -> file:///path
296-
format!("file:///{}", path_str)
289+
std::env::current_dir()?.join(canonical_path)
297290
};
298291

299-
uri_str
292+
let url = url::Url::from_file_path(&absolute_path)
293+
.map_err(|_| anyhow::anyhow!("Failed to convert path to Url: {:?}", absolute_path))?;
294+
295+
url.as_str()
300296
.parse()
301297
.map_err(|e| anyhow::anyhow!("Failed to parse URI: {}", e))
302298
}
299+
300+
#[cfg(test)]
301+
mod tests {
302+
use super::*;
303+
304+
#[test]
305+
fn test_path_to_uri_with_spaces() {
306+
let path = if cfg!(target_os = "windows") {
307+
r"C:\Users\max\dev\anycode\code copy.ts"
308+
} else {
309+
"/Users/max/dev/anycode/code copy.ts"
310+
};
311+
let uri = path_to_uri(path).unwrap();
312+
assert!(uri.to_string().contains("code%20copy.ts"));
313+
}
314+
315+
#[test]
316+
fn test_path_to_uri_relative() {
317+
let path = "src/utils.rs";
318+
let uri = path_to_uri(path).unwrap();
319+
assert!(uri.to_string().starts_with("file:///"));
320+
assert!(uri.to_string().ends_with("src/utils.rs"));
321+
}
322+
323+
#[test]
324+
fn test_path_to_uri_cyrillic() {
325+
let path = if cfg!(target_os = "windows") {
326+
r"C:\Users\max\dev\anycode\привет мир.ts"
327+
} else {
328+
"/Users/max/dev/anycode/привет мир.ts"
329+
};
330+
let uri = path_to_uri(path).unwrap();
331+
assert!(uri.to_string().contains("%20"));
332+
// "привет" in UTF-8 percent-encoded is %D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82
333+
assert!(uri.to_string().contains("%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82"));
334+
}
335+
336+
#[test]
337+
fn test_path_to_uri_special_chars() {
338+
let path = if cfg!(target_os = "windows") {
339+
r"C:\Users\max\dev\anycode\file#name?.ts"
340+
} else {
341+
"/Users/max/dev/anycode/file#name?.ts"
342+
};
343+
let uri = path_to_uri(path).unwrap();
344+
assert!(uri.to_string().contains("file%23name%3F.ts"));
345+
}
346+
}

anycode/components/toolbar/Toolbar.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@
240240
height: 14px;
241241
background-color: var(--theme-border, rgba(255, 255, 255, 0.15));
242242
margin-left: 8px;
243-
margin-right: 2px;
243+
margin-right: 8px;
244244
align-self: center;
245245
flex-shrink: 0;
246246
}

0 commit comments

Comments
 (0)