refac: add support for Windows in EscapedPathDisplay

This commit is contained in:
Vinícius R. Miguel 2023-01-05 13:33:22 -03:00
parent 0deb18289a
commit 2caeb1004c
6 changed files with 40 additions and 25 deletions

View File

@ -16,7 +16,7 @@ use crate::{
error::FinalError, error::FinalError,
info, info,
list::FileInArchive, list::FileInArchive,
utils::{self, EscapedUtf8Display, FileVisibilityPolicy}, utils::{self, EscapedPathDisplay, FileVisibilityPolicy},
warning, warning,
}; };
@ -121,7 +121,7 @@ where
// spoken text for users using screen readers, braille displays // spoken text for users using screen readers, braille displays
// and so on // and so on
if !quiet { if !quiet {
info!(inaccessible, "Compressing '{}'.", EscapedUtf8Display::new(path)); info!(inaccessible, "Compressing '{}'.", EscapedPathDisplay::new(path));
} }
if path.is_dir() { if path.is_dir() {

View File

@ -22,7 +22,7 @@ use crate::{
list::FileInArchive, list::FileInArchive,
utils::{ utils::{
self, cd_into_same_dir_as, get_invalid_utf8_paths, pretty_format_list_of_paths, strip_cur_dir, self, cd_into_same_dir_as, get_invalid_utf8_paths, pretty_format_list_of_paths, strip_cur_dir,
EscapedUtf8Display, FileVisibilityPolicy, EscapedPathDisplay, FileVisibilityPolicy,
}, },
warning, warning,
}; };
@ -191,7 +191,7 @@ where
// spoken text for users using screen readers, braille displays // spoken text for users using screen readers, braille displays
// and so on // and so on
if !quiet { if !quiet {
info!(inaccessible, "Compressing '{}'.", EscapedUtf8Display::new(path)); info!(inaccessible, "Compressing '{}'.", EscapedPathDisplay::new(path));
} }
let metadata = match path.metadata() { let metadata = match path.metadata() {

View File

@ -18,7 +18,7 @@ use crate::{
info, info,
list::ListOptions, list::ListOptions,
utils::{ 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, FileVisibilityPolicy,
}, },
warning, Opts, QuestionAction, QuestionPolicy, Subcommand, warning, Opts, QuestionAction, QuestionPolicy, Subcommand,
@ -116,7 +116,7 @@ pub fn run(
let formats = extension::extensions_from_path(&output_path); let formats = extension::extensions_from_path(&output_path);
let first_format = formats.first().ok_or_else(|| { 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}'.")) FinalError::with_title(format!("Cannot compress to '{output_path}'."))
.detail("You shall supply the compression format") .detail("You shall supply the compression format")
.hint("Try adding supported extensions (see --help):") .hint("Try adding supported extensions (see --help):")
@ -139,7 +139,7 @@ pub fn run(
// To file.tar.bz.xz // To file.tar.bz.xz
let suggested_output_path = build_archive_file_suggestion(&output_path, ".tar") let suggested_output_path = build_archive_file_suggestion(&output_path, ".tar")
.expect("output path should contain a compression format"); .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 { let first_detail_message = if is_multiple_inputs {
"You are trying to compress multiple files." "You are trying to compress multiple files."
} else { } else {
@ -163,7 +163,7 @@ pub fn run(
if let Some(format) = formats.iter().skip(1).find(|format| format.is_archive()) { if let Some(format) = formats.iter().skip(1).find(|format| format.is_archive()) {
let error = FinalError::with_title(format!( let error = FinalError::with_title(format!(
"Cannot compress to '{}'.", "Cannot compress to '{}'.",
EscapedUtf8Display::new(&output_path) EscapedPathDisplay::new(&output_path)
)) ))
.detail(format!("Found the format '{}' in an incorrect position.", format)) .detail(format!("Found the format '{}' in an incorrect position.", format))
.detail(format!( .detail(format!(
@ -177,7 +177,7 @@ pub fn run(
.hint(format!( .hint(format!(
"Otherwise, remove the last '{}' from '{}'.", "Otherwise, remove the last '{}' from '{}'.",
format, format,
EscapedUtf8Display::new(&output_path) EscapedPathDisplay::new(&output_path)
)); ));
return Err(error.into()); return Err(error.into());
@ -213,7 +213,7 @@ pub fn run(
eprintln!("{red}FATAL ERROR:\n", red = *colors::RED); eprintln!("{red}FATAL ERROR:\n", red = *colors::RED);
eprintln!( eprintln!(
" Ouch failed to delete the file '{}'.", " Ouch failed to delete the file '{}'.",
EscapedUtf8Display::new(&output_path) EscapedPathDisplay::new(&output_path)
); );
eprintln!(" Please delete it manually."); eprintln!(" Please delete it manually.");
eprintln!(" This file is corrupted if compression didn't finished."); eprintln!(" This file is corrupted if compression didn't finished.");

View File

@ -1,27 +1,42 @@
use std::{borrow::Cow, fmt::Display, path::Path}; use std::{borrow::Cow, fmt::Display, path::Path};
use bstr::BStr;
use crate::CURRENT_DIRECTORY; use crate::CURRENT_DIRECTORY;
/// Converts invalid UTF-8 bytes to the Unicode replacement codepoint (<28>) in its Display implementation. /// Converts invalid UTF-8 bytes to the Unicode replacement codepoint (<28>) in its Display implementation.
pub struct EscapedUtf8Display<'a> { pub struct EscapedPathDisplay<'a> {
bstr: &'a BStr, path: &'a Path,
} }
impl<'a> EscapedUtf8Display<'a> { impl<'a> EscapedPathDisplay<'a> {
pub fn new(path: &'a Path) -> Self { pub fn new(path: &'a Path) -> Self {
use std::os::unix::prelude::OsStrExt; Self { path }
let bytes = path.as_os_str().as_bytes();
Self { bstr: BStr::new(bytes) }
} }
} }
impl Display for EscapedUtf8Display<'_> { #[cfg(unix)]
impl Display for EscapedPathDisplay<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.bstr) use std::os::unix::prelude::OsStrExt;
let bstr = bstr::BStr::new(self.path.as_os_str().as_bytes());
write!(f, "{}", bstr)
}
}
#[cfg(windows)]
impl Display for EscapedPathDisplay<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
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(())
} }
} }

View File

@ -9,7 +9,7 @@ use std::{
use fs_err as fs; use fs_err as fs;
use super::user_wants_to_overwrite; 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. /// 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)?; fs::create_dir_all(path)?;
// creating a directory is an important change to the file system we // creating a directory is an important change to the file system we
// should always inform the user about // should always inform the user about
info!(accessible, "directory {} created.", EscapedUtf8Display::new(path)); info!(accessible, "directory {} created.", EscapedPathDisplay::new(path));
} }
Ok(()) Ok(())
} }

View File

@ -10,7 +10,7 @@ mod fs;
mod question; mod question;
pub use file_visibility::FileVisibilityPolicy; 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::{ pub use fs::{
cd_into_same_dir_as, clear_path, create_dir_if_non_existent, is_symlink, remove_file_or_dir, try_infer_extension, cd_into_same_dir_as, clear_path, create_dir_if_non_existent, is_symlink, remove_file_or_dir, try_infer_extension,
}; };