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) + } + }) }