Rename so that prefixes are not repeated

This commit is contained in:
Austen Adler 2022-03-06 21:28:16 -05:00
parent 9761e5c0c5
commit 1780b2a60d
5 changed files with 111 additions and 41 deletions

View File

@ -1,21 +1,27 @@
#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)] // Enable clippy 'hard mode'
#![warn(clippy::all, clippy::pedantic, clippy::nursery)]
// Intended behavior (10_f64 as i32)
#![allow(clippy::cast_possible_truncation)]
// Cannot be fixed
#![allow(clippy::multiple_crate_versions)]
#![allow(clippy::struct_excessive_bools)]
// #![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
// #![allow(dead_code, unused_imports)] // #![allow(dead_code, unused_imports)]
mod errors; mod errors;
mod math_eval;
mod shuf; mod shuf;
mod sort; mod sort;
mod uniq; mod uniq;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use errors::KakMessage; use errors::KakMessage;
use shuf::ShufOptions;
use sort::SortOptions;
use std::{ use std::{
env, fs, env, fs,
fs::{File, OpenOptions}, fs::{File, OpenOptions},
io::Write, io::Write,
str::FromStr, str::FromStr,
}; };
use uniq::UniqOptions;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[clap(about, version, author)] #[clap(about, version, author)]
@ -31,9 +37,11 @@ struct Cli {
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum Commands { enum Commands {
Sort(SortOptions), Sort(sort::Options),
Shuf(ShufOptions), Shuf(shuf::Options),
Uniq(UniqOptions), Uniq(uniq::Options),
#[clap(visible_aliases = &["bc", "eval"])]
MathEval(math_eval::Options),
} }
#[derive(PartialEq, PartialOrd, Ord, Eq, Debug)] #[derive(PartialEq, PartialOrd, Ord, Eq, Debug)]
@ -102,7 +110,7 @@ impl SelectionDesc {
let sorted_a = self.sort(); let sorted_a = self.sort();
let sorted_b = b.sort(); let sorted_b = b.sort();
sorted_b.left >= sorted_a.left && sorted_b.right <= sorted_b.right sorted_b.left >= sorted_a.left && sorted_b.right <= sorted_a.right
} }
} }
@ -114,7 +122,7 @@ fn main() {
eprintln!( eprintln!(
"{} (Debug info: {})", "{} (Debug info: {})",
msg.0, msg.0,
msg.1.as_ref().unwrap_or(&String::default()) msg.1.as_ref().map_or("", String::as_str)
); );
msg msg
} }
@ -150,9 +158,10 @@ fn run() -> Result<KakMessage, KakMessage> {
})?; })?;
match &options.command { match &options.command {
Commands::Sort(sort_options) => sort::sort(sort_options), Commands::Sort(o) => sort::sort(o),
Commands::Shuf(shuf_options) => shuf::shuf(shuf_options), Commands::Shuf(o) => shuf::shuf(o),
Commands::Uniq(uniq_options) => uniq::uniq(uniq_options), Commands::Uniq(o) => uniq::uniq(o),
Commands::MathEval(o) => math_eval::math_eval(o),
} }
} }
@ -195,21 +204,38 @@ pub fn get_var(var_name: &str) -> Result<String, KakMessage> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
const sd: SelectionDesc = SelectionDesc {
left: AnchorPosition { row: 18, col: 9 },
right: AnchorPosition { row: 10, col: 1 },
};
#[test] #[test]
fn test_anchor_position() { fn test_anchor_position() {
let sd = SelectionDesc { // let sd = SelectionDesc {
left: AnchorPosition { row: 18, col: 9 }, // left: AnchorPosition { row: 18, col: 9 },
right: AnchorPosition { row: 10, col: 0 }, // right: AnchorPosition { row: 10, col: 0 },
}; // };
// Check parsing // Check parsing
assert_eq!(SelectionDesc::from_str("18.9,10.0").unwrap(), sd); assert_eq!(SelectionDesc::from_str("18.9,10.1").unwrap(), sd);
// Check if multiple parsed ones match // Check if multiple parsed ones match
assert_eq!( assert_eq!(
SelectionDesc::from_str("18.9,10.0").unwrap(), SelectionDesc::from_str("18.9,10.1").unwrap(),
SelectionDesc::from_str("18.9,10.0").unwrap() SelectionDesc::from_str("18.9,10.1").unwrap()
); );
// Check if sorting works // Check if sorting works
assert_eq!(sd.sort(), SelectionDesc::from_str("10.0,18.9").unwrap()); assert_eq!(sd.sort(), SelectionDesc::from_str("10.1,18.9").unwrap());
assert_eq!(sd.sort(), sd.sort().sort()); assert_eq!(sd.sort(), sd.sort().sort());
} }
#[test]
fn test_contains() {
assert_true!(sd.contains(sd));
assert_false!(sd.contains(SelectionDesc::from_str("17.9,10.1").unwrap()))
assert_false!(sd.contains(SelectionDesc::from_str("18.8,10.1").unwrap()))
assert_false!(sd.contains(SelectionDesc::from_str("18.9,11.1").unwrap()))
assert_false!(sd.contains(SelectionDesc::from_str("18.9,10.2").unwrap()))
assert_true!(sd.contains(SelectionDesc::from_str("19.9,10.1").unwrap()))
assert_true!(sd.contains(SelectionDesc::from_str("18.10,10.1").unwrap()))
assert_true!(sd.contains(SelectionDesc::from_str("18.9,9.1").unwrap()))
assert_true!(sd.contains(SelectionDesc::from_str("18.9,10.0").unwrap()))
}
} }

