diff --git a/Cargo.toml b/Cargo.toml index bd12c54..b7b3ade 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,6 @@ +[workspace] +members = ["cli", "."] + [package] authors = ["Gavin Panella "] categories = ["encoding", "filesystem"] diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 0000000..211cda9 --- /dev/null +++ b/cli/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "shell-quote-cli" +version = "0.1.0" +edition = "2021" + +[[bin]] +path = "src/main.rs" +name = "sq" + +[dependencies] +shell-quote = { path = ".." } + +[dependencies.clap] +version = "=4.5.9" +features = ["derive", "env", "wrap_help"] diff --git a/cli/src/main.rs b/cli/src/main.rs new file mode 100644 index 0000000..6a88ee9 --- /dev/null +++ b/cli/src/main.rs @@ -0,0 +1,36 @@ +use std::io::{self, IsTerminal, Read, Write}; + +use shell_quote::{Bash, Fish, Sh}; + +mod options; + +fn main() -> Result<(), Box> { + let options = ::parse(); + let quoted: Vec = if options.command.is_empty() && !io::stdin().is_terminal() { + let mut buf = Vec::new(); + io::stdin().read_to_end(&mut buf)?; + match options.shell { + options::Shell::Bash => Bash::quote_vec(&buf), + options::Shell::Fish => Fish::quote_vec(&buf), + options::Shell::Sh => Sh::quote_vec(&buf), + } + } else { + options + .command + .iter() + .fold(Vec::::new(), |mut acc, arg| { + if !acc.is_empty() { + acc.push(b' '); + } + match options.shell { + options::Shell::Bash => Bash::quote_into_vec(arg, &mut acc), + options::Shell::Fish => Fish::quote_into_vec(arg, &mut acc), + options::Shell::Sh => Sh::quote_into_vec(arg, &mut acc), + }; + acc + }) + }; + io::stdout().write_all("ed)?; + + Ok(()) +} diff --git a/cli/src/options.rs b/cli/src/options.rs new file mode 100644 index 0000000..23e66a3 --- /dev/null +++ b/cli/src/options.rs @@ -0,0 +1,35 @@ +use std::ffi::OsString; + +use clap::{command, Parser, ValueEnum, ValueHint}; + +#[derive(Parser, Debug)] +#[command( + author, version, about, long_about = None, max_term_width = 80, +)] +pub struct Options { + #[arg( + short = 's', + long = "shell", + help = "The shell for which to quote arguments.", + value_hint = ValueHint::ExecutablePath, + value_enum, + env = "SHELL", + )] + pub shell: Shell, + + #[arg( + help = "The arguments to quote. When none are provided, reads from stdin.", + trailing_var_arg = true, + allow_hyphen_values = true + )] + pub command: Vec, +} + +#[derive(Debug, Clone, ValueEnum)] +pub enum Shell { + #[value(alias = "zsh")] + Bash, + Fish, + #[value(alias = "dash")] + Sh, +}