Move verbatim path printing to uucore::Display

This commit is contained in:
Jan Verbeek 2021-08-29 20:09:58 +02:00
parent 4f891add5a
commit 0e1f8f7b34
2 changed files with 35 additions and 26 deletions

View file

@ -10,9 +10,10 @@ extern crate uucore;
use clap::{crate_version, App, Arg};
use std::env;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::io;
use std::path::PathBuf;
use uucore::display::println_verbatim;
use uucore::error::{FromIo, UResult};
static ABOUT: &str = "Display the full filename of the current working directory.";
@ -57,6 +58,7 @@ fn logical_path() -> io::Result<PathBuf> {
// POSIX: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pwd.html
#[cfg(not(windows))]
{
use std::path::Path;
fn looks_reasonable(path: &Path) -> bool {
// First, check if it's an absolute path.
if !path.has_root() {
@ -148,30 +150,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
.map(Into::into)
.unwrap_or(cwd);
print_path(&cwd).map_err_context(|| "failed to print current directory".to_owned())?;
Ok(())
}
fn print_path(path: &Path) -> io::Result<()> {
let stdout = io::stdout();
let mut stdout = stdout.lock();
// On Unix we print non-lossily.
#[cfg(unix)]
{
use std::os::unix::ffi::OsStrExt;
stdout.write_all(path.as_os_str().as_bytes())?;
stdout.write_all(b"\n")?;
}
// On other platforms we potentially mangle it.
// There might be some clever way to do it correctly on Windows, but
// invalid unicode in filenames is rare there.
#[cfg(not(unix))]
{
writeln!(stdout, "{}", path.display())?;
}
println_verbatim(&cwd).map_err_context(|| "failed to print current directory".to_owned())?;
Ok(())
}

View file

@ -5,6 +5,9 @@
/// will wrap quotes around the filename and add the necessary escapes to make
/// it copy/paste-able into a shell.
///
/// For writing raw paths to stdout when the output should not be quoted or escaped,
/// use `println_verbatim`. This will preserve invalid unicode.
///
/// # Examples
/// ```
/// use std::path::Path;
@ -13,6 +16,7 @@
/// let path = Path::new("foo/bar.baz");
///
/// println!("Found file {}", path.quote()); // Prints "Found file 'foo/bar.baz'"
/// println_verbatim(path)?; // Prints "foo/bar.baz"
/// # Ok::<(), std::io::Error>(())
/// ```
// spell-checker:ignore Fbar
@ -20,6 +24,7 @@ use std::ffi::OsStr;
#[cfg(any(unix, target_os = "wasi", windows))]
use std::fmt::Write as FmtWrite;
use std::fmt::{self, Display, Formatter};
use std::io::{self, Write as IoWrite};
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;
@ -268,6 +273,31 @@ fn from_utf8_iter(mut bytes: &[u8]) -> impl Iterator<Item = Result<&str, u8>> {
})
}
/// Print a path (or `OsStr`-like object) directly to stdout, with a trailing newline,
/// without losing any information if its encoding is invalid.
///
/// This function is appropriate for commands where printing paths is the point and the
/// output is likely to be captured, like `pwd` and `basename`. For informational output
/// use `Quotable::quote`.
///
/// FIXME: This is lossy on Windows. It could probably be implemented using some low-level
/// API that takes UTF-16, without going through io::Write. This is not a big priority
/// because broken filenames are much rarer on Windows than on Unix.
pub fn println_verbatim<S: AsRef<OsStr>>(text: S) -> io::Result<()> {
let stdout = io::stdout();
let mut stdout = stdout.lock();
#[cfg(any(unix, target_os = "wasi"))]
{
stdout.write_all(text.as_ref().as_bytes())?;
stdout.write_all(b"\n")?;
}
#[cfg(not(any(unix, target_os = "wasi")))]
{
writeln!(stdout, "{}", std::path::Path::new(text.as_ref()).display())?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;