mirror of https://github.com/sharkdp/fd.git
Merge 9bf0306725
into 11069e284a
This commit is contained in:
commit
7eba1242f4
|
@ -630,6 +630,14 @@ pub struct Opts {
|
|||
#[arg(long, aliases(&["mount", "xdev"]), hide_short_help = true, long_help)]
|
||||
pub one_file_system: bool,
|
||||
|
||||
/// By default we output matched files/dirs raw. When the user specifies
|
||||
/// --quote we output the files wrapped in quotes per the rules laid out
|
||||
/// in coreutils: https://www.gnu.org/software/coreutils/quotes.html
|
||||
/// This should mimic the `ls -lsa` output style
|
||||
#[cfg(any(unix, windows))]
|
||||
#[arg(long, aliases(&["quote"]), hide_short_help = true, long_help)]
|
||||
pub use_quoting: bool,
|
||||
|
||||
#[cfg(feature = "completions")]
|
||||
#[arg(long, hide = true, exclusive = true)]
|
||||
gen_completions: Option<Option<Shell>>,
|
||||
|
|
|
@ -122,6 +122,9 @@ pub struct Config {
|
|||
|
||||
/// Whether or not to strip the './' prefix for search results
|
||||
pub strip_cwd_prefix: bool,
|
||||
|
||||
/// Whether to use quoting on the output file names
|
||||
pub use_quoting: bool,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
|
|
@ -251,6 +251,7 @@ fn construct_config(mut opts: Opts, pattern_regexps: &[String]) -> Result<Config
|
|||
one_file_system: opts.one_file_system,
|
||||
null_separator: opts.null_separator,
|
||||
quiet: opts.quiet,
|
||||
use_quoting: opts.use_quoting,
|
||||
max_depth: opts.max_depth(),
|
||||
min_depth: opts.min_depth(),
|
||||
prune: opts.prune,
|
||||
|
|
|
@ -54,6 +54,43 @@ fn print_trailing_slash<W: Write>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// Trying to copy: https://www.gnu.org/software/coreutils/quotes.html
|
||||
fn path_needs_quoting(path: &str) -> i8 {
|
||||
// If it contains any special chars we return single quote
|
||||
if path.contains(" ") || path.contains("$") || path.contains("\"") {
|
||||
return 1;
|
||||
// If it ONLY contains a ' we return double quote
|
||||
} else if path.contains("'") {
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Quote a path with coreutils style quoting to make copy/paste
|
||||
// more friendly for shells
|
||||
fn quote_path(path_str: &str) -> String {
|
||||
let quote_type = path_needs_quoting(path_str);
|
||||
let mut tmp_str:String = path_str.into();
|
||||
|
||||
// Quote with single quotes
|
||||
if quote_type == 1 {
|
||||
// Escape single quotes in path
|
||||
tmp_str = str::replace(&tmp_str, "'", "'\\''");
|
||||
|
||||
format!("'{}'", tmp_str)
|
||||
// Quote with double quotes
|
||||
} else if quote_type == 2 {
|
||||
// Escape double quotes in path
|
||||
tmp_str = str::replace(&tmp_str, "\"", "\\\"");
|
||||
|
||||
format!("\"{}\"", tmp_str)
|
||||
// No quoting required
|
||||
} else {
|
||||
path_str.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this function is performance critical and can probably be optimized
|
||||
fn print_entry_colorized<W: Write>(
|
||||
stdout: &mut W,
|
||||
|
@ -62,9 +99,22 @@ fn print_entry_colorized<W: Write>(
|
|||
ls_colors: &LsColors,
|
||||
) -> io::Result<()> {
|
||||
// Split the path between the parent and the last component
|
||||
let mut offset = 0;
|
||||
let path = entry.stripped_path(config);
|
||||
let path_str = path.to_string_lossy();
|
||||
let mut offset = 0;
|
||||
let path = entry.stripped_path(config);
|
||||
let mut path_str = path.to_string_lossy();
|
||||
let mut needs_quoting = false;
|
||||
|
||||
// Wrap the path in quotes
|
||||
if config.use_quoting {
|
||||
let tmp_str = quote_path(&path_str);
|
||||
|
||||
// If the quoted string is new, then we flag that to tweak the offset
|
||||
// so the colors line up
|
||||
if tmp_str != path_str {
|
||||
path_str = tmp_str.into();
|
||||
needs_quoting = true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(parent) = path.parent() {
|
||||
offset = parent.to_string_lossy().len();
|
||||
|
@ -78,6 +128,11 @@ fn print_entry_colorized<W: Write>(
|
|||
}
|
||||
|
||||
if offset > 0 {
|
||||
|
||||
if needs_quoting {
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
let mut parent_str = Cow::from(&path_str[..offset]);
|
||||
if let Some(ref separator) = config.path_separator {
|
||||
*parent_str.to_mut() = replace_path_separator(&parent_str, separator);
|
||||
|
|
|
@ -78,6 +78,14 @@ fn test_simple() {
|
|||
);
|
||||
}
|
||||
|
||||
static AND_QUOTE_FILES: &[&str] = &[
|
||||
"one'two.quo",
|
||||
"one two.quo",
|
||||
"one\"two.quo",
|
||||
"one$two.quo",
|
||||
"one'two$.quo",
|
||||
];
|
||||
|
||||
static AND_EXTRA_FILES: &[&str] = &[
|
||||
"a.foo",
|
||||
"one/b.foo",
|
||||
|
@ -2534,6 +2542,20 @@ fn test_strip_cwd_prefix() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quoting() {
|
||||
let te = TestEnv::new(DEFAULT_DIRS, AND_QUOTE_FILES);
|
||||
|
||||
te.assert_output(
|
||||
&["--quote", ".quo"],
|
||||
"'one two.quo'
|
||||
\"one'two.quo\"
|
||||
\"one'two\\$.quo\"
|
||||
'one\"two.quo'
|
||||
'one$two.quo'",
|
||||
);
|
||||
}
|
||||
|
||||
/// When fd is ran from a non-existent working directory, but an existent
|
||||
/// directory is passed in the arguments, it should still run fine
|
||||
#[test]
|
||||
|
|
Loading…
Reference in New Issue