mirror of
https://github.com/sharkdp/fd
synced 2024-09-05 08:13:19 +00:00
Format the source code using rustfmt
This commit is contained in:
parent
e075e1cf7c
commit
049b9ec06b
21
src/app.rs
21
src/app.rs
|
@ -34,9 +34,24 @@ pub fn build_app() -> App<'static, 'static> {
|
|||
.setting(AppSettings::DeriveDisplayOrder)
|
||||
.arg(arg("hidden").long("hidden").short("H"))
|
||||
.arg(arg("no-ignore").long("no-ignore").short("I"))
|
||||
.arg(arg("rg-alias-hidden-ignore").short("u").multiple(true).hidden(true))
|
||||
.arg(arg("case-sensitive").long("case-sensitive").short("s").overrides_with("ignore-case"))
|
||||
.arg(arg("ignore-case").long("ignore-case").short("i").overrides_with("case-sensitive"))
|
||||
.arg(
|
||||
arg("rg-alias-hidden-ignore")
|
||||
.short("u")
|
||||
.multiple(true)
|
||||
.hidden(true),
|
||||
)
|
||||
.arg(
|
||||
arg("case-sensitive")
|
||||
.long("case-sensitive")
|
||||
.short("s")
|
||||
.overrides_with("ignore-case"),
|
||||
)
|
||||
.arg(
|
||||
arg("ignore-case")
|
||||
.long("ignore-case")
|
||||
.short("i")
|
||||
.overrides_with("case-sensitive"),
|
||||
)
|
||||
.arg(arg("absolute-path").long("absolute-path").short("a"))
|
||||
.arg(arg("follow").long("follow").short("L").alias("dereference"))
|
||||
.arg(arg("full-path").long("full-path").short("p"))
|
||||
|
|
|
@ -47,7 +47,9 @@ pub fn absolute_path(path: &Path) -> io::Result<PathBuf> {
|
|||
let path_buf = path.canonicalize()?;
|
||||
|
||||
#[cfg(windows)]
|
||||
let path_buf = Path::new(path_buf.as_path().to_string_lossy().trim_left_matches(r"\\?\")).to_path_buf();
|
||||
let path_buf = Path::new(path_buf.as_path().to_string_lossy().trim_left_matches(
|
||||
r"\\?\",
|
||||
)).to_path_buf();
|
||||
|
||||
Ok(path_buf)
|
||||
}
|
||||
|
|
|
@ -9,11 +9,45 @@ pub type ExtensionStyles = HashMap<String, Style>;
|
|||
/// Maps filenames to ANSI colors / styles.
|
||||
pub type FilenameStyles = HashMap<String, Style>;
|
||||
|
||||
const LS_CODES: &'static [&'static str] =
|
||||
&["no", "no", "fi", "rs", "di", "ln", "ln", "ln", "or", "mi", "pi", "pi",
|
||||
"so", "bd", "bd", "cd", "cd", "do", "ex", "lc", "lc", "rc", "rc", "ec",
|
||||
"ec", "su", "su", "sg", "sg", "st", "ow", "ow", "tw", "tw", "ca", "mh",
|
||||
"cl"];
|
||||
const LS_CODES: &'static [&'static str] = &[
|
||||
"no",
|
||||
"no",
|
||||
"fi",
|
||||
"rs",
|
||||
"di",
|
||||
"ln",
|
||||
"ln",
|
||||
"ln",
|
||||
"or",
|
||||
"mi",
|
||||
"pi",
|
||||
"pi",
|
||||
"so",
|
||||
"bd",
|
||||
"bd",
|
||||
"cd",
|
||||
"cd",
|
||||
"do",
|
||||
"ex",
|
||||
"lc",
|
||||
"lc",
|
||||
"rc",
|
||||
"rc",
|
||||
"ec",
|
||||
"ec",
|
||||
"su",
|
||||
"su",
|
||||
"sg",
|
||||
"sg",
|
||||
"st",
|
||||
"ow",
|
||||
"ow",
|
||||
"tw",
|
||||
"tw",
|
||||
"ca",
|
||||
"mh",
|
||||
"cl",
|
||||
];
|
||||
|
||||
/// Defines how different file system entries should be colorized / styled.
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
@ -67,40 +101,41 @@ impl LsColors {
|
|||
// Try to match the first part as a text-decoration argument
|
||||
let mut decoration = LsColors::parse_decoration(first);
|
||||
|
||||
let c1 = if decoration.is_none() { Some(first) } else { split.next() };
|
||||
let c1 = if decoration.is_none() {
|
||||
Some(first)
|
||||
} else {
|
||||
split.next()
|
||||
};
|
||||
let c2 = split.next();
|
||||
let c3 = split.next();
|
||||
|
||||
let color =
|
||||
if c1 == Some("38") && c2 == Some("5") {
|
||||
let n_white = 7;
|
||||
let n = if let Some(num) = c3 {
|
||||
u8::from_str_radix(num, 10).unwrap_or(n_white)
|
||||
} else {
|
||||
n_white
|
||||
};
|
||||
|
||||
Colour::Fixed(n)
|
||||
} else if let Some(color_s) = c1 {
|
||||
match color_s {
|
||||
"30" => Colour::Black,
|
||||
"31" => Colour::Red,
|
||||
"32" => Colour::Green,
|
||||
"33" => Colour::Yellow,
|
||||
"34" => Colour::Blue,
|
||||
"35" => Colour::Purple,
|
||||
"36" => Colour::Cyan,
|
||||
_ => Colour::White
|
||||
}
|
||||
let color = if c1 == Some("38") && c2 == Some("5") {
|
||||
let n_white = 7;
|
||||
let n = if let Some(num) = c3 {
|
||||
u8::from_str_radix(num, 10).unwrap_or(n_white)
|
||||
} else {
|
||||
Colour::White
|
||||
n_white
|
||||
};
|
||||
|
||||
Colour::Fixed(n)
|
||||
} else if let Some(color_s) = c1 {
|
||||
match color_s {
|
||||
"30" => Colour::Black,
|
||||
"31" => Colour::Red,
|
||||
"32" => Colour::Green,
|
||||
"33" => Colour::Yellow,
|
||||
"34" => Colour::Blue,
|
||||
"35" => Colour::Purple,
|
||||
"36" => Colour::Cyan,
|
||||
_ => Colour::White,
|
||||
}
|
||||
} else {
|
||||
Colour::White
|
||||
};
|
||||
|
||||
if decoration.is_none() {
|
||||
// Try to find a decoration somewhere in the sequence
|
||||
decoration = code.split(';')
|
||||
.flat_map(LsColors::parse_decoration)
|
||||
.next();
|
||||
decoration = code.split(';').flat_map(LsColors::parse_decoration).next();
|
||||
}
|
||||
|
||||
let ansi_style = decoration.unwrap_or(Colour::normal)(color);
|
||||
|
@ -130,13 +165,12 @@ impl LsColors {
|
|||
"di" => self.directory = style,
|
||||
"ln" => self.symlink = style,
|
||||
"ex" => self.executable = style,
|
||||
_ => return
|
||||
_ => return,
|
||||
}
|
||||
} else if pattern.starts_with("*.") {
|
||||
let extension = String::from(pattern).split_off(2);
|
||||
self.extensions.insert(extension, style);
|
||||
}
|
||||
else if pattern.starts_with('*') {
|
||||
} else if pattern.starts_with('*') {
|
||||
let filename = String::from(pattern).split_off(1);
|
||||
self.filenames.insert(filename, style);
|
||||
} else {
|
||||
|
@ -162,58 +196,63 @@ impl LsColors {
|
|||
|
||||
#[test]
|
||||
fn test_parse_simple() {
|
||||
assert_eq!(Some(Colour::Red.normal()),
|
||||
LsColors::parse_style("31"));
|
||||
assert_eq!(Some(Colour::Red.normal()), LsColors::parse_style("31"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_decoration() {
|
||||
assert_eq!(Some(Colour::Red.normal()),
|
||||
LsColors::parse_style("00;31"));
|
||||
assert_eq!(Some(Colour::Red.normal()), LsColors::parse_style("00;31"));
|
||||
|
||||
assert_eq!(Some(Colour::Blue.italic()),
|
||||
LsColors::parse_style("03;34"));
|
||||
assert_eq!(Some(Colour::Blue.italic()), LsColors::parse_style("03;34"));
|
||||
|
||||
assert_eq!(Some(Colour::Cyan.bold()),
|
||||
LsColors::parse_style("01;36"));
|
||||
assert_eq!(Some(Colour::Cyan.bold()), LsColors::parse_style("01;36"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_decoration_backwards() {
|
||||
assert_eq!(Some(Colour::Blue.italic()),
|
||||
LsColors::parse_style("34;03"));
|
||||
assert_eq!(Some(Colour::Blue.italic()), LsColors::parse_style("34;03"));
|
||||
|
||||
assert_eq!(Some(Colour::Cyan.bold()),
|
||||
LsColors::parse_style("36;01"));
|
||||
assert_eq!(Some(Colour::Cyan.bold()), LsColors::parse_style("36;01"));
|
||||
|
||||
assert_eq!(Some(Colour::Red.normal()),
|
||||
LsColors::parse_style("31;00"));
|
||||
assert_eq!(Some(Colour::Red.normal()), LsColors::parse_style("31;00"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_256() {
|
||||
assert_eq!(Some(Colour::Fixed(115).normal()),
|
||||
LsColors::parse_style("38;5;115"));
|
||||
assert_eq!(
|
||||
Some(Colour::Fixed(115).normal()),
|
||||
LsColors::parse_style("38;5;115")
|
||||
);
|
||||
|
||||
assert_eq!(Some(Colour::Fixed(115).normal()),
|
||||
LsColors::parse_style("00;38;5;115"));
|
||||
assert_eq!(
|
||||
Some(Colour::Fixed(115).normal()),
|
||||
LsColors::parse_style("00;38;5;115")
|
||||
);
|
||||
|
||||
assert_eq!(Some(Colour::Fixed(119).bold()),
|
||||
LsColors::parse_style("01;38;5;119"));
|
||||
assert_eq!(
|
||||
Some(Colour::Fixed(119).bold()),
|
||||
LsColors::parse_style("01;38;5;119")
|
||||
);
|
||||
|
||||
assert_eq!(Some(Colour::Fixed(119).bold()),
|
||||
LsColors::parse_style("38;5;119;01"));
|
||||
assert_eq!(
|
||||
Some(Colour::Fixed(119).bold()),
|
||||
LsColors::parse_style("38;5;119;01")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_string() {
|
||||
assert_eq!(LsColors::default(), LsColors::from_string(&String::new()));
|
||||
|
||||
let result = LsColors::from_string(
|
||||
&String::from("rs=0:di=03;34:ln=01;36:*.foo=01;35:*README=33"));
|
||||
let result = LsColors::from_string(&String::from(
|
||||
"rs=0:di=03;34:ln=01;36:*.foo=01;35:*README=33",
|
||||
));
|
||||
|
||||
assert_eq!(Colour::Blue.italic(), result.directory);
|
||||
assert_eq!(Colour::Cyan.bold(), result.symlink);
|
||||
assert_eq!(Some(&Colour::Purple.bold()), result.extensions.get("foo"));
|
||||
assert_eq!(Some(&Colour::Yellow.normal()), result.filenames.get("README"));
|
||||
assert_eq!(
|
||||
Some(&Colour::Yellow.normal()),
|
||||
result.filenames.get("README")
|
||||
);
|
||||
}
|
||||
|
|
115
src/main.rs
115
src/main.rs
|
@ -36,7 +36,7 @@ fn main() {
|
|||
// Get the current working directory
|
||||
let current_dir_buf = match env::current_dir() {
|
||||
Ok(cd) => cd,
|
||||
Err(_) => error("Error: could not get current directory.")
|
||||
Err(_) => error("Error: could not get current directory."),
|
||||
};
|
||||
let current_dir = current_dir_buf.as_path();
|
||||
|
||||
|
@ -47,15 +47,18 @@ fn main() {
|
|||
|
||||
root_dir_is_absolute = path.is_absolute();
|
||||
|
||||
fshelper::absolute_path(path).unwrap_or_else(
|
||||
|_| error(&format!("Error: could not find directory '{}'.", rd))
|
||||
)
|
||||
fshelper::absolute_path(path).unwrap_or_else(|_| {
|
||||
error(&format!("Error: could not find directory '{}'.", rd))
|
||||
})
|
||||
} else {
|
||||
current_dir_buf.clone()
|
||||
};
|
||||
|
||||
if !root_dir_buf.is_dir() {
|
||||
error(&format!("Error: '{}' is not a directory.", root_dir_buf.to_string_lossy()));
|
||||
error(&format!(
|
||||
"Error: '{}' is not a directory.",
|
||||
root_dir_buf.to_string_lossy()
|
||||
));
|
||||
}
|
||||
|
||||
let root_dir = root_dir_buf.as_path();
|
||||
|
@ -71,65 +74,71 @@ fn main() {
|
|||
let colored_output = match matches.value_of("color") {
|
||||
Some("always") => true,
|
||||
Some("never") => false,
|
||||
_ => atty::is(Stream::Stdout)
|
||||
_ => atty::is(Stream::Stdout),
|
||||
};
|
||||
|
||||
let ls_colors =
|
||||
if colored_output {
|
||||
Some(
|
||||
env::var("LS_COLORS")
|
||||
.ok()
|
||||
.map(|val| LsColors::from_string(&val))
|
||||
.unwrap_or_default()
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let ls_colors = if colored_output {
|
||||
Some(
|
||||
env::var("LS_COLORS")
|
||||
.ok()
|
||||
.map(|val| LsColors::from_string(&val))
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let config = FdOptions {
|
||||
case_sensitive: case_sensitive,
|
||||
search_full_path: matches.is_present("full-path"),
|
||||
ignore_hidden: !(matches.is_present("hidden") || matches.occurrences_of("rg-alias-hidden-ignore") >= 2),
|
||||
read_ignore: !(matches.is_present("no-ignore") || matches.is_present("rg-alias-hidden-ignore")),
|
||||
follow_links: matches.is_present("follow"),
|
||||
null_separator: matches.is_present("null_separator"),
|
||||
max_depth: matches.value_of("depth")
|
||||
.and_then(|n| usize::from_str_radix(n, 10).ok()),
|
||||
threads: std::cmp::max(
|
||||
matches.value_of("threads")
|
||||
.and_then(|n| usize::from_str_radix(n, 10).ok())
|
||||
.unwrap_or_else(num_cpus::get),
|
||||
1
|
||||
),
|
||||
max_buffer_time: matches.value_of("max-buffer-time")
|
||||
.and_then(|n| u64::from_str_radix(n, 10).ok())
|
||||
.map(time::Duration::from_millis),
|
||||
path_display: if matches.is_present("absolute-path") || root_dir_is_absolute {
|
||||
PathDisplay::Absolute
|
||||
} else {
|
||||
PathDisplay::Relative
|
||||
},
|
||||
ls_colors: ls_colors,
|
||||
file_type: match matches.value_of("file-type") {
|
||||
Some("f") | Some("file") => FileType::RegularFile,
|
||||
Some("d") | Some("directory") => FileType::Directory,
|
||||
Some("l") | Some("symlink") => FileType::SymLink,
|
||||
_ => FileType::Any,
|
||||
},
|
||||
extension: matches.value_of("extension")
|
||||
.map(|e| e.trim_left_matches('.').to_lowercase()),
|
||||
case_sensitive: case_sensitive,
|
||||
search_full_path: matches.is_present("full-path"),
|
||||
ignore_hidden: !(matches.is_present("hidden") ||
|
||||
matches.occurrences_of("rg-alias-hidden-ignore") >= 2),
|
||||
read_ignore: !(matches.is_present("no-ignore") ||
|
||||
matches.is_present("rg-alias-hidden-ignore")),
|
||||
follow_links: matches.is_present("follow"),
|
||||
null_separator: matches.is_present("null_separator"),
|
||||
max_depth: matches.value_of("depth").and_then(|n| {
|
||||
usize::from_str_radix(n, 10).ok()
|
||||
}),
|
||||
threads: std::cmp::max(
|
||||
matches
|
||||
.value_of("threads")
|
||||
.and_then(|n| usize::from_str_radix(n, 10).ok())
|
||||
.unwrap_or_else(num_cpus::get),
|
||||
1,
|
||||
),
|
||||
max_buffer_time: matches
|
||||
.value_of("max-buffer-time")
|
||||
.and_then(|n| u64::from_str_radix(n, 10).ok())
|
||||
.map(time::Duration::from_millis),
|
||||
path_display: if matches.is_present("absolute-path") || root_dir_is_absolute {
|
||||
PathDisplay::Absolute
|
||||
} else {
|
||||
PathDisplay::Relative
|
||||
},
|
||||
ls_colors: ls_colors,
|
||||
file_type: match matches.value_of("file-type") {
|
||||
Some("f") | Some("file") => FileType::RegularFile,
|
||||
Some("d") |
|
||||
Some("directory") => FileType::Directory,
|
||||
Some("l") | Some("symlink") => FileType::SymLink,
|
||||
_ => FileType::Any,
|
||||
},
|
||||
extension: matches.value_of("extension").map(|e| {
|
||||
e.trim_left_matches('.').to_lowercase()
|
||||
}),
|
||||
};
|
||||
|
||||
let root = Path::new(ROOT_DIR);
|
||||
let base = match config.path_display {
|
||||
PathDisplay::Relative => current_dir,
|
||||
PathDisplay::Absolute => root
|
||||
PathDisplay::Absolute => root,
|
||||
};
|
||||
|
||||
match RegexBuilder::new(pattern)
|
||||
.case_insensitive(!config.case_sensitive)
|
||||
.build() {
|
||||
Ok(re) => walk::scan(root_dir, Arc::new(re), base, Arc::new(config)),
|
||||
Err(err) => error(err.description())
|
||||
.case_insensitive(!config.case_sensitive)
|
||||
.build() {
|
||||
Ok(re) => walk::scan(root_dir, Arc::new(re), base, Arc::new(config)),
|
||||
Err(err) => error(err.description()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,9 @@ pub fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) {
|
|||
|
||||
#[cfg(unix)]
|
||||
let is_executable = |p: Option<&fs::Metadata>| {
|
||||
p.map(|f| f.permissions().mode() & 0o111 != 0)
|
||||
.unwrap_or(false)
|
||||
p.map(|f| f.permissions().mode() & 0o111 != 0).unwrap_or(
|
||||
false,
|
||||
)
|
||||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
|
@ -44,23 +45,24 @@ pub fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) {
|
|||
let metadata = component_path.metadata().ok();
|
||||
let is_directory = metadata.as_ref().map(|md| md.is_dir()).unwrap_or(false);
|
||||
|
||||
let style =
|
||||
if component_path.symlink_metadata()
|
||||
.map(|md| md.file_type().is_symlink())
|
||||
.unwrap_or(false) {
|
||||
&ls_colors.symlink
|
||||
} else if is_directory {
|
||||
&ls_colors.directory
|
||||
} else if is_executable(metadata.as_ref()) {
|
||||
&ls_colors.executable
|
||||
} else {
|
||||
// Look up file name
|
||||
let o_style =
|
||||
component_path.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.and_then(|n| ls_colors.filenames.get(n));
|
||||
let style = if component_path
|
||||
.symlink_metadata()
|
||||
.map(|md| md.file_type().is_symlink())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
&ls_colors.symlink
|
||||
} else if is_directory {
|
||||
&ls_colors.directory
|
||||
} else if is_executable(metadata.as_ref()) {
|
||||
&ls_colors.executable
|
||||
} else {
|
||||
// Look up file name
|
||||
let o_style = component_path
|
||||
.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.and_then(|n| ls_colors.filenames.get(n));
|
||||
|
||||
match o_style {
|
||||
match o_style {
|
||||
Some(s) => s,
|
||||
None =>
|
||||
// Look up file extension
|
||||
|
@ -69,7 +71,7 @@ pub fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) {
|
|||
.and_then(|e| ls_colors.extensions.get(e))
|
||||
.unwrap_or(&default_style)
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
write!(handle, "{}", style.paint(comp_str)).ok();
|
||||
|
||||
|
@ -91,7 +93,11 @@ pub fn print_entry(base: &Path, entry: &PathBuf, config: &FdOptions) {
|
|||
} else {
|
||||
// Uncolorized output
|
||||
|
||||
let prefix = if config.path_display == PathDisplay::Absolute { ROOT_DIR } else { "" };
|
||||
let prefix = if config.path_display == PathDisplay::Absolute {
|
||||
ROOT_DIR
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let separator = if config.null_separator { "\0" } else { "\n" };
|
||||
|
||||
let r = write!(&mut io::stdout(), "{}{}{}", prefix, path_str, separator);
|
||||
|
|
74
src/walk.rs
74
src/walk.rs
|
@ -35,16 +35,16 @@ pub fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions
|
|||
let (tx, rx) = channel();
|
||||
|
||||
let walker = WalkBuilder::new(root)
|
||||
.hidden(config.ignore_hidden)
|
||||
.ignore(config.read_ignore)
|
||||
.git_ignore(config.read_ignore)
|
||||
.parents(config.read_ignore)
|
||||
.git_global(config.read_ignore)
|
||||
.git_exclude(config.read_ignore)
|
||||
.follow_links(config.follow_links)
|
||||
.max_depth(config.max_depth)
|
||||
.threads(config.threads)
|
||||
.build_parallel();
|
||||
.hidden(config.ignore_hidden)
|
||||
.ignore(config.read_ignore)
|
||||
.git_ignore(config.read_ignore)
|
||||
.parents(config.read_ignore)
|
||||
.git_global(config.read_ignore)
|
||||
.git_exclude(config.read_ignore)
|
||||
.follow_links(config.follow_links)
|
||||
.max_depth(config.max_depth)
|
||||
.threads(config.threads)
|
||||
.build_parallel();
|
||||
|
||||
// Spawn the thread that receives all results through the channel.
|
||||
let rx_config = Arc::clone(&config);
|
||||
|
@ -58,8 +58,9 @@ pub fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions
|
|||
let mut mode = ReceiverMode::Buffering;
|
||||
|
||||
// Maximum time to wait before we start streaming to the console.
|
||||
let max_buffer_time = rx_config.max_buffer_time
|
||||
.unwrap_or_else(|| time::Duration::from_millis(100));
|
||||
let max_buffer_time = rx_config.max_buffer_time.unwrap_or_else(
|
||||
|| time::Duration::from_millis(100),
|
||||
);
|
||||
|
||||
for value in rx {
|
||||
match mode {
|
||||
|
@ -77,7 +78,7 @@ pub fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions
|
|||
// Start streaming
|
||||
mode = ReceiverMode::Streaming;
|
||||
}
|
||||
},
|
||||
}
|
||||
ReceiverMode::Streaming => {
|
||||
output::print_entry(&rx_base, &value, &rx_config);
|
||||
}
|
||||
|
@ -110,20 +111,28 @@ pub fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions
|
|||
// Filter out unwanted file types.
|
||||
match config.file_type {
|
||||
FileType::Any => (),
|
||||
FileType::RegularFile => if entry.file_type().map_or(false, |ft| !ft.is_file()) {
|
||||
return ignore::WalkState::Continue;
|
||||
},
|
||||
FileType::Directory => if entry.file_type().map_or(false, |ft| !ft.is_dir()) {
|
||||
return ignore::WalkState::Continue;
|
||||
},
|
||||
FileType::SymLink => if entry.file_type().map_or(false, |ft| !ft.is_symlink()) {
|
||||
return ignore::WalkState::Continue;
|
||||
},
|
||||
FileType::RegularFile => {
|
||||
if entry.file_type().map_or(false, |ft| !ft.is_file()) {
|
||||
return ignore::WalkState::Continue;
|
||||
}
|
||||
}
|
||||
FileType::Directory => {
|
||||
if entry.file_type().map_or(false, |ft| !ft.is_dir()) {
|
||||
return ignore::WalkState::Continue;
|
||||
}
|
||||
}
|
||||
FileType::SymLink => {
|
||||
if entry.file_type().map_or(false, |ft| !ft.is_symlink()) {
|
||||
return ignore::WalkState::Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out unwanted extensions.
|
||||
if let Some(ref filter_ext) = config.extension {
|
||||
let entry_ext = entry.path().extension().map(|e| e.to_string_lossy().to_lowercase());
|
||||
let entry_ext = entry.path().extension().map(|e| {
|
||||
e.to_string_lossy().to_lowercase()
|
||||
});
|
||||
if entry_ext.map_or(true, |ext| ext != *filter_ext) {
|
||||
return ignore::WalkState::Continue;
|
||||
}
|
||||
|
@ -131,22 +140,21 @@ pub fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions
|
|||
|
||||
let path_rel_buf = match fshelper::path_relative_from(entry.path(), &*base) {
|
||||
Some(p) => p,
|
||||
None => error("Error: could not get relative path for directory entry.")
|
||||
None => error("Error: could not get relative path for directory entry."),
|
||||
};
|
||||
let path_rel = path_rel_buf.as_path();
|
||||
|
||||
let search_str_o =
|
||||
if config.search_full_path {
|
||||
Some(path_rel.to_string_lossy())
|
||||
} else {
|
||||
path_rel.file_name()
|
||||
.map(|f| f.to_string_lossy())
|
||||
};
|
||||
let search_str_o = if config.search_full_path {
|
||||
Some(path_rel.to_string_lossy())
|
||||
} else {
|
||||
path_rel.file_name().map(|f| f.to_string_lossy())
|
||||
};
|
||||
|
||||
if let Some(search_str) = search_str_o {
|
||||
// TODO: take care of the unwrap call
|
||||
pattern.find(&*search_str)
|
||||
.map(|_| tx_thread.send(path_rel_buf.to_owned()).unwrap());
|
||||
pattern.find(&*search_str).map(|_| {
|
||||
tx_thread.send(path_rel_buf.to_owned()).unwrap()
|
||||
});
|
||||
}
|
||||
|
||||
ignore::WalkState::Continue
|
||||
|
|
|
@ -44,15 +44,15 @@ fn create_working_directory() -> Result<TempDir, io::Error> {
|
|||
fs::File::create(root.join("ignored.foo"))?;
|
||||
fs::File::create(root.join(".hidden.foo"))?;
|
||||
|
||||
#[cfg(unix)]
|
||||
unix::fs::symlink(root.join("one/two"), root.join("symlink"))?;
|
||||
#[cfg(unix)] unix::fs::symlink(root.join("one/two"), root.join("symlink"))?;
|
||||
|
||||
// Note: creating symlinks on Windows requires the `SeCreateSymbolicLinkPrivilege` which
|
||||
// is by default only granted for administrators.
|
||||
#[cfg(windows)]
|
||||
windows::fs::symlink_dir(root.join("one/two"), root.join("symlink"))?;
|
||||
#[cfg(windows)] windows::fs::symlink_dir(root.join("one/two"), root.join("symlink"))?;
|
||||
|
||||
fs::File::create(root.join(".ignore"))?.write_all(b"ignored.foo")?;
|
||||
fs::File::create(root.join(".ignore"))?.write_all(
|
||||
b"ignored.foo",
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(temp_dir)
|
||||
|
@ -61,9 +61,12 @@ fn create_working_directory() -> Result<TempDir, io::Error> {
|
|||
/// Find the *fd* executable.
|
||||
fn find_fd_exe() -> PathBuf {
|
||||
// Tests exe is in target/debug/deps, the *fd* exe is in target/debug
|
||||
let root = env::current_exe().expect("tests executable")
|
||||
.parent().expect("tests executable directory")
|
||||
.parent().expect("fd executable directory")
|
||||
let root = env::current_exe()
|
||||
.expect("tests executable")
|
||||
.parent()
|
||||
.expect("tests executable directory")
|
||||
.parent()
|
||||
.expect("fd executable directory")
|
||||
.to_path_buf();
|
||||
|
||||
let exe_name = if cfg!(windows) { "fd.exe" } else { "fd" };
|
||||
|
@ -77,38 +80,37 @@ fn format_exit_error(args: &[&str], output: &process::Output) -> String {
|
|||
"`fd {}` did not exit successfully.\nstdout:\n---\n{}---\nstderr:\n---\n{}---",
|
||||
args.join(" "),
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr))
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
)
|
||||
}
|
||||
|
||||
/// Format an error message for when the output of *fd* did not match the expected output.
|
||||
fn format_output_error(args: &[&str], expected: &str, actual: &str) -> String {
|
||||
// Generate diff text.
|
||||
let diff_text =
|
||||
diff::lines(expected, actual)
|
||||
.into_iter()
|
||||
.map(|diff| {
|
||||
match diff {
|
||||
diff::Result::Left(l) => format!("-{}", l),
|
||||
diff::Result::Both(l, _) => format!(" {}", l),
|
||||
diff::Result::Right(r) => format!("+{}", r),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
let diff_text = diff::lines(expected, actual)
|
||||
.into_iter()
|
||||
.map(|diff| match diff {
|
||||
diff::Result::Left(l) => format!("-{}", l),
|
||||
diff::Result::Both(l, _) => format!(" {}", l),
|
||||
diff::Result::Right(r) => format!("+{}", r),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
format!(
|
||||
concat!(
|
||||
"`fd {}` did not produce the expected output.\n",
|
||||
"Showing diff between expected and actual:\n{}\n"),
|
||||
"Showing diff between expected and actual:\n{}\n"
|
||||
),
|
||||
args.join(" "),
|
||||
diff_text)
|
||||
diff_text
|
||||
)
|
||||
}
|
||||
|
||||
/// Normalize the output for comparison.
|
||||
fn normalize_output(s: &str, trim_left: bool) -> String {
|
||||
// Split into lines and normalize separators.
|
||||
let mut lines = s
|
||||
.replace('\0', "NULL\n")
|
||||
let mut lines = s.replace('\0', "NULL\n")
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let line = if trim_left { line.trim_left() } else { line };
|
||||
|
@ -145,7 +147,12 @@ impl TestEnv {
|
|||
|
||||
/// Assert that calling *fd* in the specified path under the root working directory,
|
||||
/// and with the specified arguments produces the expected output.
|
||||
pub fn assert_output_subdirectory<P: AsRef<Path>>(&self, path: P, args: &[&str], expected: &str) {
|
||||
pub fn assert_output_subdirectory<P: AsRef<Path>>(
|
||||
&self,
|
||||
path: P,
|
||||
args: &[&str],
|
||||
expected: &str,
|
||||
) {
|
||||
// Setup *fd* command.
|
||||
let mut cmd = process::Command::new(&self.fd_exe);
|
||||
cmd.current_dir(self.temp_dir.path().join(path));
|
||||
|
|
120
tests/tests.rs
120
tests/tests.rs
|
@ -20,7 +20,8 @@ fn test_simple() {
|
|||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
one/two/three/directory_foo",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&[],
|
||||
|
@ -33,7 +34,8 @@ fn test_simple() {
|
|||
one/two/three
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo
|
||||
symlink");
|
||||
symlink",
|
||||
);
|
||||
}
|
||||
|
||||
/// Explicit root path
|
||||
|
@ -47,12 +49,14 @@ fn test_explicit_root_path() {
|
|||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
one/two/three/directory_foo",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["foo", "one/two/three"],
|
||||
"one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
one/two/three/directory_foo",
|
||||
);
|
||||
|
||||
te.assert_output_subdirectory(
|
||||
"one/two",
|
||||
|
@ -62,7 +66,8 @@ fn test_explicit_root_path() {
|
|||
c.foo
|
||||
C.Foo2
|
||||
three/d.foo
|
||||
three/directory_foo");
|
||||
three/directory_foo",
|
||||
);
|
||||
}
|
||||
|
||||
/// Regex searches
|
||||
|
@ -75,13 +80,15 @@ fn test_regex_searches() {
|
|||
"a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2");
|
||||
one/two/C.Foo2",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["--case-sensitive", "[a-c].foo"],
|
||||
"a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo");
|
||||
one/two/c.foo",
|
||||
);
|
||||
}
|
||||
|
||||
/// Smart case
|
||||
|
@ -92,15 +99,12 @@ fn test_smart_case() {
|
|||
te.assert_output(
|
||||
&["c.foo"],
|
||||
"one/two/c.foo
|
||||
one/two/C.Foo2");
|
||||
one/two/C.Foo2",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["C.Foo"],
|
||||
"one/two/C.Foo2");
|
||||
te.assert_output(&["C.Foo"], "one/two/C.Foo2");
|
||||
|
||||
te.assert_output(
|
||||
&["Foo"],
|
||||
"one/two/C.Foo2");
|
||||
te.assert_output(&["Foo"], "one/two/C.Foo2");
|
||||
}
|
||||
|
||||
/// Case sensitivity (--case-sensitive)
|
||||
|
@ -108,17 +112,14 @@ fn test_smart_case() {
|
|||
fn test_case_sensitive() {
|
||||
let te = TestEnv::new();
|
||||
|
||||
te.assert_output(
|
||||
&["--case-sensitive", "c.foo"],
|
||||
"one/two/c.foo");
|
||||
te.assert_output(&["--case-sensitive", "c.foo"], "one/two/c.foo");
|
||||
|
||||
te.assert_output(
|
||||
&["--case-sensitive", "C.Foo"],
|
||||
"one/two/C.Foo2");
|
||||
te.assert_output(&["--case-sensitive", "C.Foo"], "one/two/C.Foo2");
|
||||
|
||||
te.assert_output(
|
||||
&["--ignore-case", "--case-sensitive", "C.Foo"],
|
||||
"one/two/C.Foo2");
|
||||
"one/two/C.Foo2",
|
||||
);
|
||||
}
|
||||
|
||||
/// Case insensitivity (--ignore-case)
|
||||
|
@ -129,12 +130,14 @@ fn test_case_insensitive() {
|
|||
te.assert_output(
|
||||
&["--ignore-case", "C.Foo"],
|
||||
"one/two/c.foo
|
||||
one/two/C.Foo2");
|
||||
one/two/C.Foo2",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["--case-sensitive", "--ignore-case", "C.Foo"],
|
||||
"one/two/c.foo
|
||||
one/two/C.Foo2");
|
||||
one/two/C.Foo2",
|
||||
);
|
||||
}
|
||||
|
||||
/// Full path search (--full-path)
|
||||
|
@ -145,11 +148,10 @@ fn test_full_path() {
|
|||
te.assert_output(
|
||||
&["--full-path", "three.*foo"],
|
||||
"one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
one/two/three/directory_foo",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["--full-path", "^a\\.foo"],
|
||||
"a.foo");
|
||||
te.assert_output(&["--full-path", "^a\\.foo"], "a.foo");
|
||||
}
|
||||
|
||||
/// Hidden files (--hidden)
|
||||
|
@ -165,7 +167,8 @@ fn test_hidden() {
|
|||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
one/two/three/directory_foo",
|
||||
);
|
||||
}
|
||||
|
||||
/// Ignored files (--no-ignore)
|
||||
|
@ -181,7 +184,8 @@ fn test_no_ignore() {
|
|||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
one/two/three/directory_foo",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["--hidden", "--no-ignore", "foo"],
|
||||
|
@ -192,7 +196,8 @@ fn test_no_ignore() {
|
|||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
one/two/three/directory_foo",
|
||||
);
|
||||
}
|
||||
|
||||
/// Ignored files with ripgrep aliases (-u / -uu)
|
||||
|
@ -208,7 +213,8 @@ fn test_no_ignore_aliases() {
|
|||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
one/two/three/directory_foo",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["-uu", "foo"],
|
||||
|
@ -219,7 +225,8 @@ fn test_no_ignore_aliases() {
|
|||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo
|
||||
one/two/three/directory_foo");
|
||||
one/two/three/directory_foo",
|
||||
);
|
||||
}
|
||||
|
||||
/// Symlinks (--follow)
|
||||
|
@ -232,7 +239,8 @@ fn test_follow() {
|
|||
"one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
symlink/c.foo
|
||||
symlink/C.Foo2");
|
||||
symlink/C.Foo2",
|
||||
);
|
||||
}
|
||||
|
||||
/// Null separator (--print0)
|
||||
|
@ -247,7 +255,8 @@ fn test_print0() {
|
|||
one/two/C.Foo2NULL
|
||||
one/two/c.fooNULL
|
||||
one/two/three/d.fooNULL
|
||||
one/two/three/directory_fooNULL");
|
||||
one/two/three/directory_fooNULL",
|
||||
);
|
||||
}
|
||||
|
||||
/// Maximum depth (--max-depth)
|
||||
|
@ -264,7 +273,8 @@ fn test_max_depth() {
|
|||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three
|
||||
symlink");
|
||||
symlink",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["--max-depth", "2"],
|
||||
|
@ -272,13 +282,15 @@ fn test_max_depth() {
|
|||
one
|
||||
one/b.foo
|
||||
one/two
|
||||
symlink");
|
||||
symlink",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["--max-depth", "1"],
|
||||
"a.foo
|
||||
one
|
||||
symlink");
|
||||
symlink",
|
||||
);
|
||||
}
|
||||
|
||||
/// Absolute paths (--absolute-path)
|
||||
|
@ -287,8 +299,10 @@ fn test_absolute_path() {
|
|||
let te = TestEnv::new();
|
||||
|
||||
let abs_path = te.root()
|
||||
.canonicalize().expect("absolute path")
|
||||
.to_str().expect("string")
|
||||
.canonicalize()
|
||||
.expect("absolute path")
|
||||
.to_str()
|
||||
.expect("string")
|
||||
.to_string();
|
||||
|
||||
#[cfg(windows)]
|
||||
|
@ -303,8 +317,8 @@ fn test_absolute_path() {
|
|||
{abs_path}/one/two/C.Foo2
|
||||
{abs_path}/one/two/three/d.foo
|
||||
{abs_path}/one/two/three/directory_foo",
|
||||
abs_path=abs_path
|
||||
)
|
||||
abs_path = abs_path
|
||||
),
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
|
@ -316,8 +330,8 @@ fn test_absolute_path() {
|
|||
{abs_path}/one/two/C.Foo2
|
||||
{abs_path}/one/two/three/d.foo
|
||||
{abs_path}/one/two/three/directory_foo",
|
||||
abs_path=abs_path
|
||||
)
|
||||
abs_path = abs_path
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -332,18 +346,18 @@ fn test_type() {
|
|||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/C.Foo2
|
||||
one/two/three/d.foo");
|
||||
one/two/three/d.foo",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["--type", "d"],
|
||||
"one
|
||||
one/two
|
||||
one/two/three
|
||||
one/two/three/directory_foo");
|
||||
one/two/three/directory_foo",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["--type", "l"],
|
||||
"symlink");
|
||||
te.assert_output(&["--type", "l"], "symlink");
|
||||
}
|
||||
|
||||
/// File extension (--extension)
|
||||
|
@ -356,16 +370,16 @@ fn test_extension() {
|
|||
"a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/three/d.foo");
|
||||
one/two/three/d.foo",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["--extension", ".foo"],
|
||||
"a.foo
|
||||
one/b.foo
|
||||
one/two/c.foo
|
||||
one/two/three/d.foo");
|
||||
one/two/three/d.foo",
|
||||
);
|
||||
|
||||
te.assert_output(
|
||||
&["--extension", "foo2"],
|
||||
"one/two/C.Foo2");
|
||||
te.assert_output(&["--extension", "foo2"], "one/two/C.Foo2");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue