Use RegexSet instead of hand-written parser

This commit is contained in:
Martin Larralde 2018-02-07 16:13:28 +01:00 committed by David Peter
parent 86fe9977e8
commit 370d9f081f
4 changed files with 17 additions and 54 deletions

View file

@ -16,6 +16,7 @@ use exec::CommandTemplate;
use lscolors::LsColors;
use walk::FileType;
use regex_syntax::{Expr, ExprBuilder};
use regex::RegexSet;
/// Configuration options for *fd*.
pub struct FdOptions {
@ -65,7 +66,7 @@ pub struct FdOptions {
/// The extension to search for. Only entries matching the extension will be included.
///
/// The value (if present) will be a lowercase string without leading dots.
pub extensions: Option<HashSet<String>>,
pub extensions: Option<RegexSet>,
/// If a value is supplied, each item found will be used to generate and execute commands.
pub command: Option<CommandTemplate>,

View file

@ -25,7 +25,6 @@ mod app;
mod exec;
mod internal;
mod output;
mod utils;
mod walk;
#[cfg(windows)]
@ -38,7 +37,7 @@ use std::sync::Arc;
use std::time;
use atty::Stream;
use regex::RegexBuilder;
use regex::{RegexBuilder, RegexSetBuilder};
use exec::CommandTemplate;
use internal::{error, pattern_has_uppercase_char, transform_args_with_exec, FdOptions};
@ -153,8 +152,15 @@ fn main() {
.collect(),
},
extensions: matches.values_of("extension").map(|exts| {
exts.map(|e| String::from(".") + &e.trim_left_matches('.'))
.collect()
let patterns = exts.map(|e| e.trim_left_matches('.'))
.map(|e| format!(r".\.{}$", regex::escape(e)));
match RegexSetBuilder::new(patterns)
.case_insensitive(true)
.build()
{
Ok(re) => re,
Err(err) => error(err.description()),
}
}),
command,
exclude_patterns: matches

View file

@ -1,45 +0,0 @@
// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::path::Path;
use std::iter::Iterator;
/// Determine if an os string ends with any of the given extensions (case insensitive).
pub fn path_has_any_extension<'a, I>(path: &Path, exts: I) -> bool
where
I: 'a + Iterator<Item = &'a String> + Clone,
{
// TODO: remove these two lines when we drop support for Rust version < 1.23.
#[allow(unused_imports)]
use std::ascii::AsciiExt;
if let Some(ref name) = path.file_name() {
if let Some(ref name_str) = name.to_str() {
exts.clone().any(|x| {
let mut it = name_str.chars().rev();
if x.chars()
.rev()
.zip(&mut it)
.all(|(a, b)| a.eq_ignore_ascii_case(&b))
{
match it.next() {
Some('/') | None => false,
_ => true,
}
} else {
false
}
})
} else {
false
}
} else {
false
}
}

View file

@ -11,7 +11,6 @@ extern crate ctrlc;
use exec;
use fshelper;
use internal::{error, FdOptions, EXITCODE_SIGINT, MAX_BUFFER_LENGTH};
use utils::path_has_any_extension;
use output;
use std::process;
@ -214,9 +213,11 @@ pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<FdOptions>) {
}
// Filter out unwanted extensions.
if let Some(ref filter_exts) = config.extensions {
if !path_has_any_extension(entry_path, filter_exts.iter()) {
return ignore::WalkState::Continue;
if let Some(ref exts_regex) = config.extensions {
if let Some(path_str) = entry_path.file_name().map_or(None, |s| s.to_str()) {
if !exts_regex.is_match(path_str) {
return ignore::WalkState::Continue;
}
}
}