From c5249db1898a63f7a9dbdc5351779c8b27234348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9lanie=20Chauvel?= Date: Mon, 18 Sep 2023 17:32:52 +0200 Subject: [PATCH] fix(hyperlink): respect spec on Windows and make it for with Konsole --- Cargo.lock | 23 +++-------------------- Cargo.toml | 3 +-- src/output/file_name.rs | 28 ++++++++++++---------------- 3 files changed, 16 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c16d39a5..12cf5028 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -361,7 +361,6 @@ dependencies = [ "ansiterm", "chrono", "criterion", - "gethostname", "git2", "glob", "lazy_static", @@ -371,6 +370,7 @@ dependencies = [ "natord", "num_cpus", "number_prefix", + "percent-encoding", "phf", "proc-mounts", "scoped_threadpool", @@ -379,7 +379,6 @@ dependencies = [ "timeago", "trycmd", "unicode-width", - "urlencoding", "uzers", "zoneinfo_compiled", ] @@ -412,16 +411,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "gethostname" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" -dependencies = [ - "libc", - "windows-targets", -] - [[package]] name = "git2" version = "0.18.0" @@ -753,9 +742,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "phf" @@ -1258,12 +1247,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf8parse" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index eb1dc4c9..742b5ad7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,7 +72,6 @@ name = "eza" [dependencies] ansiterm = "0.12.2" -gethostname = "0.4.3" chrono = { version = "0.4.31", default-features = false, features = ["clock"] } glob = "0.3" lazy_static = "1.3" @@ -82,13 +81,13 @@ log = "0.4" natord = "1.0" num_cpus = "1.16" number_prefix = "0.4" +percent-encoding = "2.3.0" phf = { version = "0.11.2", features = ["macros"] } scoped_threadpool = "0.1" term_grid = "0.1" terminal_size = "0.2.6" timeago = { version = "0.4.2", default-features = false } unicode-width = "0.1" -urlencoding = "2.1.3" zoneinfo_compiled = "0.5.1" [dependencies.git2] diff --git a/src/output/file_name.rs b/src/output/file_name.rs index c98598f3..8b4ce791 100644 --- a/src/output/file_name.rs +++ b/src/output/file_name.rs @@ -10,9 +10,6 @@ use crate::output::escape; use crate::output::icons::{icon_for_file, iconify_style}; use crate::output::render::FiletypeColours; -const HYPERLINK_START: &str = "\x1B]8;;"; -const HYPERLINK_END: &str = "\x1B\x5C"; - /// Basically a file name factory. #[derive(Debug, Copy, Clone)] pub struct Options { @@ -345,26 +342,25 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { /// So in that situation, those characters will be escaped and highlighted in /// a different colour. fn escaped_file_name<'unused>(&self) -> Vec> { + use percent_encoding::{CONTROLS, utf8_percent_encode}; + + const HYPERLINK_START: &str = "\x1B]8;;"; + const HYPERLINK_END: &str = "\x1B\x5C"; + let file_style = self.style(); let mut bits = Vec::new(); let mut display_hyperlink = false; if self.options.embed_hyperlinks == EmbedHyperlinks::On { if let Some(abs_path) = self.file.absolute_path().and_then(|p| p.as_os_str().to_str()) { - #[cfg(not(target_os = "windows"))] - bits.insert(0, ANSIString::from(format!( - "{}file://{}{}{}", - HYPERLINK_START, - gethostname::gethostname().to_str().unwrap_or(""), - urlencoding::encode(abs_path).replace("%2F", "/"), - HYPERLINK_END, - ))); + let abs_path = utf8_percent_encode(abs_path, CONTROLS).to_string(); + + // On Windows, `std::fs::canonicalize` adds the Win32 File prefix, which we need to remove #[cfg(target_os = "windows")] - bits.insert(0, ANSIString::from(format!( - "{}file://{}{}", - HYPERLINK_START, - abs_path.replace("\\\\?\\", ""), - HYPERLINK_END, + let abs_path = abs_path.strip_prefix("\\\\?\\").unwrap_or(&abs_path); + + bits.push(ANSIString::from(format!( + "{HYPERLINK_START}file://{abs_path}{HYPERLINK_END}" ))); display_hyperlink = true;