diff --git a/Cargo.lock b/Cargo.lock index d5a02db..e6694c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -194,6 +194,17 @@ dependencies = [ "alphanumeric-sort", "clap", "regex", + "shellwords", +] + +[[package]] +name = "shellwords" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e515aa4699a88148ed5ef96413ceef0048ce95b43fbc955a33bde0a70fcae6" +dependencies = [ + "lazy_static", + "regex", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 913870c..9cf7516 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,9 @@ keywords = ["cli", "kakoune"] [dependencies] regex = "1" -clap = {version = "3", features = ["derive"]} +clap = {version = "3", features = ["derive", "env"]} alphanumeric-sort = "1" +shellwords = "1" [profile.release] lto = true diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..8380318 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,23 @@ +#[derive(Debug)] +pub struct KakMessage(pub String, pub Option); + +impl From for KakMessage { + fn from(err: std::io::Error) -> Self { + Self( + "Error writing to fifo".to_string(), + Some(format!("{:?}", err)), + ) + } +} + +impl From for KakMessage { + fn from(err: String) -> Self { + Self(err, None) + } +} + +impl From for KakMessage { + fn from(err: shellwords::MismatchedQuotes) -> Self { + Self("Corrupt kak response".to_string(), Some(err.to_string())) + } +} diff --git a/src/main.rs b/src/main.rs index 4057ef0..8d718ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,7 @@ struct Options { // #[clap(env = "kak_response_fifo", takes_value = false)] // kak_response_fifo_name: PathBuf, #[clap(index = 1)] - regex: String, + regex: Option, #[clap(short = 'S', long)] // TODO: Can we invert a boolean? This name is terrible no_skip_whitespace: bool, @@ -31,28 +31,32 @@ struct Options { } fn main() { - match run() { - Ok(()) => send_message(&KakMessage("Replaced successfully".to_string(), None)), - Err(msg) => send_message(&msg), - } + let msg = match run() { + Ok(msg) => msg, + Err(msg) => { + eprintln!("{} (Debug info: {:?})", msg.0, msg.1); + msg + } + }; + + send_message(&msg); } fn send_message(msg: &KakMessage) { - // TODO: This isn't echoing anything - eprintln!("{} (Debug info: {:?})", msg.0, msg.1); - let msg_str = msg.0.replace('\'', "''"); - let mut f = open_command_fifo().unwrap(); + { + let mut f = open_command_fifo().unwrap(); - write!(f, "echo '{}';", msg_str).unwrap(); - write!(f, "echo -debug '{}';", msg_str).unwrap(); + write!(f, "echo '{}';", msg_str).unwrap(); + write!(f, "echo -debug '{}';", msg_str).unwrap(); - if let Some(debug_msg_str) = &msg.1 { - write!(f, "echo -debug '{}';", debug_msg_str.replace('\'', "''")).unwrap(); + if let Some(debug_msg_str) = &msg.1 { + write!(f, "echo -debug '{}';", debug_msg_str.replace('\'', "''")).unwrap(); + } } } -fn run() -> Result<(), KakMessage> { +fn run() -> Result { let options = Options::try_parse().map_err(|e| { KakMessage( "Error parsing arguments".to_string(), @@ -60,8 +64,17 @@ fn run() -> Result<(), KakMessage> { ) })?; - let re = Regex::new(&options.regex) - .map_err(|_| format!("Invalid regular expression: {}", options.regex))?; + let re = options + .regex + .as_ref() + .map(|r| Regex::new(r)) + .transpose() + .map_err(|_| { + format!( + "Invalid regular expression: {}", + options.regex.unwrap_or("".to_string()) + ) + })?; let selections = read_selections()?; @@ -78,7 +91,7 @@ fn run() -> Result<(), KakMessage> { } }) .map(|a| { - let captures = re.captures(a)?; + let captures = re.as_ref()?.captures(a)?; captures .get(1) .or_else(|| captures.get(0)) @@ -112,9 +125,12 @@ fn run() -> Result<(), KakMessage> { let new_selection = i.0.replace('\'', "''"); write!(f, " '{}'", new_selection)?; } - write!(f, " ;")?; + write!(f, " ; exec R;")?; - Ok(()) + Ok(KakMessage( + format!("Sorted {} selections", selections.len()), + None, + )) } fn read_selections() -> Result, KakMessage> {