mirror of https://github.com/sharkdp/fd.git
Allow more than one match to be captured per path
This commit is contained in:
parent
fed071eef1
commit
56ee505178
|
@ -2,6 +2,7 @@ use std::ffi::OsStr;
|
|||
use std::{
|
||||
fs::{FileType, Metadata},
|
||||
path::{Path, PathBuf},
|
||||
collections::HashMap,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
|
@ -18,7 +19,7 @@ enum DirEntryInner {
|
|||
pub struct DirEntry {
|
||||
inner: DirEntryInner,
|
||||
metadata: OnceCell<Option<Metadata>>,
|
||||
matches: Vec<String>,
|
||||
match_list: HashMap<usize, HashMap<usize, String>>,
|
||||
}
|
||||
|
||||
impl DirEntry {
|
||||
|
@ -27,7 +28,7 @@ impl DirEntry {
|
|||
Self {
|
||||
inner: DirEntryInner::Normal(e),
|
||||
metadata: OnceCell::new(),
|
||||
matches: Vec::new(),
|
||||
match_list: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +36,7 @@ impl DirEntry {
|
|||
Self {
|
||||
inner: DirEntryInner::BrokenSymlink(path),
|
||||
metadata: OnceCell::new(),
|
||||
matches: Vec::new(),
|
||||
match_list: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,8 +47,8 @@ impl DirEntry {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn matches(&self) -> &Vec<String> {
|
||||
&&self.matches
|
||||
pub fn matches(&self) -> &HashMap<usize, HashMap<usize, String>> {
|
||||
&self.match_list
|
||||
}
|
||||
|
||||
pub fn into_path(self) -> PathBuf {
|
||||
|
@ -83,22 +84,21 @@ impl DirEntry {
|
|||
pub fn is_match(&mut self, pattern: &Regex, search_full_path: bool) -> bool {
|
||||
let search_str = self.get_search_str(search_full_path);
|
||||
let search_res = filesystem::osstr_to_bytes(search_str.as_ref());
|
||||
let mut found: HashMap<usize, HashMap<usize, String>> = HashMap::new();
|
||||
|
||||
let mut parts:Vec<String> = Vec::new();
|
||||
for matched in pattern.captures_iter(&search_res) {
|
||||
for (j, group) in matched.iter().enumerate() {
|
||||
if j > 0 {
|
||||
if let Some(value) = group {
|
||||
let cap = value.as_bytes();
|
||||
let text = std::str::from_utf8(cap).unwrap();
|
||||
let part = text.to_string();
|
||||
parts.push(part);
|
||||
}
|
||||
for (ocurrence, matched) in pattern.captures_iter(&search_res).enumerate() {
|
||||
let mut matched_groups: HashMap<usize, String> = HashMap::new();
|
||||
for (group, group_match) in matched.iter().enumerate() {
|
||||
if let Some(value) = group_match {
|
||||
let cap = value.as_bytes();
|
||||
let text = String::from_utf8(cap.to_vec()).unwrap();
|
||||
matched_groups.insert(group, text );
|
||||
}
|
||||
}
|
||||
found.insert(ocurrence, matched_groups);
|
||||
}
|
||||
self.matches = parts;
|
||||
self.matches.len() > 0
|
||||
self.match_list = found;
|
||||
self.match_list.len() > 0
|
||||
}
|
||||
|
||||
fn get_search_str(&self, search_full_path: bool) -> Cow<OsStr> {
|
||||
|
|
|
@ -11,6 +11,7 @@ use std::path::{Component, Path, PathBuf, Prefix};
|
|||
use std::process::Stdio;
|
||||
use std::str;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use argmax::Command;
|
||||
|
@ -84,7 +85,7 @@ impl CommandSet {
|
|||
self.mode == ExecutionMode::Batch
|
||||
}
|
||||
|
||||
pub fn execute(&self, input: &Path, matches: &Vec<String>, out_perm: Arc<Mutex<()>>, buffer_output: bool) -> ExitCode {
|
||||
pub fn execute(&self, input: &Path, matches: &HashMap<usize, HashMap<usize, String>>, out_perm: Arc<Mutex<()>>, buffer_output: bool) -> ExitCode {
|
||||
let path_separator = self.path_separator.as_deref();
|
||||
let commands = self
|
||||
.commands
|
||||
|
@ -109,7 +110,7 @@ impl CommandSet {
|
|||
Ok(mut builders) => {
|
||||
for path in paths {
|
||||
for builder in &mut builders {
|
||||
if let Err(e) = builder.push(&path, path_separator, &Vec::new()) {
|
||||
if let Err(e) = builder.push(&path, path_separator, &HashMap::new()) {
|
||||
return handle_cmd_error(Some(&builder.cmd), e);
|
||||
}
|
||||
}
|
||||
|
@ -149,9 +150,9 @@ impl CommandBuilder {
|
|||
if arg.has_tokens() {
|
||||
path_arg = Some(arg.clone());
|
||||
} else if path_arg == None {
|
||||
pre_args.push(arg.generate("", None, &Vec::new()));
|
||||
pre_args.push(arg.generate("", None, &HashMap::new()));
|
||||
} else {
|
||||
post_args.push(arg.generate("", None, &Vec::new()));
|
||||
post_args.push(arg.generate("", None, &HashMap::new()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,7 +177,7 @@ impl CommandBuilder {
|
|||
Ok(cmd)
|
||||
}
|
||||
|
||||
fn push(&mut self, path: &Path, separator: Option<&str>, matches: &Vec<String>) -> io::Result<()> {
|
||||
fn push(&mut self, path: &Path, separator: Option<&str>, matches: &HashMap<usize, HashMap<usize, String>>) -> io::Result<()> {
|
||||
if self.limit > 0 && self.count >= self.limit {
|
||||
self.finish()?;
|
||||
}
|
||||
|
@ -298,7 +299,7 @@ impl CommandTemplate {
|
|||
///
|
||||
/// Using the internal `args` field, and a supplied `input` variable, a `Command` will be
|
||||
/// build.
|
||||
fn generate(&self, input: &Path, path_separator: Option<&str>, matches: &Vec<String>) -> io::Result<Command> {
|
||||
fn generate(&self, input: &Path, path_separator: Option<&str>, matches: &HashMap<usize, HashMap<usize, String>>) -> io::Result<Command> {
|
||||
let mut cmd = Command::new(self.args[0].generate(&input, path_separator, matches));
|
||||
for arg in &self.args[1..] {
|
||||
cmd.try_arg(arg.generate(&input, path_separator, matches))?;
|
||||
|
@ -325,7 +326,7 @@ impl ArgumentTemplate {
|
|||
/// Generate an argument from this template. If path_separator is Some, then it will replace
|
||||
/// the path separator in all placeholder tokens. Text arguments and tokens are not affected by
|
||||
/// path separator substitution.
|
||||
pub fn generate(&self, path: impl AsRef<Path>, path_separator: Option<&str>, matches: &Vec<String>) -> OsString {
|
||||
pub fn generate(&self, path: impl AsRef<Path>, path_separator: Option<&str>, matches: &HashMap<usize, HashMap<usize, String>>) -> OsString {
|
||||
use self::Token::*;
|
||||
let path = path.as_ref();
|
||||
|
||||
|
@ -349,8 +350,10 @@ impl ArgumentTemplate {
|
|||
}
|
||||
Text(ref string) => s.push(string),
|
||||
Positional(pos) => {
|
||||
if let Some(re_group) = matches.get(pos) {
|
||||
s.push(re_group)
|
||||
if let Some(groups) = matches.get(&0) {
|
||||
if let Some(re_group) = groups.get(&pos) {
|
||||
s.push(re_group)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -565,7 +568,7 @@ mod tests {
|
|||
let arg = ArgumentTemplate::Tokens(vec![Token::Placeholder]);
|
||||
macro_rules! check {
|
||||
($input:expr, $expected:expr) => {
|
||||
assert_eq!(arg.generate($input, Some("#"), &Vec::new()), OsString::from($expected));
|
||||
assert_eq!(arg.generate($input, Some("#"), &HashMap::new()), OsString::from($expected));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue