Rename TokenizedCommand to CommandTemplate

This commit is contained in:
Matthias Reitinger 2017-11-15 02:14:04 +01:00 committed by David Peter
parent c18caaa6f6
commit 0f82fe7ec0
4 changed files with 61 additions and 66 deletions

View file

@ -10,16 +10,12 @@ use std::path::PathBuf;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
use super::TokenizedCommand; use super::CommandTemplate;
/// An event loop that listens for inputs from the `rx` receiver. Each received input will /// 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 /// 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. /// be executed, and this process will continue until the receiver's sender has closed.
pub fn job( pub fn job(rx: Arc<Mutex<Receiver<PathBuf>>>, cmd: Arc<CommandTemplate>, out_perm: Arc<Mutex<()>>) {
rx: Arc<Mutex<Receiver<PathBuf>>>,
cmd: Arc<TokenizedCommand>,
out_perm: Arc<Mutex<()>>,
) {
loop { loop {
// Create a lock on the shared receiver for this thread. // Create a lock on the shared receiver for this thread.
let lock = rx.lock().unwrap(); let lock = rx.lock().unwrap();

View file

@ -24,52 +24,17 @@ use self::command::execute_command;
use self::token::Token; use self::token::Token;
pub use self::job::job; pub use self::job::job;
/// Contains a collection of `TokenizedArgument`s that are utilized to generate command strings. /// Represents a template that is utilized to generate command strings.
/// ///
/// The arguments are a representation of the supplied command template, and are meant to be coupled /// The template is meant to be coupled with an input in order to generate a command. The
/// with an input in order to generate a command. The `generate_and_execute()` method will be used /// `generate_and_execute()` method will be used to generate a command and execute it.
/// to generate a command and execute it.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct TokenizedCommand { pub struct CommandTemplate {
args: Vec<TokenizedArgument>, args: Vec<ArgumentTemplate>,
} }
/// Represents a single command argument. impl CommandTemplate {
/// pub fn new<I, S>(input: I) -> CommandTemplate
/// The argument is either a collection of `Token`s including at least one placeholder variant,
/// or a fixed text.
#[derive(Clone, Debug, PartialEq)]
enum TokenizedArgument {
Tokens(Vec<Token>),
Text(String),
}
impl TokenizedArgument {
pub fn generate<'a>(&'a self, path: &str) -> Cow<'a, str> {
use self::Token::*;
match *self {
TokenizedArgument::Tokens(ref tokens) => {
let mut s = String::new();
for token in tokens {
match *token {
Basename => s += basename(path),
BasenameNoExt => s += remove_extension(basename(path)),
NoExt => s += remove_extension(path),
Parent => s += dirname(path),
Placeholder => s += path,
Text(ref string) => s += string,
}
}
Cow::Owned(s)
}
TokenizedArgument::Text(ref text) => Cow::Borrowed(text),
}
}
}
impl TokenizedCommand {
pub fn new<I, S>(input: I) -> TokenizedCommand
where where
I: IntoIterator<Item = S>, I: IntoIterator<Item = S>,
S: AsRef<str>, S: AsRef<str>,
@ -109,7 +74,7 @@ impl TokenizedCommand {
// Without a placeholder, the argument is just fixed text. // Without a placeholder, the argument is just fixed text.
if tokens.is_empty() { if tokens.is_empty() {
args.push(TokenizedArgument::Text(arg.to_owned())); args.push(ArgumentTemplate::Text(arg.to_owned()));
continue; continue;
} }
@ -118,15 +83,15 @@ impl TokenizedCommand {
tokens.push(Token::Text(arg[start..].to_owned())); tokens.push(Token::Text(arg[start..].to_owned()));
} }
args.push(TokenizedArgument::Tokens(tokens)); args.push(ArgumentTemplate::Tokens(tokens));
} }
// If a placeholder token was not supplied, append one at the end of the command. // If a placeholder token was not supplied, append one at the end of the command.
if !has_placeholder { if !has_placeholder {
args.push(TokenizedArgument::Tokens(vec![Token::Placeholder])); args.push(ArgumentTemplate::Tokens(vec![Token::Placeholder]));
} }
TokenizedCommand { args: args } CommandTemplate { args: args }
} }
/// Generates and executes a command. /// Generates and executes a command.
@ -149,28 +114,62 @@ impl TokenizedCommand {
} }
} }
/// Represents a template for a single command argument.
///
/// The argument is either a collection of `Token`s including at least one placeholder variant, or
/// a fixed text.
#[derive(Clone, Debug, PartialEq)]
enum ArgumentTemplate {
Tokens(Vec<Token>),
Text(String),
}
impl ArgumentTemplate {
pub fn generate<'a>(&'a self, path: &str) -> Cow<'a, str> {
use self::Token::*;
match *self {
ArgumentTemplate::Tokens(ref tokens) => {
let mut s = String::new();
for token in tokens {
match *token {
Basename => s += basename(path),
BasenameNoExt => s += remove_extension(basename(path)),
NoExt => s += remove_extension(path),
Parent => s += dirname(path),
Placeholder => s += path,
Text(ref string) => s += string,
}
}
Cow::Owned(s)
}
ArgumentTemplate::Text(ref text) => Cow::Borrowed(text),
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{TokenizedCommand, TokenizedArgument, Token}; use super::{CommandTemplate, ArgumentTemplate, Token};
#[test] #[test]
fn tokens() { fn tokens() {
let expected = TokenizedCommand { let expected = CommandTemplate {
args: vec![ args: vec![
TokenizedArgument::Text("echo".into()), ArgumentTemplate::Text("echo".into()),
TokenizedArgument::Text("${SHELL}:".into()), ArgumentTemplate::Text("${SHELL}:".into()),
TokenizedArgument::Tokens(vec![Token::Placeholder]), ArgumentTemplate::Tokens(vec![Token::Placeholder]),
], ],
}; };
assert_eq!(TokenizedCommand::new(&[&"echo", &"${SHELL}:"]), expected); assert_eq!(CommandTemplate::new(&[&"echo", &"${SHELL}:"]), expected);
assert_eq!( assert_eq!(
TokenizedCommand::new(&["echo", "{.}"]), CommandTemplate::new(&["echo", "{.}"]),
TokenizedCommand { CommandTemplate {
args: vec![ args: vec![
TokenizedArgument::Text("echo".into()), ArgumentTemplate::Text("echo".into()),
TokenizedArgument::Tokens(vec![Token::NoExt]), ArgumentTemplate::Tokens(vec![Token::NoExt]),
], ],
} }
); );

View file

@ -10,7 +10,7 @@ use std::process;
use std::time; use std::time;
use std::io::Write; use std::io::Write;
use exec::TokenizedCommand; use exec::CommandTemplate;
use lscolors::LsColors; use lscolors::LsColors;
use walk::FileType; use walk::FileType;
use regex_syntax::{Expr, ExprBuilder}; use regex_syntax::{Expr, ExprBuilder};
@ -76,7 +76,7 @@ pub struct FdOptions {
pub extension: Option<String>, pub extension: Option<String>,
/// If a value is supplied, each item found will be used to generate and execute commands. /// If a value is supplied, each item found will be used to generate and execute commands.
pub command: Option<TokenizedCommand>, pub command: Option<CommandTemplate>,
/// A list of glob patterns that should be excluded from the search. /// A list of glob patterns that should be excluded from the search.
pub exclude_patterns: Vec<String>, pub exclude_patterns: Vec<String>,

View file

@ -39,7 +39,7 @@ use std::time;
use atty::Stream; use atty::Stream;
use regex::RegexBuilder; use regex::RegexBuilder;
use exec::TokenizedCommand; use exec::CommandTemplate;
use internal::{error, pattern_has_uppercase_char, FdOptions, PathDisplay}; use internal::{error, pattern_has_uppercase_char, FdOptions, PathDisplay};
use lscolors::LsColors; use lscolors::LsColors;
use walk::FileType; use walk::FileType;
@ -105,7 +105,7 @@ fn main() {
None None
}; };
let command = matches.values_of("exec").map(TokenizedCommand::new); let command = matches.values_of("exec").map(CommandTemplate::new);
let config = FdOptions { let config = FdOptions {
case_sensitive, case_sensitive,