Add xlookup

This commit is contained in:
Austen Adler 2022-09-06 00:28:00 -04:00
parent 3660a35923
commit 6745a8ad5b
6 changed files with 111 additions and 21 deletions

View File

@ -1,4 +1,4 @@
use std::num::ParseIntError; use std::{fmt, fmt::Display, num::ParseIntError};
#[derive(Debug)] #[derive(Debug)]
pub enum KakError { pub enum KakError {
@ -16,10 +16,14 @@ pub enum KakError {
NotImplemented(&'static str), NotImplemented(&'static str),
/// Custom error string /// Custom error string
Custom(String), Custom(String),
/// Custom static error string
CustomStatic(&'static str),
/// The selections/selections_desc list passed was empty /// The selections/selections_desc list passed was empty
SetEmptySelections, SetEmptySelections,
} }
impl std::error::Error for KakError {}
impl KakError { impl KakError {
pub fn details(&self) -> String { pub fn details(&self) -> String {
match self { match self {
@ -30,6 +34,7 @@ impl KakError {
Self::Io(e) => format!("{e:?}"), Self::Io(e) => format!("{e:?}"),
Self::NotImplemented(e) => e.to_string(), Self::NotImplemented(e) => e.to_string(),
Self::Custom(s) => s.clone(), Self::Custom(s) => s.clone(),
Self::CustomStatic(s) => s.to_string(),
Self::SetEmptySelections => { Self::SetEmptySelections => {
String::from("Attempted to set selections/selections_desc to empty list") String::from("Attempted to set selections/selections_desc to empty list")
} }
@ -37,22 +42,23 @@ impl KakError {
} }
} }
impl ToString for KakError { impl Display for KakError {
fn to_string(&self) -> String { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
format!( write!(f, "Error: ")?;
"Error: {}", match self {
match self { Self::EnvVarNotSet(_) => write!(f, "env var not set"),
Self::EnvVarNotSet(_) => "env var not set", Self::EnvVarUnicode(_) => write!(f, "env var not unicode"),
Self::EnvVarUnicode(_) => "env var not unicode", Self::Parse(_) => write!(f, "Could not parse"),
Self::Parse(_) => "Could not parse", Self::KakResponse(_) => write!(f, "Invalid kak response"),
Self::KakResponse(_) => "Invalid kak response", Self::Io(_) => write!(f, "IO error"),
Self::Io(_) => "IO error", Self::NotImplemented(_) => write!(f, "Not Implemented"),
Self::NotImplemented(_) => "Not Implemented", Self::Custom(s) => write!(f, "{}", s),
Self::Custom(s) => s, Self::CustomStatic(s) => write!(f, "{}", s),
Self::SetEmptySelections => Self::SetEmptySelections => write!(
"Attempted to set selections/selections_desc to empty list", f,
} "Attempted to set selections/selections_desc to empty list"
) ),
}
} }
} }

View File

@ -325,7 +325,7 @@ impl FromStr for AnchorPosition {
} }
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Register { pub enum Register {
Numeric0, Numeric0,
Numeric1, Numeric1,

View File

@ -40,11 +40,12 @@ pub fn incr(options: &Options, should_increment: bool) -> Result<String, KakErro
) )
} else { } else {
format!( format!(
"{} {} selections by {} ({} errors)", "{} {} selections by {} ({} error{})",
if should_increment { "Incr" } else { "Decr" }, if should_increment { "Incr" } else { "Decr" },
selections.len().saturating_sub(err_count), selections.len().saturating_sub(err_count),
options.amount, options.amount,
err_count, err_count,
if err_count == 1 { "" } else { "s" }
) )
}) })
} }

View File