44
src/math_eval.rs Normal file
View File

@ -0,0 +1,44 @@
use crate::{kak_response, open_command_fifo, KakMessage};
use evalexpr::{eval, Value};
use std::io::Write;
#[derive(clap::StructOpt, Debug)]
pub struct Options;
pub fn math_eval(_options: &Options) -> Result<KakMessage, KakMessage> {
let selections = kak_response("%val{selections}")?;
let mut f = open_command_fifo()?;
write!(f, "reg '\"'")?;
let mut err = None;
let mut err_count: usize = 0;
for i in selections.iter().map(|s| {
// TODO: Do all of these need to be strings?
match eval(s) {
Ok(Value::Float(f)) => Some(f.to_string()),
Ok(Value::Int(f)) => Some(f.to_string()),
// TODO: Should this be none?
Ok(_) => None,
Err(e) => {
eprintln!("Error: {:?}", e);
if err.is_none() {
err = Some(e);
err_count = err_count.saturating_add(1);
}
None
}
}
}) {
// TODO: String allocation?
let new_selection = i.map(|s| s.replace('\'', "''"));
// .unwrap_or_else(|| "".to_string());
write!(f, " '{}'", new_selection.as_deref().unwrap_or(""))?;
}
write!(f, " ; exec R;")?;
Ok(KakMessage(
format!("MathEval {} selections", selections.len()),
None,
))
}

View File

