summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/uu/ls/src/ls.rs18
-rw-r--r--tests/by-util/test_ls.rs32
2 files changed, 49 insertions, 1 deletions
diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs
index a5fe3d624..3cf848ae2 100644
--- a/src/uu/ls/src/ls.rs
+++ b/src/uu/ls/src/ls.rs
@@ -3019,7 +3019,23 @@ fn display_file_name(
let absolute_path = fs::canonicalize(&path.p_buf).unwrap_or_default();
let absolute_path = absolute_path.to_string_lossy();
- // TODO encode path
+ #[cfg(not(target_os = "windows"))]
+ let unencoded_chars = "_-.:~/";
+ #[cfg(target_os = "windows")]
+ let unencoded_chars = "_-.:~/\\";
+
+ // percentage encoding of path
+ let absolute_path: String = absolute_path
+ .chars()
+ .map(|c| {
+ if c.is_alphanumeric() || unencoded_chars.contains(c) {
+ c.to_string()
+ } else {
+ format!("%{:02x}", c as u8)
+ }
+ })
+ .collect();
+
// \x1b = ESC, \x07 = BEL
name = format!("\x1b]8;;file://{hostname}{absolute_path}\x07{name}\x1b]8;;\x07");
}
diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs
index c9f43028c..76cb0d216 100644
--- a/tests/by-util/test_ls.rs
+++ b/tests/by-util/test_ls.rs
@@ -3904,6 +3904,38 @@ fn test_ls_hyperlink() {
.stdout_is(format!("{file}\n"));
}
+// spell-checker: disable
+#[test]
+fn test_ls_hyperlink_encode_link() {
+ let (at, mut ucmd) = at_and_ucmd!();
+
+ #[cfg(not(target_os = "windows"))]
+ {
+ at.touch("back\\slash");
+ at.touch("ques?tion");
+ }
+ at.touch("encoded%3Fquestion");
+ at.touch("sp ace");
+
+ let result = ucmd.arg("--hyperlink").succeeds();
+ #[cfg(not(target_os = "windows"))]
+ {
+ assert!(result
+ .stdout_str()
+ .contains("back%5cslash\x07back\\slash\x1b]8;;\x07"));
+ assert!(result
+ .stdout_str()
+ .contains("ques%3ftion\x07ques?tion\x1b]8;;\x07"));
+ }
+ assert!(result
+ .stdout_str()
+ .contains("encoded%253Fquestion\x07encoded%3Fquestion\x1b]8;;\x07"));
+ assert!(result
+ .stdout_str()
+ .contains("sp%20ace\x07sp ace\x1b]8;;\x07"));
+}
+// spell-checker: enable
+
#[test]
fn test_ls_color_do_not_reset() {
let scene: TestScenario = TestScenario::new(util_name!());