From 2caeb1004c0af6cc6ddd9e9076b58b2e1b0f3a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20R=2E=20Miguel?= Date: Thu, 5 Jan 2023 13:33:22 -0300 Subject: [PATCH] refac: add support for Windows in EscapedPathDisplay --- src/archive/tar.rs | 4 ++-- src/archive/zip.rs | 4 ++-- src/commands/mod.rs | 12 ++++++------ src/utils/formatting.rs | 33 ++++++++++++++++++++++++--------- src/utils/fs.rs | 4 ++-- src/utils/mod.rs | 2 +- 6 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/archive/tar.rs b/src/archive/tar.rs index 2adffd878..243ed8a1c 100644 --- a/src/archive/tar.rs +++ b/src/archive/tar.rs @@ -16,7 +16,7 @@ use crate::{ error::FinalError, info, list::FileInArchive, - utils::{self, EscapedUtf8Display, FileVisibilityPolicy}, + utils::{self, EscapedPathDisplay, FileVisibilityPolicy}, warning, }; @@ -121,7 +121,7 @@ where // spoken text for users using screen readers, braille displays // and so on if !quiet { - info!(inaccessible, "Compressing '{}'.", EscapedUtf8Display::new(path)); + info!(inaccessible, "Compressing '{}'.", EscapedPathDisplay::new(path)); } if path.is_dir() { diff --git a/src/archive/zip.rs b/src/archive/zip.rs index 64b94ad56..a29fa3e79 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -22,7 +22,7 @@ use crate::{ list::FileInArchive, utils::{ self, cd_into_same_dir_as, get_invalid_utf8_paths, pretty_format_list_of_paths, strip_cur_dir, - EscapedUtf8Display, FileVisibilityPolicy, + EscapedPathDisplay, FileVisibilityPolicy, }, warning, }; @@ -191,7 +191,7 @@ where // spoken text for users using screen readers, braille displays // and so on if !quiet { - info!(inaccessible, "Compressing '{}'.", EscapedUtf8Display::new(path)); + info!(inaccessible, "Compressing '{}'.", EscapedPathDisplay::new(path)); } let metadata = match path.metadata() { diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 79e31a434..42d983ce0 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -18,7 +18,7 @@ use crate::{ info, list::ListOptions, utils::{ - self, pretty_format_list_of_paths, to_utf, try_infer_extension, user_wants_to_continue, EscapedUtf8Display, + self, pretty_format_list_of_paths, to_utf, try_infer_extension, user_wants_to_continue, EscapedPathDisplay, FileVisibilityPolicy, }, warning, Opts, QuestionAction, QuestionPolicy, Subcommand, @@ -116,7 +116,7 @@ pub fn run( let formats = extension::extensions_from_path(&output_path); let first_format = formats.first().ok_or_else(|| { - let output_path = EscapedUtf8Display::new(&output_path); + let output_path = EscapedPathDisplay::new(&output_path); FinalError::with_title(format!("Cannot compress to '{output_path}'.")) .detail("You shall supply the compression format") .hint("Try adding supported extensions (see --help):") @@ -139,7 +139,7 @@ pub fn run( // To file.tar.bz.xz let suggested_output_path = build_archive_file_suggestion(&output_path, ".tar") .expect("output path should contain a compression format"); - let output_path = EscapedUtf8Display::new(&output_path); + let output_path = EscapedPathDisplay::new(&output_path); let first_detail_message = if is_multiple_inputs { "You are trying to compress multiple files." } else { @@ -163,7 +163,7 @@ pub fn run( if let Some(format) = formats.iter().skip(1).find(|format| format.is_archive()) { let error = FinalError::with_title(format!( "Cannot compress to '{}'.", - EscapedUtf8Display::new(&output_path) + EscapedPathDisplay::new(&output_path) )) .detail(format!("Found the format '{}' in an incorrect position.", format)) .detail(format!( @@ -177,7 +177,7 @@ pub fn run( .hint(format!( "Otherwise, remove the last '{}' from '{}'.", format, - EscapedUtf8Display::new(&output_path) + EscapedPathDisplay::new(&output_path) )); return Err(error.into()); @@ -213,7 +213,7 @@ pub fn run( eprintln!("{red}FATAL ERROR:\n", red = *colors::RED); eprintln!( " Ouch failed to delete the file '{}'.", - EscapedUtf8Display::new(&output_path) + EscapedPathDisplay::new(&output_path) ); eprintln!(" Please delete it manually."); eprintln!(" This file is corrupted if compression didn't finished."); diff --git a/src/utils/formatting.rs b/src/utils/formatting.rs index 2a6a13aac..040c96246 100644 --- a/src/utils/formatting.rs +++ b/src/utils/formatting.rs @@ -1,27 +1,42 @@ use std::{borrow::Cow, fmt::Display, path::Path}; -use bstr::BStr; - use crate::CURRENT_DIRECTORY; /// Converts invalid UTF-8 bytes to the Unicode replacement codepoint (�) in its Display implementation. -pub struct EscapedUtf8Display<'a> { - bstr: &'a BStr, +pub struct EscapedPathDisplay<'a> { + path: &'a Path, } -impl<'a> EscapedUtf8Display<'a> { +impl<'a> EscapedPathDisplay<'a> { pub fn new(path: &'a Path) -> Self { + Self { path } + } +} + +#[cfg(unix)] +impl Display for EscapedPathDisplay<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use std::os::unix::prelude::OsStrExt; - let bytes = path.as_os_str().as_bytes(); + let bstr = bstr::BStr::new(self.path.as_os_str().as_bytes()); - Self { bstr: BStr::new(bytes) } + write!(f, "{}", bstr) } } -impl Display for EscapedUtf8Display<'_> { +#[cfg(windows)] +impl Display for EscapedPathDisplay<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.bstr) + use std::{char, fmt::Write, os::windows::prelude::OsStrExt}; + + let utf16 = self.path.as_os_str().encode_wide(); + let chars = char::decode_utf16(utf16).map(|decoded| decoded.unwrap_or(char::REPLACEMENT_CHARACTER)); + + for char in chars { + f.write_char(char)?; + } + + Ok(()) } } diff --git a/src/utils/fs.rs b/src/utils/fs.rs index 21417019c..f6f48886d 100644 --- a/src/utils/fs.rs +++ b/src/utils/fs.rs @@ -9,7 +9,7 @@ use std::{ use fs_err as fs; use super::user_wants_to_overwrite; -use crate::{extension::Extension, info, utils::EscapedUtf8Display, QuestionPolicy}; +use crate::{extension::Extension, info, utils::EscapedPathDisplay, QuestionPolicy}; /// Remove `path` asking the user to overwrite if necessary. /// @@ -41,7 +41,7 @@ pub fn create_dir_if_non_existent(path: &Path) -> crate::Result<()> { fs::create_dir_all(path)?; // creating a directory is an important change to the file system we // should always inform the user about - info!(accessible, "directory {} created.", EscapedUtf8Display::new(path)); + info!(accessible, "directory {} created.", EscapedPathDisplay::new(path)); } Ok(()) } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 67646dbf0..a601287c7 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -10,7 +10,7 @@ mod fs; mod question; pub use file_visibility::FileVisibilityPolicy; -pub use formatting::{nice_directory_display, pretty_format_list_of_paths, strip_cur_dir, to_utf, EscapedUtf8Display}; +pub use formatting::{nice_directory_display, pretty_format_list_of_paths, strip_cur_dir, to_utf, EscapedPathDisplay}; pub use fs::{ cd_into_same_dir_as, clear_path, create_dir_if_non_existent, is_symlink, remove_file_or_dir, try_infer_extension, };