From aa1b27280e62f934ca804768fb4728f60d1bd69c Mon Sep 17 00:00:00 2001 From: Austen Adler Date: Sat, 29 Jan 2022 10:23:25 -0500 Subject: [PATCH 1/4] Improve main.rs fifos --- README.adoc | 3 +- src/main.rs | 109 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 71 insertions(+), 41 deletions(-) diff --git a/README.adoc b/README.adoc index cd4cdcb..b4e5675 100644 --- a/README.adoc +++ b/README.adoc @@ -47,7 +47,8 @@ define-command sort-selections -params 0.. %{ # TODO: Send additional parameters - rust-selection-sort -R "$regex" $args -- "$@" > "$kak_command_fifo" + rust-selection-sort -R "$regex" -f "$kak_command_fifo" -- "$@" + } exec R } diff --git a/src/main.rs b/src/main.rs index c0a9513..4057ef0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,29 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)] +mod errors; use alphanumeric_sort::compare_str; use clap::Parser; +use errors::KakMessage; use regex::Regex; +use std::env; +use std::fs; +use std::fs::File; +use std::fs::OpenOptions; +use std::io::Write; -struct KakMessage(String, Option); - -#[derive(Parser)] +#[derive(Parser, Debug)] #[clap(about, version, author)] struct Options { + // TODO: Allow clap to parse these. Currently clap treats them as positional + // #[clap(env = "kak_command_fifo", takes_value = false)] + // kak_command_fifo_name: PathBuf, + // #[clap(env = "kak_response_fifo", takes_value = false)] + // kak_response_fifo_name: PathBuf, + #[clap(index = 1)] + regex: String, #[clap(short = 'S', long)] // TODO: Can we invert a boolean? This name is terrible no_skip_whitespace: bool, - #[clap(short = 'R', long, required = true)] - regex: String, - #[clap(multiple_occurrences = true, required = true)] - selections: Vec, #[clap(short, long)] lexicographic_sort: bool, #[clap(short, long)] @@ -31,29 +39,36 @@ fn main() { fn send_message(msg: &KakMessage) { // TODO: This isn't echoing anything - let msg_str = msg.0.replace('\'', "''"); - print!("echo '{}';", msg_str); + eprintln!("{} (Debug info: {:?})", msg.0, msg.1); - if let Some(debug_info) = &msg.1 { - print!("echo -debug '{}';", msg_str); - print!("echo -debug '{}';", debug_info.replace('\'', "''")); + let msg_str = msg.0.replace('\'', "''"); + let mut f = open_command_fifo().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(); } } fn run() -> Result<(), KakMessage> { - let options = Options::try_parse()?; + let options = Options::try_parse().map_err(|e| { + KakMessage( + "Error parsing arguments".to_string(), + Some(format!("Could not parse: {:?}", e)), + ) + })?; - let replacement_re = options.regex; + let re = Regex::new(&options.regex) + .map_err(|_| format!("Invalid regular expression: {}", options.regex))?; - let re = Regex::new(&replacement_re) - .map_err(|_| format!("Invalid regular expression: {}", replacement_re))?; + let selections = read_selections()?; - let mut zipped = options - .selections + let mut zipped = selections .iter() .zip( - options - .selections + selections .iter() .map(|a| { if options.no_skip_whitespace { @@ -83,7 +98,9 @@ fn run() -> Result<(), KakMessage> { } }); - print!("reg '\"'"); + let mut f = open_command_fifo()?; + + write!(f, "reg '\"'")?; let iter: Box> = if options.reverse { Box::new(zipped.iter().rev()) @@ -93,32 +110,44 @@ fn run() -> Result<(), KakMessage> { for i in iter { let new_selection = i.0.replace('\'', "''"); - print!(" '{}'", new_selection); + write!(f, " '{}'", new_selection)?; } - print!(" ;"); + write!(f, " ;")?; + Ok(()) } -impl From for KakMessage { - fn from(err: std::io::Error) -> Self { - Self( - "Error writing to fifo".to_string(), - Some(format!("{:?}", err)), - ) +fn read_selections() -> Result, KakMessage> { + { + let mut f = open_command_fifo()?; + + write!( + f, + "echo -quoting shell -to-file {} -- %val{{selections}}", + get_var("kak_response_fifo")? + )?; } + + let selections = shellwords::split(&fs::read_to_string(&get_var("kak_response_fifo")?)?)?; + + Ok(selections) } -impl From for KakMessage { - fn from(err: clap::Error) -> Self { - Self( - "Error parsing arguments".to_string(), - Some(format!("{:?}", err)), // Some(err.message.pieces.map(|p| p.0).join()), - ) - } +fn open_command_fifo() -> Result { + OpenOptions::new() + .write(true) + .append(true) + .open(&get_var("kak_command_fifo")?) + .map_err(|e| e.into()) } -impl From for KakMessage { - fn from(err: String) -> Self { - Self(err, None) - } +fn get_var(var_name: &str) -> Result { + env::var(var_name).map_err(|e| match e { + env::VarError::NotPresent => { + KakMessage(format!("Env var {} is not defined", var_name), None) + } + env::VarError::NotUnicode(_) => { + KakMessage(format!("Env var {} is not unicode", var_name), None) + } + }) } From 60d32a89a64b2cf92d747aa72bd45bcba8b1780d Mon Sep 17 00:00:00 2001 From: Austen Adler Date: Sat, 29 Jan 2022 10:23:54 -0500 Subject: [PATCH 2/4] Split out errors --- Cargo.lock | 11 +++++++++++ Cargo.toml | 3 ++- src/errors.rs | 23 ++++++++++++++++++++++ src/main.rs | 54 +++++++++++++++++++++++++++++++++------------------ 4 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 src/errors.rs 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> { From 9dea39b30ac1621e83c05ced836c48b34a27e653 Mon Sep 17 00:00:00 2001 From: Austen Adler Date: Sun, 30 Jan 2022 16:49:34 -0500 Subject: [PATCH 3/4] Try adding other size shrinking options --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 9cf7516..d9600af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,6 @@ shellwords = "1" [profile.release] lto = true opt-level = "z" +strip = true +codegen-units = 1 +panic = "abort" From 311327c12f1175e67e4031f2fe9387ffda911513 Mon Sep 17 00:00:00 2001 From: Austen Adler Date: Fri, 11 Feb 2022 22:02:19 -0500 Subject: [PATCH 4/4] Rename app --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e6694c7..2105c9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,6 +101,16 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "kakutils-rs" +version = "0.1.0" +dependencies = [ + "alphanumeric-sort", + "clap", + "regex", + "shellwords", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -187,16 +197,6 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" -[[package]] -name = "rust-selection-sort" -version = "0.1.0" -dependencies = [ - "alphanumeric-sort", - "clap", - "regex", - "shellwords", -] - [[package]] name = "shellwords" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index d9600af..ae02e87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rust-selection-sort" +name = "kakutils-rs" version = "0.1.0" edition = "2021" license = "MIT"