mirror of
https://github.com/sharkdp/fd
synced 2024-10-04 14:59:15 +00:00
Enable absolute paths w/ exec
This commit is contained in:
parent
884bd41cae
commit
718f723d31
|
@ -35,7 +35,7 @@ subdirectories and about a million files. For averaging and statistical analysis
|
|||
cache". Results for a cold cache are similar.
|
||||
|
||||
Let's start with `find`:
|
||||
```sh
|
||||
```
|
||||
find ~ -iregex '.*[0-9]\.jpg$'
|
||||
|
||||
time 6.265 s (6.127 s .. NaN s)
|
||||
|
@ -45,7 +45,7 @@ std dev 31.73 ms (0.0 s .. 33.48 ms)
|
|||
```
|
||||
|
||||
`find` is much faster if it does not need to perform a regular-expression search:
|
||||
```sh
|
||||
```
|
||||
find ~ -iname '*[0-9].jpg'
|
||||
|
||||
time 2.866 s (2.754 s .. 2.964 s)
|
||||
|
@ -57,7 +57,7 @@ std dev 23.11 ms (0.0 s .. 25.09 ms)
|
|||
Now let's try the same for `fd`. Note that `fd` *always* performs a regular expression
|
||||
search. The options `--hidden` and `--no-ignore` are needed for a fair comparison,
|
||||
otherwise `fd` does not have to traverse hidden folders and ignored paths (see below):
|
||||
```sh
|
||||
```
|
||||
fd --hidden --no-ignore '.*[0-9]\.jpg$' ~
|
||||
|
||||
time 892.6 ms (839.0 ms .. 915.4 ms)
|
||||
|
@ -71,7 +71,7 @@ same 14030 files :smile:.
|
|||
|
||||
Finally, let's run `fd` without `--hidden` and `--no-ignore` (this can lead to different
|
||||
search results, of course):
|
||||
```sh
|
||||
```
|
||||
fd '[0-9]\.jpg$' ~
|
||||
|
||||
time 159.5 ms (155.8 ms .. 165.3 ms)
|
||||
|
|
|
@ -7,7 +7,11 @@ use super::TokenizedCommand;
|
|||
/// An event loop that listens for inputs from the `rx` receiver. Each received input will
|
||||
/// generate a command with the supplied command template. The generated command will then
|
||||
/// be executed, and this process will continue until the receiver's sender has closed.
|
||||
pub fn job(rx: Arc<Mutex<Receiver<PathBuf>>>, cmd: Arc<TokenizedCommand>) {
|
||||
pub fn job(
|
||||
rx: Arc<Mutex<Receiver<PathBuf>>>,
|
||||
base: Arc<Option<PathBuf>>,
|
||||
cmd: Arc<TokenizedCommand>,
|
||||
) {
|
||||
// A string buffer that will be re-used in each iteration.
|
||||
let buffer = &mut String::with_capacity(256);
|
||||
|
||||
|
@ -17,14 +21,18 @@ pub fn job(rx: Arc<Mutex<Receiver<PathBuf>>>, cmd: Arc<TokenizedCommand>) {
|
|||
|
||||
// Obtain the next path from the receiver, else if the channel
|
||||
// has closed, exit from the loop
|
||||
let value = match lock.recv() {
|
||||
Ok(value) => value,
|
||||
let value: PathBuf = match lock.recv() {
|
||||
Ok(value) => {
|
||||
match *base {
|
||||
Some(ref base) => base.join(&value),
|
||||
None => value,
|
||||
}
|
||||
}
|
||||
Err(_) => break,
|
||||
};
|
||||
|
||||
// Drop the lock so that other threads can read from the the receiver.
|
||||
drop(lock);
|
||||
|
||||
// Generate a command to store within the buffer, and execute the command.
|
||||
// Note that the `then_execute()` method will clear the buffer for us.
|
||||
cmd.generate(buffer, &value).then_execute();
|
||||
|
|
|
@ -1,29 +1,16 @@
|
|||
// TODO: Possible optimization could avoid pushing characters on a buffer.
|
||||
mod command;
|
||||
mod ticket;
|
||||
mod token;
|
||||
mod job;
|
||||
mod paths;
|
||||
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::path::Path;
|
||||
|
||||
use self::paths::{basename, dirname, remove_extension};
|
||||
use self::command::CommandTicket;
|
||||
use self::ticket::CommandTicket;
|
||||
use self::token::Token;
|
||||
pub use self::job::job;
|
||||
|
||||
/// Designates what should be written to a buffer
|
||||
///
|
||||
/// Each `Token` contains either text, or a placeholder variant, which will be used to generate
|
||||
/// commands after all tokens for a given command template have been collected.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Token {
|
||||
Placeholder,
|
||||
Basename,
|
||||
Parent,
|
||||
NoExt,
|
||||
BasenameNoExt,
|
||||
Text(String),
|
||||
}
|
||||
|
||||
/// Signifies that a placeholder token was found
|
||||
const PLACE: u8 = 1;
|
||||
|
||||
|
@ -150,22 +137,6 @@ fn append(tokens: &mut Vec<Token>, elem: &str) {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for TokenizedCommand {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
for token in &self.tokens {
|
||||
match *token {
|
||||
Token::Placeholder => f.write_str("{}")?,
|
||||
Token::Basename => f.write_str("{/}")?,
|
||||
Token::Parent => f.write_str("{//}")?,
|
||||
Token::NoExt => f.write_str("{.}")?,
|
||||
Token::BasenameNoExt => f.write_str("{/.}")?,
|
||||
Token::Text(ref string) => f.write_str(string)?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{TokenizedCommand, Token};
|
||||
|
|
29
src/exec/token.rs
Normal file
29
src/exec/token.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
/// Designates what should be written to a buffer
|
||||
///
|
||||
/// Each `Token` contains either text, or a placeholder variant, which will be used to generate
|
||||
/// commands after all tokens for a given command template have been collected.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Token {
|
||||
Placeholder,
|
||||
Basename,
|
||||
Parent,
|
||||
NoExt,
|
||||
BasenameNoExt,
|
||||
Text(String),
|
||||
}
|
||||
|
||||
impl Display for Token {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Token::Placeholder => f.write_str("{}")?,
|
||||
Token::Basename => f.write_str("{/}")?,
|
||||
Token::Parent => f.write_str("{//}")?,
|
||||
Token::NoExt => f.write_str("{.}")?,
|
||||
Token::BasenameNoExt => f.write_str("{/.}")?,
|
||||
Token::Text(ref string) => f.write_str(string)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use exec::{self, TokenizedCommand};
|
||||
use fshelper;
|
||||
use internal::{error, FdOptions};
|
||||
use internal::{error, FdOptions, PathDisplay};
|
||||
use output;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -55,10 +55,12 @@ pub fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions
|
|||
// Spawn the thread that receives all results through the channel.
|
||||
let rx_config = Arc::clone(&config);
|
||||
let rx_base = base.to_owned();
|
||||
let is_absolute = config.path_display == PathDisplay::Absolute;
|
||||
let receiver_thread = thread::spawn(move || {
|
||||
// This will be set to `Some` if the `--exec` argument was supplied.
|
||||
if let Some(ref cmd) = rx_config.command {
|
||||
let shared_rx = Arc::new(Mutex::new(rx));
|
||||
let base = Arc::new(if is_absolute { Some(rx_base) } else { None });
|
||||
|
||||
// This is safe because `cmd` will exist beyond the end of this scope.
|
||||
// It's required to tell Rust that it's safe to share across threads.
|
||||
|
@ -69,9 +71,10 @@ pub fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions
|
|||
for _ in 0..threads {
|
||||
let rx = shared_rx.clone();
|
||||
let cmd = cmd.clone();
|
||||
let base = base.clone();
|
||||
|
||||
// Spawn a job thread that will listen for and execute inputs.
|
||||
let handle = thread::spawn(move || exec::job(rx, cmd));
|
||||
let handle = thread::spawn(move || exec::job(rx, base, cmd));
|
||||
|
||||
// Push the handle of the spawned thread into the vector for later joining.
|
||||
handles.push(handle);
|
||||
|
|
Loading…
Reference in a new issue