@ -9,6 +9,7 @@
#![allow(dead_code, unused_imports)] #![allow(dead_code, unused_imports)]
#![feature(slice_group_by)] #![feature(slice_group_by)]
#![feature(slice_take)] #![feature(slice_take)]
#![feature(array_chunks)]
mod box_; mod box_;
mod errors; mod errors;
@ -22,6 +23,7 @@ mod stdin;
mod trim; mod trim;
mod uniq; mod uniq;
mod utils; mod utils;
mod xlookup;
// mod xargs; // mod xargs;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use kakplugin::{display_message, get_var, KakError}; use kakplugin::{display_message, get_var, KakError};
@ -63,7 +65,11 @@ enum Commands {
Stdin(stdin::Options), Stdin(stdin::Options),
#[clap(about = "Make boxes out of selections", visible_aliases = &["square"])] #[clap(about = "Make boxes out of selections", visible_aliases = &["square"])]
Box_(box_::Options), Box_(box_::Options),
#[clap(about = "Map selections based on a register", visible_aliases = &["vlookup"])]
Xlookup(xlookup::Options),
#[clap(about = "Increment selections")]
Decr(incr::Options), Decr(incr::Options),
#[clap(about = "Decrement selections")]
Incr(incr::Options), Incr(incr::Options),
} }
@ -114,6 +120,7 @@ fn run() -> Result<String, KakError> {
// Commands::Xargs(o) => xargs::xargs(o), // Commands::Xargs(o) => xargs::xargs(o),
Commands::Stdin(o) => stdin::stdin(o), Commands::Stdin(o) => stdin::stdin(o),
Commands::Box_(o) => box_::box_(o), Commands::Box_(o) => box_::box_(o),
Commands::Xlookup(o) => xlookup::xlookup(o),
Commands::Incr(o) => incr::incr(o, true), Commands::Incr(o) => incr::incr(o, true),
Commands::Decr(o) => incr::incr(o, false), Commands::Decr(o) => incr::incr(o, false),
} }

View File

@ -25,9 +25,10 @@ pub fn math_eval(_options: &Options) -> Result<String, KakError> {
format!("Processed {} selections", selections.len()) format!("Processed {} selections", selections.len())
} else { } else {
format!( format!(
"Processed {} selections ({} errors)", "Processed {} selections ({} error{})",
selections.len().saturating_sub(err_count), selections.len().saturating_sub(err_count),
err_count err_count,
if err_count == 1 { "" } else { "s" }
) )
}) })
} }

75
src/xlookup.rs Normal file
View File

@ -0,0 +1,75 @@
use crate::utils::get_hash;
use evalexpr::{eval, Value};
use kakplugin::{
get_selections, open_command_fifo, set_selections, types::Register, KakError, Selection,
};
use std::{
collections::{
btree_map::Entry::{Occupied, Vacant},
hash_map::DefaultHasher,
BTreeMap,
},
hash::{Hash, Hasher},
io::Write,
};
#[derive(clap::StructOpt, Debug)]
pub struct Options {
#[clap(help = "Register with the lookup table")]
register: Register,
}
pub fn xlookup(options: &Options) -> Result<String, KakError> {
let lookup_table = build_lookuptable(options.register)?;
eprintln!("Lookup table: {lookup_table:#?}");
let selections = get_selections(None)?;
let mut err_count: usize = 0;
set_selections(selections.iter().map(|key| {
match lookup_table.get(&get_hash(&key, false, None, false)) {
Some(v) => v.to_string(),
None => {
eprintln!(
"Nothing for '{key}' ({})",
get_hash(&key, false, None, false)
);
err_count += 1;
String::from("")
}
}
}))?;
Ok(if err_count == 0 {
format!("Xlookup {} selections", selections.len())
} else {
format!(
"Xlookup {} selections ({} error{})",
selections.len().saturating_sub(err_count),
err_count,
if err_count == 1 { "" } else { "s" }
)
})
}
pub fn build_lookuptable(reg: Register) -> Result<BTreeMap<u64, Selection>, KakError> {
let mut selections = get_selections(Some(&format!("\"{reg}z")))?;
let mut iter = selections.array_chunks_mut();
let ret = iter.try_fold(BTreeMap::new(), |mut acc, [key, value]| {
match acc.entry(get_hash(&key, false, None, false)) {
Occupied(_) => Err(KakError::Custom(format!("Duplicate key '{key}'"))),
Vacant(v) => {
v.insert(value.to_owned());
Ok(acc)
}
}
})?;
if !iter.into_remainder().is_empty() {
Err(KakError::CustomStatic("Odd number of selections"))
} else if ret.is_empty() {
Err(KakError::CustomStatic("No selections"))
} else {
Ok(ret)
}
}