Rename so that prefixes are not repeated
This commit is contained in:
parent
9761e5c0c5
commit
1780b2a60d
66
src/main.rs
66
src/main.rs
@ -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
44
src/math_eval.rs
Normal 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,
|
||||||
|
))
|
||||||
|
}
|
@ -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)?;
|
||||||
}
|
}
|
||||||
|
28
src/sort.rs
28
src/sort.rs
@ -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())
|
||||||
|
@ -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?
|
||||||
|
Loading…
Reference in New Issue
Block a user