@ -2,8 +2,8 @@ use crate::{kak_response, open_command_fifo, KakMessage};
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
use std::io::Write; use std::io::Write;
#[derive(clap::StructOpt, Debug)] #[derive(clap::StructOpt, Debug)]
pub struct ShufOptions; pub struct Options;
pub fn shuf(_shuf_options: &ShufOptions) -> Result<KakMessage, KakMessage> { pub fn shuf(_options: &Options) -> Result<KakMessage, KakMessage> {
let mut selections = kak_response("%val{selections}")?; let mut selections = kak_response("%val{selections}")?;
let mut rng = thread_rng(); let mut rng = thread_rng();
@ -12,7 +12,7 @@ pub fn shuf(_shuf_options: &ShufOptions) -> Result<KakMessage, KakMessage> {
let mut f = open_command_fifo()?; let mut f = open_command_fifo()?;
write!(f, "reg '\"'")?; write!(f, "reg '\"'")?;
for i in selections.iter() { for i in &selections {
let new_selection = i.replace('\'', "''"); let new_selection = i.replace('\'', "''");
write!(f, " '{}'", new_selection)?; write!(f, " '{}'", new_selection)?;
} }

View File

@ -4,7 +4,7 @@ use regex::Regex;
use std::{cmp::Ordering, io::Write, str::FromStr}; use std::{cmp::Ordering, io::Write, str::FromStr};
#[derive(clap::StructOpt, Debug)] #[derive(clap::StructOpt, Debug)]
pub struct SortOptions { pub struct Options {
#[clap(index = 1)] #[clap(index = 1)]
regex: Option<Regex>, regex: Option<Regex>,
#[clap(short = 's', long)] #[clap(short = 's', long)]
@ -40,7 +40,7 @@ struct SortableSelection<'a> {
/// Gets a Vec of sortable selections with a given list of subselections and descriptions /// Gets a Vec of sortable selections with a given list of subselections and descriptions
fn get_sortable_selections_subselections<'a, 'b, 'tmp, S: AsRef<str> + std::fmt::Debug + 'a>( fn get_sortable_selections_subselections<'a, 'b, 'tmp, S: AsRef<str> + std::fmt::Debug + 'a>(
sort_options: &'b SortOptions, options: &'b Options,
selections: &'a [S], selections: &'a [S],
selections_desc: &'tmp [S], selections_desc: &'tmp [S],
subselections: &'a [S], subselections: &'a [S],
@ -57,7 +57,7 @@ fn get_sortable_selections_subselections<'a, 'b, 'tmp, S: AsRef<str> + std::fmt:
.zip(selections_desc.iter()) .zip(selections_desc.iter())
.map(|(s, sd)| { .map(|(s, sd)| {
Ok(( Ok((
to_sortable_selection(s.as_ref(), sort_options), to_sortable_selection(s.as_ref(), options),
SelectionDesc::from_str(sd.as_ref())?, SelectionDesc::from_str(sd.as_ref())?,
)) ))
}) })
@ -80,7 +80,7 @@ fn get_sortable_selections_subselections<'a, 'b, 'tmp, S: AsRef<str> + std::fmt:
for (s, s_desc) in &mut sortable_selections { for (s, s_desc) in &mut sortable_selections {
for i in &subselections { for i in &subselections {
if s_desc.contains(&i.1) { if s_desc.contains(&i.1) {
s.subselections.push(i.0.clone()); s.subselections.push(i.0);
} }
} }
} }
@ -106,9 +106,9 @@ fn get_sortable_selections_subselections<'a, 'b, 'tmp, S: AsRef<str> + std::fmt:
fn to_sortable_selection<'a, 'b>( fn to_sortable_selection<'a, 'b>(
selection: &'a str, selection: &'a str,
sort_options: &'b SortOptions, options: &'b Options,
) -> SortableSelection<'a> { ) -> SortableSelection<'a> {
if sort_options.no_skip_whitespace { if options.no_skip_whitespace {
SortableSelection { SortableSelection {
content: selection, content: selection,
content_comparison: selection, content_comparison: selection,
@ -123,10 +123,10 @@ fn to_sortable_selection<'a, 'b>(
} }
} }
pub fn sort(sort_options: &SortOptions) -> Result<KakMessage, KakMessage> { pub fn sort(options: &Options) -> Result<KakMessage, KakMessage> {
eprintln!("Got sort options: {:?}", sort_options); eprintln!("Got sort options: {:?}", options);
let subselections: Option<(Vec<String>, Vec<String>)> = sort_options let subselections: Option<(Vec<String>, Vec<String>)> = options
.subselections_register .subselections_register
.map::<Result<(Vec<String>, Vec<String>), KakMessage>, _>(|_c| { .map::<Result<(Vec<String>, Vec<String>), KakMessage>, _>(|_c| {
let subselections = kak_response("%val{selections}")?; let subselections = kak_response("%val{selections}")?;
@ -142,7 +142,7 @@ pub fn sort(sort_options: &SortOptions) -> Result<KakMessage, KakMessage> {
let selections_desc = kak_response("%val{selections_desc}")?; let selections_desc = kak_response("%val{selections_desc}")?;
get_sortable_selections_subselections( get_sortable_selections_subselections(
sort_options, options,
&selections, &selections,
&selections_desc, &selections_desc,
subselections, subselections,
@ -151,13 +151,13 @@ pub fn sort(sort_options: &SortOptions) -> Result<KakMessage, KakMessage> {
} }
None => selections None => selections
.iter() .iter()
.map(|s| to_sortable_selection(s, sort_options)) .map(|s| to_sortable_selection(s, options))
.collect(), .collect(),
}; };
zipped.sort_by(|a, b| { zipped.sort_by(|a, b| {
for (a_subselection, b_subselection) in a.subselections.iter().zip(b.subselections.iter()) { for (a_subselection, b_subselection) in a.subselections.iter().zip(b.subselections.iter()) {
let comparison = if sort_options.lexicographic_sort { let comparison = if options.lexicographic_sort {
a_subselection.cmp(b_subselection) a_subselection.cmp(b_subselection)
} else { } else {
compare_str(a_subselection, b_subselection) compare_str(a_subselection, b_subselection)
@ -168,7 +168,7 @@ pub fn sort(sort_options: &SortOptions) -> Result<KakMessage, KakMessage> {
} }
} }
if sort_options.lexicographic_sort { if options.lexicographic_sort {
a.content_comparison.cmp(b.content_comparison) a.content_comparison.cmp(b.content_comparison)
} else { } else {
compare_str(a.content_comparison, b.content_comparison) compare_str(a.content_comparison, b.content_comparison)
@ -179,7 +179,7 @@ pub fn sort(sort_options: &SortOptions) -> Result<KakMessage, KakMessage> {
write!(f, "reg '\"'")?; write!(f, "reg '\"'")?;
let iter: Box<dyn Iterator<Item = _>> = if sort_options.reverse { let iter: Box<dyn Iterator<Item = _>> = if options.reverse {
Box::new(zipped.iter().rev()) Box::new(zipped.iter().rev())
} else { } else {
Box::new(zipped.iter()) Box::new(zipped.iter())

View File

@ -4,27 +4,27 @@ use std::{
io::Write, io::Write,
}; };
#[derive(clap::StructOpt, Debug)] #[derive(clap::StructOpt, Debug)]
pub struct UniqOptions { pub struct Options {
#[clap(short, long)] #[clap(short, long)]
ignore_case: bool, ignore_case: bool,
// TODO: Can we invert a boolean? This name is terrible // TODO: Can we invert a boolean? This name is terrible
#[clap(short = 'S', long)] #[clap(short = 'S', long)]
no_skip_whitespace: bool, no_skip_whitespace: bool,
} }
pub fn uniq(uniq_options: &UniqOptions) -> Result<KakMessage, KakMessage> { pub fn uniq(options: &Options) -> Result<KakMessage, KakMessage> {
let selections = kak_response("%val{selections}")?; let selections = kak_response("%val{selections}")?;
let mut f = open_command_fifo()?; let mut f = open_command_fifo()?;
write!(f, "reg '\"'")?; write!(f, "reg '\"'")?;
for i in selections.iter().scan(HashMap::new(), |state, s| { for i in selections.iter().scan(HashMap::new(), |state, s| {
let key = if uniq_options.no_skip_whitespace { let key = if options.no_skip_whitespace {
s s
} else { } else {
s.trim() s.trim()
}; };
let key = if uniq_options.ignore_case { let key = if options.ignore_case {
key.to_lowercase() key.to_lowercase()
} else { } else {
// TODO: Do I really need to clone this? // TODO: Do I really need to clone this?