Add set command
This commit is contained in:
parent
ec3c685a16
commit
01a7063c22
17
Cargo.lock
generated
17
Cargo.lock
generated
@ -139,6 +139,8 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"evalexpr",
|
"evalexpr",
|
||||||
"kakplugin",
|
"kakplugin",
|
||||||
|
"linked-hash-map",
|
||||||
|
"linked_hash_set",
|
||||||
"rand",
|
"rand",
|
||||||
"regex",
|
"regex",
|
||||||
"shellwords",
|
"shellwords",
|
||||||
@ -156,6 +158,21 @@ version = "0.2.113"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9"
|
checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked-hash-map"
|
||||||
|
version = "0.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked_hash_set"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588"
|
||||||
|
dependencies = [
|
||||||
|
"linked-hash-map",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.4.1"
|
version = "2.4.1"
|
||||||
|
@ -39,6 +39,8 @@ shellwords = "1"
|
|||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
evalexpr = "7"
|
evalexpr = "7"
|
||||||
kakplugin = {path = "./kakplugin/"}
|
kakplugin = {path = "./kakplugin/"}
|
||||||
|
linked-hash-map = "0.5.4"
|
||||||
|
linked_hash_set = "0.1.4"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
mod errors;
|
mod errors;
|
||||||
mod types;
|
pub mod types;
|
||||||
pub use errors::KakError;
|
pub use errors::KakError;
|
||||||
use std::{
|
use std::{
|
||||||
env, fmt,
|
env,
|
||||||
fs::{self, File, OpenOptions},
|
fs::{self, File, OpenOptions},
|
||||||
io::{BufWriter, Write},
|
io::{BufWriter, Write},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
use types::Register;
|
||||||
pub use types::{
|
pub use types::{
|
||||||
AnchorPosition, Selection, SelectionDesc, SelectionWithDesc, SelectionWithSubselections,
|
AnchorPosition, Selection, SelectionDesc, SelectionWithDesc, SelectionWithSubselections,
|
||||||
};
|
};
|
||||||
@ -95,14 +96,14 @@ pub fn get_selections_with_desc() -> Result<Vec<SelectionWithDesc>, KakError> {
|
|||||||
pub fn set_selections<'a, I, S: 'a + ?Sized>(selections: I) -> Result<(), KakError>
|
pub fn set_selections<'a, I, S: 'a + ?Sized>(selections: I) -> Result<(), KakError>
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = &'a S>,
|
I: IntoIterator<Item = &'a S>,
|
||||||
S: AsRef<str> + fmt::Display,
|
S: AsRef<str>,
|
||||||
{
|
{
|
||||||
let mut f = open_command_fifo()?;
|
let mut f = open_command_fifo()?;
|
||||||
write!(f, "reg '\"'")?;
|
write!(f, "set-register '\"'")?;
|
||||||
for i in selections {
|
for i in selections {
|
||||||
write!(f, " '{}'", i.as_ref().replace('\'', "''"))?;
|
write!(f, " '{}'", escape(i))?;
|
||||||
}
|
}
|
||||||
write!(f, "; exec R;")?;
|
write!(f, "; execute-keys R;")?;
|
||||||
f.flush()?;
|
f.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -131,7 +132,7 @@ pub fn display_message<S: AsRef<str>>(
|
|||||||
message: S,
|
message: S,
|
||||||
debug_message: Option<S>,
|
debug_message: Option<S>,
|
||||||
) -> Result<(), KakError> {
|
) -> Result<(), KakError> {
|
||||||
let msg_str = message.as_ref().replace('\'', "''");
|
let msg_str = escape(message);
|
||||||
{
|
{
|
||||||
let mut f = open_command_fifo()?;
|
let mut f = open_command_fifo()?;
|
||||||
|
|
||||||
@ -139,32 +140,36 @@ pub fn display_message<S: AsRef<str>>(
|
|||||||
write!(f, "echo -debug '{}';", msg_str)?;
|
write!(f, "echo -debug '{}';", msg_str)?;
|
||||||
|
|
||||||
if let Some(debug_msg_str) = &debug_message.as_ref() {
|
if let Some(debug_msg_str) = &debug_message.as_ref() {
|
||||||
write!(
|
write!(f, "echo -debug '{}';", escape(debug_msg_str))?;
|
||||||
f,
|
|
||||||
"echo -debug '{}';",
|
|
||||||
debug_msg_str.as_ref().replace('\'', "''")
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
f.flush()?;
|
f.flush()?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn escape<S: AsRef<str>>(s: S) -> String {
|
||||||
|
s.as_ref().replace('\'', "''")
|
||||||
|
}
|
||||||
|
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will return `Err` if command fifo could not be opened or written to
|
/// Will return `Err` if command fifo could not be opened or written to
|
||||||
pub fn exec(cmd: &str) -> Result<(), KakError> {
|
pub fn cmd(cmd: &str) -> Result<(), KakError> {
|
||||||
let mut f = open_command_fifo()?;
|
let mut f = open_command_fifo()?;
|
||||||
|
|
||||||
write!(f, "{}", cmd)?;
|
write!(f, "{};", cmd)?;
|
||||||
f.flush().map_err(Into::into)
|
f.flush().map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn restore_register(r: &Register) -> Result<(), KakError> {
|
||||||
|
cmd(&format!("execute-keys '\"{}z'", r.kak_escaped()))
|
||||||
|
}
|
||||||
|
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will return `Err` if command fifo could not be opened or written to
|
/// Will return `Err` if command fifo could not be opened or written to
|
||||||
pub fn response(msg: &str) -> Result<Vec<String>, KakError> {
|
pub fn response(msg: &str) -> Result<Vec<String>, KakError> {
|
||||||
exec(&format!(
|
cmd(&format!(
|
||||||
"echo -quoting shell -to-file {} -- {msg}",
|
"echo -quoting shell -to-file {} -- {msg}",
|
||||||
get_var("kak_response_fifo")?
|
get_var("kak_response_fifo")?
|
||||||
))?;
|
))?;
|
||||||
|
@ -93,6 +93,352 @@ impl FromStr for AnchorPosition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum Register {
|
||||||
|
Numeric0,
|
||||||
|
Numeric1,
|
||||||
|
Numeric2,
|
||||||
|
Numeric3,
|
||||||
|
Numeric4,
|
||||||
|
Numeric5,
|
||||||
|
Numeric6,
|
||||||
|
Numeric7,
|
||||||
|
Numeric8,
|
||||||
|
Numeric9,
|
||||||
|
|
||||||
|
UppercaseA,
|
||||||
|
UppercaseB,
|
||||||
|
UppercaseC,
|
||||||
|
UppercaseD,
|
||||||
|
UppercaseE,
|
||||||
|
UppercaseF,
|
||||||
|
UppercaseG,
|
||||||
|
UppercaseH,
|
||||||
|
UppercaseI,
|
||||||
|
UppercaseJ,
|
||||||
|
UppercaseK,
|
||||||
|
UppercaseL,
|
||||||
|
UppercaseM,
|
||||||
|
UppercaseN,
|
||||||
|
UppercaseO,
|
||||||
|
UppercaseP,
|
||||||
|
UppercaseQ,
|
||||||
|
UppercaseR,
|
||||||
|
UppercaseS,
|
||||||
|
UppercaseT,
|
||||||
|
UppercaseU,
|
||||||
|
UppercaseV,
|
||||||
|
UppercaseW,
|
||||||
|
UppercaseX,
|
||||||
|
UppercaseY,
|
||||||
|
UppercaseZ,
|
||||||
|
|
||||||
|
LowercaseA,
|
||||||
|
LowercaseB,
|
||||||
|
LowercaseC,
|
||||||
|
LowercaseD,
|
||||||
|
LowercaseE,
|
||||||
|
LowercaseF,
|
||||||
|
LowercaseG,
|
||||||
|
LowercaseH,
|
||||||
|
LowercaseI,
|
||||||
|
LowercaseJ,
|
||||||
|
LowercaseK,
|
||||||
|
LowercaseL,
|
||||||
|
LowercaseM,
|
||||||
|
LowercaseN,
|
||||||
|
LowercaseO,
|
||||||
|
LowercaseP,
|
||||||
|
LowercaseQ,
|
||||||
|
LowercaseR,
|
||||||
|
LowercaseS,
|
||||||
|
LowercaseT,
|
||||||
|
LowercaseU,
|
||||||
|
LowercaseV,
|
||||||
|
LowercaseW,
|
||||||
|
LowercaseX,
|
||||||
|
LowercaseY,
|
||||||
|
LowercaseZ,
|
||||||
|
|
||||||
|
Dquote,
|
||||||
|
Slash,
|
||||||
|
Arobase,
|
||||||
|
Caret,
|
||||||
|
Pipe,
|
||||||
|
Percent,
|
||||||
|
Dot,
|
||||||
|
Hash,
|
||||||
|
Underscore,
|
||||||
|
Colon,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Register {
|
||||||
|
pub fn kak_expanded(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Dquote => "dquote",
|
||||||
|
Self::Slash => "slash",
|
||||||
|
Self::Arobase => "arobase",
|
||||||
|
Self::Caret => "caret",
|
||||||
|
Self::Pipe => "pipe",
|
||||||
|
Self::Percent => "percent",
|
||||||
|
Self::Dot => "dot",
|
||||||
|
Self::Hash => "hash",
|
||||||
|
Self::Underscore => "underscore",
|
||||||
|
Self::Colon => "colon",
|
||||||
|
|
||||||
|
// Everything else is the same
|
||||||
|
_ => self.kak_escaped(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_char(&self) -> char {
|
||||||
|
match self {
|
||||||
|
Self::Numeric0 => '0',
|
||||||
|
Self::Numeric1 => '1',
|
||||||
|
Self::Numeric2 => '2',
|
||||||
|
Self::Numeric3 => '3',
|
||||||
|
Self::Numeric4 => '4',
|
||||||
|
Self::Numeric5 => '5',
|
||||||
|
Self::Numeric6 => '6',
|
||||||
|
Self::Numeric7 => '7',
|
||||||
|
Self::Numeric8 => '8',
|
||||||
|
Self::Numeric9 => '9',
|
||||||
|
|
||||||
|
Self::UppercaseA => 'A',
|
||||||
|
Self::UppercaseB => 'B',
|
||||||
|
Self::UppercaseC => 'C',
|
||||||
|
Self::UppercaseD => 'D',
|
||||||
|
Self::UppercaseE => 'E',
|
||||||
|
Self::UppercaseF => 'F',
|
||||||
|
Self::UppercaseG => 'G',
|
||||||
|
Self::UppercaseH => 'H',
|
||||||
|
Self::UppercaseI => 'I',
|
||||||
|
Self::UppercaseJ => 'J',
|
||||||
|
Self::UppercaseK => 'K',
|
||||||
|
Self::UppercaseL => 'L',
|
||||||
|
Self::UppercaseM => 'M',
|
||||||
|
Self::UppercaseN => 'N',
|
||||||
|
Self::UppercaseO => 'O',
|
||||||
|
Self::UppercaseP => 'P',
|
||||||
|
Self::UppercaseQ => 'Q',
|
||||||
|
Self::UppercaseR => 'R',
|
||||||
|
Self::UppercaseS => 'S',
|
||||||
|
Self::UppercaseT => 'T',
|
||||||
|
Self::UppercaseU => 'U',
|
||||||
|
Self::UppercaseV => 'V',
|
||||||
|
Self::UppercaseW => 'W',
|
||||||
|
Self::UppercaseX => 'X',
|
||||||
|
Self::UppercaseY => 'Y',
|
||||||
|
Self::UppercaseZ => 'Z',
|
||||||
|
|
||||||
|
Self::LowercaseA => 'a',
|
||||||
|
Self::LowercaseB => 'b',
|
||||||
|
Self::LowercaseC => 'c',
|
||||||
|
Self::LowercaseD => 'd',
|
||||||
|
Self::LowercaseE => 'e',
|
||||||
|
Self::LowercaseF => 'f',
|
||||||
|
Self::LowercaseG => 'g',
|
||||||
|
Self::LowercaseH => 'h',
|
||||||
|
Self::LowercaseI => 'i',
|
||||||
|
Self::LowercaseJ => 'j',
|
||||||
|
Self::LowercaseK => 'k',
|
||||||
|
Self::LowercaseL => 'l',
|
||||||
|
Self::LowercaseM => 'm',
|
||||||
|
Self::LowercaseN => 'n',
|
||||||
|
Self::LowercaseO => 'o',
|
||||||
|
Self::LowercaseP => 'p',
|
||||||
|
Self::LowercaseQ => 'q',
|
||||||
|
Self::LowercaseR => 'r',
|
||||||
|
Self::LowercaseS => 's',
|
||||||
|
Self::LowercaseT => 't',
|
||||||
|
Self::LowercaseU => 'u',
|
||||||
|
Self::LowercaseV => 'v',
|
||||||
|
Self::LowercaseW => 'w',
|
||||||
|
Self::LowercaseX => 'x',
|
||||||
|
Self::LowercaseY => 'y',
|
||||||
|
Self::LowercaseZ => 'z',
|
||||||
|
|
||||||
|
Self::Dquote => '"',
|
||||||
|
Self::Slash => '/',
|
||||||
|
Self::Arobase => '@',
|
||||||
|
Self::Caret => '^',
|
||||||
|
Self::Pipe => '|',
|
||||||
|
Self::Percent => '%',
|
||||||
|
Self::Dot => '.',
|
||||||
|
Self::Hash => '#',
|
||||||
|
Self::Underscore => '_',
|
||||||
|
Self::Colon => ':',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kak_escaped(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Numeric0 => "0",
|
||||||
|
Self::Numeric1 => "1",
|
||||||
|
Self::Numeric2 => "2",
|
||||||
|
Self::Numeric3 => "3",
|
||||||
|
Self::Numeric4 => "4",
|
||||||
|
Self::Numeric5 => "5",
|
||||||
|
Self::Numeric6 => "6",
|
||||||
|
Self::Numeric7 => "7",
|
||||||
|
Self::Numeric8 => "8",
|
||||||
|
Self::Numeric9 => "9",
|
||||||
|
|
||||||
|
Self::UppercaseA => "A",
|
||||||
|
Self::UppercaseB => "B",
|
||||||
|
Self::UppercaseC => "C",
|
||||||
|
Self::UppercaseD => "D",
|
||||||
|
Self::UppercaseE => "E",
|
||||||
|
Self::UppercaseF => "F",
|
||||||
|
Self::UppercaseG => "G",
|
||||||
|
Self::UppercaseH => "H",
|
||||||
|
Self::UppercaseI => "I",
|
||||||
|
Self::UppercaseJ => "J",
|
||||||
|
Self::UppercaseK => "K",
|
||||||
|
Self::UppercaseL => "L",
|
||||||
|
Self::UppercaseM => "M",
|
||||||
|
Self::UppercaseN => "N",
|
||||||
|
Self::UppercaseO => "O",
|
||||||
|
Self::UppercaseP => "P",
|
||||||
|
Self::UppercaseQ => "Q",
|
||||||
|
Self::UppercaseR => "R",
|
||||||
|
Self::UppercaseS => "S",
|
||||||
|
Self::UppercaseT => "T",
|
||||||
|
Self::UppercaseU => "U",
|
||||||
|
Self::UppercaseV => "V",
|
||||||
|
Self::UppercaseW => "W",
|
||||||
|
Self::UppercaseX => "X",
|
||||||
|
Self::UppercaseY => "Y",
|
||||||
|
Self::UppercaseZ => "Z",
|
||||||
|
|
||||||
|
Self::LowercaseA => "a",
|
||||||
|
Self::LowercaseB => "b",
|
||||||
|
Self::LowercaseC => "c",
|
||||||
|
Self::LowercaseD => "d",
|
||||||
|
Self::LowercaseE => "e",
|
||||||
|
Self::LowercaseF => "f",
|
||||||
|
Self::LowercaseG => "g",
|
||||||
|
Self::LowercaseH => "h",
|
||||||
|
Self::LowercaseI => "i",
|
||||||
|
Self::LowercaseJ => "j",
|
||||||
|
Self::LowercaseK => "k",
|
||||||
|
Self::LowercaseL => "l",
|
||||||
|
Self::LowercaseM => "m",
|
||||||
|
Self::LowercaseN => "n",
|
||||||
|
Self::LowercaseO => "o",
|
||||||
|
Self::LowercaseP => "p",
|
||||||
|
Self::LowercaseQ => "q",
|
||||||
|
Self::LowercaseR => "r",
|
||||||
|
Self::LowercaseS => "s",
|
||||||
|
Self::LowercaseT => "t",
|
||||||
|
Self::LowercaseU => "u",
|
||||||
|
Self::LowercaseV => "v",
|
||||||
|
Self::LowercaseW => "w",
|
||||||
|
Self::LowercaseX => "x",
|
||||||
|
Self::LowercaseY => "y",
|
||||||
|
Self::LowercaseZ => "z",
|
||||||
|
|
||||||
|
Self::Dquote => "\\\"",
|
||||||
|
Self::Slash => "/",
|
||||||
|
Self::Arobase => "@",
|
||||||
|
Self::Caret => "^",
|
||||||
|
Self::Pipe => "|",
|
||||||
|
Self::Percent => "%",
|
||||||
|
Self::Dot => ".",
|
||||||
|
Self::Hash => "#",
|
||||||
|
Self::Underscore => "_",
|
||||||
|
Self::Colon => ":",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Register {
|
||||||
|
type Err = KakError;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"0" => Ok(Self::Numeric0),
|
||||||
|
"1" => Ok(Self::Numeric1),
|
||||||
|
"2" => Ok(Self::Numeric2),
|
||||||
|
"3" => Ok(Self::Numeric3),
|
||||||
|
"4" => Ok(Self::Numeric4),
|
||||||
|
"5" => Ok(Self::Numeric5),
|
||||||
|
"6" => Ok(Self::Numeric6),
|
||||||
|
"7" => Ok(Self::Numeric7),
|
||||||
|
"8" => Ok(Self::Numeric8),
|
||||||
|
"9" => Ok(Self::Numeric9),
|
||||||
|
|
||||||
|
"A" => Ok(Self::UppercaseA),
|
||||||
|
"B" => Ok(Self::UppercaseB),
|
||||||
|
"C" => Ok(Self::UppercaseC),
|
||||||
|
"D" => Ok(Self::UppercaseD),
|
||||||
|
"E" => Ok(Self::UppercaseE),
|
||||||
|
"F" => Ok(Self::UppercaseF),
|
||||||
|
"G" => Ok(Self::UppercaseG),
|
||||||
|
"H" => Ok(Self::UppercaseH),
|
||||||
|
"I" => Ok(Self::UppercaseI),
|
||||||
|
"J" => Ok(Self::UppercaseJ),
|
||||||
|
"K" => Ok(Self::UppercaseK),
|
||||||
|
"L" => Ok(Self::UppercaseL),
|
||||||
|
"M" => Ok(Self::UppercaseM),
|
||||||
|
"N" => Ok(Self::UppercaseN),
|
||||||
|
"O" => Ok(Self::UppercaseO),
|
||||||
|
"P" => Ok(Self::UppercaseP),
|
||||||
|
"Q" => Ok(Self::UppercaseQ),
|
||||||
|
"R" => Ok(Self::UppercaseR),
|
||||||
|
"S" => Ok(Self::UppercaseS),
|
||||||
|
"T" => Ok(Self::UppercaseT),
|
||||||
|
"U" => Ok(Self::UppercaseU),
|
||||||
|
"V" => Ok(Self::UppercaseV),
|
||||||
|
"W" => Ok(Self::UppercaseW),
|
||||||
|
"X" => Ok(Self::UppercaseX),
|
||||||
|
"Y" => Ok(Self::UppercaseY),
|
||||||
|
"Z" => Ok(Self::UppercaseZ),
|
||||||
|
|
||||||
|
"a" => Ok(Self::LowercaseA),
|
||||||
|
"b" => Ok(Self::LowercaseB),
|
||||||
|
"c" => Ok(Self::LowercaseC),
|
||||||
|
"d" => Ok(Self::LowercaseD),
|
||||||
|
"e" => Ok(Self::LowercaseE),
|
||||||
|
"f" => Ok(Self::LowercaseF),
|
||||||
|
"g" => Ok(Self::LowercaseG),
|
||||||
|
"h" => Ok(Self::LowercaseH),
|
||||||
|
"i" => Ok(Self::LowercaseI),
|
||||||
|
"j" => Ok(Self::LowercaseJ),
|
||||||
|
"k" => Ok(Self::LowercaseK),
|
||||||
|
"l" => Ok(Self::LowercaseL),
|
||||||
|
"m" => Ok(Self::LowercaseM),
|
||||||
|
"n" => Ok(Self::LowercaseN),
|
||||||
|
"o" => Ok(Self::LowercaseO),
|
||||||
|
"p" => Ok(Self::LowercaseP),
|
||||||
|
"q" => Ok(Self::LowercaseQ),
|
||||||
|
"r" => Ok(Self::LowercaseR),
|
||||||
|
"s" => Ok(Self::LowercaseS),
|
||||||
|
"t" => Ok(Self::LowercaseT),
|
||||||
|
"u" => Ok(Self::LowercaseU),
|
||||||
|
"v" => Ok(Self::LowercaseV),
|
||||||
|
"w" => Ok(Self::LowercaseW),
|
||||||
|
"x" => Ok(Self::LowercaseX),
|
||||||
|
"y" => Ok(Self::LowercaseY),
|
||||||
|
"z" => Ok(Self::LowercaseZ),
|
||||||
|
|
||||||
|
"\"" | "dquote" => Ok(Self::Dquote),
|
||||||
|
"/" | "slash" => Ok(Self::Slash),
|
||||||
|
"@" | "arobase" => Ok(Self::Arobase),
|
||||||
|
"^" | "caret" => Ok(Self::Caret),
|
||||||
|
"|" | "pipe" => Ok(Self::Pipe),
|
||||||
|
"%" | "percent" => Ok(Self::Percent),
|
||||||
|
"." | "dot" => Ok(Self::Dot),
|
||||||
|
"#" | "hash" => Ok(Self::Hash),
|
||||||
|
"_" | "underscore" => Ok(Self::Underscore),
|
||||||
|
":" | "colon" => Ok(Self::Colon),
|
||||||
|
|
||||||
|
_ => Err(KakError::Parse(format!(
|
||||||
|
"Register '{s}' could not be parsed"
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
24
src/main.rs
24
src/main.rs
@ -5,15 +5,19 @@
|
|||||||
// Cannot be fixed
|
// Cannot be fixed
|
||||||
#![allow(clippy::multiple_crate_versions)]
|
#![allow(clippy::multiple_crate_versions)]
|
||||||
#![allow(clippy::struct_excessive_bools)]
|
#![allow(clippy::struct_excessive_bools)]
|
||||||
|
// TODO: Remove
|
||||||
|
#![allow(dead_code, unused_imports)]
|
||||||
|
|
||||||
mod errors;
|
mod errors;
|
||||||
mod math_eval;
|
mod math_eval;
|
||||||
|
mod set;
|
||||||
mod shuf;
|
mod shuf;
|
||||||
mod sort;
|
mod sort;
|
||||||
mod stdin;
|
mod stdin;
|
||||||
mod trim;
|
mod trim;
|
||||||
mod uniq;
|
mod uniq;
|
||||||
mod xargs;
|
mod utils;
|
||||||
|
// mod xargs;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use kakplugin::{display_message, get_var, KakError};
|
use kakplugin::{display_message, get_var, KakError};
|
||||||
|
|
||||||
@ -31,13 +35,21 @@ struct Cli {
|
|||||||
|
|
||||||
#[derive(Subcommand, Debug)]
|
#[derive(Subcommand, Debug)]
|
||||||
enum Commands {
|
enum Commands {
|
||||||
|
#[clap(about = "Sorts selections based on content or content regex match")]
|
||||||
Sort(sort::Options),
|
Sort(sort::Options),
|
||||||
|
#[clap(about = "Shuffle selections")]
|
||||||
Shuf(shuf::Options),
|
Shuf(shuf::Options),
|
||||||
|
#[clap(about = "Find unique selections based on optional regex match")]
|
||||||
Uniq(uniq::Options),
|
Uniq(uniq::Options),
|
||||||
#[clap(visible_aliases = &["bc", "eval"])]
|
#[clap(about = "Evaluate selections as a math expression", visible_aliases = &["bc", "eval"])]
|
||||||
MathEval(math_eval::Options),
|
MathEval(math_eval::Options),
|
||||||
|
#[clap(about = "Trim every selection")]
|
||||||
Trim(trim::Options),
|
Trim(trim::Options),
|
||||||
Xargs(xargs::Options),
|
#[clap(about = "Perform set operations on selections")]
|
||||||
|
Set(set::Options),
|
||||||
|
// #[clap(about = "")]
|
||||||
|
// Xargs(xargs::Options),
|
||||||
|
#[clap(about = "Pass each selection null terminated to a command")]
|
||||||
Stdin(stdin::Options),
|
Stdin(stdin::Options),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,8 +75,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run() -> Result<String, KakError> {
|
fn run() -> Result<String, KakError> {
|
||||||
let options =
|
let options = Cli::try_parse().map_err(|e| KakError::Custom(format!("{e}")))?;
|
||||||
Cli::try_parse().map_err(|e| KakError::Parse(format!("Argument parse error: {e}")))?;
|
|
||||||
|
|
||||||
match &options.command {
|
match &options.command {
|
||||||
Commands::Sort(o) => sort::sort(o),
|
Commands::Sort(o) => sort::sort(o),
|
||||||
@ -72,7 +83,8 @@ fn run() -> Result<String, KakError> {
|
|||||||
Commands::Uniq(o) => uniq::uniq(o),
|
Commands::Uniq(o) => uniq::uniq(o),
|
||||||
Commands::MathEval(o) => math_eval::math_eval(o),
|
Commands::MathEval(o) => math_eval::math_eval(o),
|
||||||
Commands::Trim(o) => trim::trim(o),
|
Commands::Trim(o) => trim::trim(o),
|
||||||
Commands::Xargs(o) => xargs::xargs(o),
|
Commands::Set(o) => set::set(o),
|
||||||
|
// Commands::Xargs(o) => xargs::xargs(o),
|
||||||
Commands::Stdin(o) => stdin::stdin(o),
|
Commands::Stdin(o) => stdin::stdin(o),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
314
src/set.rs
Normal file
314
src/set.rs
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
// use crate::utils;
|
||||||
|
use clap::ArgEnum;
|
||||||
|
use kakplugin::{
|
||||||
|
get_selections, get_selections_with_desc, set_selections, set_selections_desc, types::Register,
|
||||||
|
KakError, Selection, SelectionWithDesc,
|
||||||
|
};
|
||||||
|
use linked_hash_map::LinkedHashMap;
|
||||||
|
use linked_hash_set::LinkedHashSet;
|
||||||
|
use regex::Regex;
|
||||||
|
use std::{collections::HashSet, io::Write, str::FromStr};
|
||||||
|
|
||||||
|
#[derive(clap::StructOpt, Debug)]
|
||||||
|
pub struct Options {
|
||||||
|
#[clap(min_values = 1, max_values = 3)]
|
||||||
|
args: Vec<String>,
|
||||||
|
|
||||||
|
#[clap(short = 'T')]
|
||||||
|
no_trim: bool,
|
||||||
|
// #[clap(short, long)]
|
||||||
|
// regex: Option<Regex>,
|
||||||
|
// #[clap(short, long)]
|
||||||
|
// ignore_case: bool,
|
||||||
|
// #[clap(short = 'S', long)]
|
||||||
|
// no_skip_whitespace: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum Operation {
|
||||||
|
Intersect,
|
||||||
|
Subtract,
|
||||||
|
Union,
|
||||||
|
Compare,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operation {
|
||||||
|
pub fn to_char(&self) -> char {
|
||||||
|
match self {
|
||||||
|
Self::Intersect => '&',
|
||||||
|
Self::Subtract => '-',
|
||||||
|
Self::Union => '+',
|
||||||
|
Self::Compare => '?',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Operation {
|
||||||
|
type Err = KakError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"intersect" | "and" | "&" => Ok(Self::Intersect),
|
||||||
|
"subtract" | "not" | "minus" | "-" | "\\" => Ok(Self::Subtract),
|
||||||
|
"union" | "or" | "plus" | "+" => Ok(Self::Union),
|
||||||
|
"compare" | "cmp" | "?" | "=" => Ok(Self::Compare),
|
||||||
|
_ => Err(KakError::Parse(format!(
|
||||||
|
"Set operation '{s}' could not be parsed"
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(options: &Options) -> Result<String, KakError> {
|
||||||
|
let (left_register, operation, right_register) = parse_arguments(&options.args[..])?;
|
||||||
|
|
||||||
|
// Underscore is a special case. We will treat it as the current selection
|
||||||
|
let (left_selections, right_selections) = match (&left_register, &right_register) {
|
||||||
|
(Register::Underscore, r) => {
|
||||||
|
let l_selections = get_selections()?;
|
||||||
|
kakplugin::restore_register(r)?;
|
||||||
|
let r_selections = get_selections()?;
|
||||||
|
|
||||||
|
(l_selections, r_selections)
|
||||||
|
}
|
||||||
|
(l, Register::Underscore) => {
|
||||||
|
let r_selections = get_selections()?;
|
||||||
|
kakplugin::restore_register(l)?;
|
||||||
|
let l_selections = get_selections()?;
|
||||||
|
|
||||||
|
(l_selections, r_selections)
|
||||||
|
}
|
||||||
|
(l, r) => {
|
||||||
|
kakplugin::restore_register(l)?;
|
||||||
|
let l_selections = get_selections()?;
|
||||||
|
|
||||||
|
kakplugin::restore_register(r)?;
|
||||||
|
let r_selections = get_selections()?;
|
||||||
|
(l_selections, r_selections)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let (left_ordered_counts, right_ordered_counts) = (
|
||||||
|
to_ordered_counts(options, left_selections),
|
||||||
|
to_ordered_counts(options, right_selections),
|
||||||
|
);
|
||||||
|
let (left_keys, right_keys) = (
|
||||||
|
left_ordered_counts
|
||||||
|
.keys()
|
||||||
|
.collect::<LinkedHashSet<&Selection>>(),
|
||||||
|
right_ordered_counts
|
||||||
|
.keys()
|
||||||
|
.collect::<LinkedHashSet<&Selection>>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = key_set_operation(&operation, &left_keys, &right_keys);
|
||||||
|
|
||||||
|
match &operation {
|
||||||
|
Operation::Compare => compare(
|
||||||
|
&left_register,
|
||||||
|
&right_register,
|
||||||
|
&result,
|
||||||
|
&left_ordered_counts,
|
||||||
|
&right_ordered_counts,
|
||||||
|
)?,
|
||||||
|
Operation::Intersect | Operation::Subtract | Operation::Union => print_result(&result)?,
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(match &operation {
|
||||||
|
Operation::Compare => format!("Compared {} selections", result.len()),
|
||||||
|
op => format!(
|
||||||
|
"{}{}{} returned {} selections",
|
||||||
|
left_register.to_char(),
|
||||||
|
op.to_char(),
|
||||||
|
right_register.to_char(),
|
||||||
|
result.len()
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_result(key_set_operation_result: &LinkedHashSet<&Selection>) -> Result<(), KakError> {
|
||||||
|
// Manually set selections so we don't have to allocate a string
|
||||||
|
let mut f = kakplugin::open_command_fifo()?;
|
||||||
|
|
||||||
|
// Send all of this into an evaluate-commands block
|
||||||
|
// -save-regs '"'
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
r#"evaluate-commands %{{
|
||||||
|
set-register '"'"#
|
||||||
|
)?;
|
||||||
|
|
||||||
|
for k in key_set_operation_result {
|
||||||
|
write!(f, " '{}\n'", kakplugin::escape(k))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
r#";
|
||||||
|
edit -scratch '*kakplugin-set*';
|
||||||
|
execute-keys '%<a-R>_';
|
||||||
|
}}"#
|
||||||
|
)?;
|
||||||
|
|
||||||
|
f.flush()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compare(
|
||||||
|
left_register: &Register,
|
||||||
|
right_register: &Register,
|
||||||
|
key_set_operation_result: &LinkedHashSet<&Selection>,
|
||||||
|
left_ordered_counts: &LinkedHashMap<Selection, usize>,
|
||||||
|
right_ordered_counts: &LinkedHashMap<Selection, usize>,
|
||||||
|
) -> Result<(), KakError> {
|
||||||
|
// Manually set selections so we don't have to allocate a string
|
||||||
|
let mut f = kakplugin::open_command_fifo()?;
|
||||||
|
|
||||||
|
// Send all of this into an evaluate-commands block
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
// -save-regs '"'
|
||||||
|
r#"evaluate-commands -save-regs '"' %{{
|
||||||
|
set-register '"'"#
|
||||||
|
)?;
|
||||||
|
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
" '?\t{}\t{}\tselection\n'",
|
||||||
|
left_register.to_char(),
|
||||||
|
right_register.to_char()
|
||||||
|
)?;
|
||||||
|
|
||||||
|
for k in key_set_operation_result {
|
||||||
|
let left_count = left_ordered_counts.get(&k as &str).unwrap_or(&0);
|
||||||
|
let right_count = right_ordered_counts.get(&k as &str).unwrap_or(&0);
|
||||||
|
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
" '{}\t{}\t{}\t{}\n'",
|
||||||
|
match (*left_count == 0, *right_count == 0) {
|
||||||
|
(true, true) => "?",
|
||||||
|
(true, false) => ">",
|
||||||
|
(false, true) => "<",
|
||||||
|
(false, false) => "=",
|
||||||
|
},
|
||||||
|
left_count,
|
||||||
|
right_count,
|
||||||
|
// TODO: Do we want to escape the \n to \\n?
|
||||||
|
// kakplugin::escape(k.replace('\n', "\\n")),
|
||||||
|
kakplugin::escape(k),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
r#";
|
||||||
|
edit -scratch '*kakplugin-set*';
|
||||||
|
execute-keys '%<a-R><a-;>3<a-W>L)<a-space>_vb';
|
||||||
|
}}"#
|
||||||
|
)?;
|
||||||
|
|
||||||
|
f.flush()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_ordered_counts(options: &Options, sels: Vec<Selection>) -> LinkedHashMap<Selection, usize> {
|
||||||
|
let mut ret = LinkedHashMap::new();
|
||||||
|
|
||||||
|
for i in sels.into_iter() {
|
||||||
|
let key = if options.no_trim {
|
||||||
|
i
|
||||||
|
} else {
|
||||||
|
i.trim().to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
if key.is_empty() {
|
||||||
|
// We don't want to even pretend to look at empty keys
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let entry: &mut usize = ret.entry(key).or_insert(0);
|
||||||
|
*entry = entry.saturating_add(1);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_set_operation<'a>(
|
||||||
|
operation: &Operation,
|
||||||
|
left_keys: &LinkedHashSet<&'a Selection>,
|
||||||
|
right_keys: &LinkedHashSet<&'a Selection>,
|
||||||
|
) -> LinkedHashSet<&'a Selection> {
|
||||||
|
match operation {
|
||||||
|
Operation::Intersect => left_keys
|
||||||
|
.intersection(&right_keys)
|
||||||
|
// .into_iter()
|
||||||
|
// TODO: Remove this
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
Operation::Subtract => left_keys
|
||||||
|
.difference(&right_keys)
|
||||||
|
.into_iter()
|
||||||
|
// TODO: Remove this
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
Operation::Compare | Operation::Union => left_keys
|
||||||
|
.union(&right_keys)
|
||||||
|
.into_iter()
|
||||||
|
// TODO: Remove this
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
// TODO: Symmetric difference?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_arguments(args: &[String]) -> Result<(Register, Operation, Register), KakError> {
|
||||||
|
let args = if args.len() == 1 {
|
||||||
|
// They gave us something like "a-b" or "c?d"
|
||||||
|
args.iter()
|
||||||
|
.flat_map(|s: &String| s.trim().chars())
|
||||||
|
.map(|c| String::from(c))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
} else {
|
||||||
|
// They gave us something like "a - b" or "c compare d"
|
||||||
|
args.iter().cloned().collect()
|
||||||
|
};
|
||||||
|
let (left_register, middle, right_register) = match &args[..] {
|
||||||
|
[l, r] => {
|
||||||
|
// They only gave us two arguments like "- a" or "b -"
|
||||||
|
match (Operation::from_str(l), Operation::from_str(r)) {
|
||||||
|
// If the operation is on the left, then the _ register is the leftmost one
|
||||||
|
(Ok(o), Err(_)) => Ok((Register::Underscore, o, Register::from_str(r)?)),
|
||||||
|
// If the operation is on the right, then the _ register is the rightmost one
|
||||||
|
(Err(_), Ok(o)) => Ok((Register::from_str(l)?, o, Register::Underscore)),
|
||||||
|
(Ok(_), Ok(_)) => Err(KakError::Custom(format!(
|
||||||
|
"Arguments '{l}' and '{r}' cannot both be operations"
|
||||||
|
))),
|
||||||
|
(Err(_), Err(_)) => Err(KakError::Custom(format!(
|
||||||
|
"One argument must be an operation"
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[l, middle, r] => {
|
||||||
|
// They gave us three arguments like "a - b" or "_ + a"
|
||||||
|
Ok((
|
||||||
|
Register::from_str(l)?,
|
||||||
|
Operation::from_str(middle)?,
|
||||||
|
Register::from_str(r)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => Err(KakError::Custom(format!(
|
||||||
|
"Invalid arguments to set command"
|
||||||
|
))),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
if left_register == right_register {
|
||||||
|
return Err(KakError::Custom(format!(
|
||||||
|
"Registers passed are the same: '{}'",
|
||||||
|
left_register.to_char()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((left_register, middle, right_register))
|
||||||
|
}
|
@ -125,7 +125,7 @@ pub fn sort(options: &Options) -> Result<String, KakError> {
|
|||||||
.subselections_register
|
.subselections_register
|
||||||
.map::<Result<_, KakError>, _>(|c| {
|
.map::<Result<_, KakError>, _>(|c| {
|
||||||
let subselections = get_selections_with_desc()?;
|
let subselections = get_selections_with_desc()?;
|
||||||
kakplugin::exec(&format!("exec {}", c))?;
|
kakplugin::cmd(&format!("exec {}", c))?;
|
||||||
Ok(subselections)
|
Ok(subselections)
|
||||||
})
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
@ -34,7 +34,6 @@ pub fn stdin(options: &Options) -> Result<String, KakError> {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Wait for the background process to exit
|
// Wait for the background process to exit
|
||||||
// TODO: Do not use a string
|
|
||||||
handle
|
handle
|
||||||
.join()
|
.join()
|
||||||
.map_err(|_e| KakError::Custom("Could not join background process".to_string()))??;
|
.map_err(|_e| KakError::Custom("Could not join background process".to_string()))??;
|
||||||
|
47
src/uniq.rs
47
src/uniq.rs
@ -1,12 +1,11 @@
|
|||||||
|
use crate::utils;
|
||||||
use kakplugin::{
|
use kakplugin::{
|
||||||
get_selections_desc, get_selections_with_desc, set_selections, set_selections_desc, KakError,
|
get_selections_desc, get_selections_with_desc, set_selections, set_selections_desc, KakError,
|
||||||
SelectionWithDesc,
|
SelectionWithDesc,
|
||||||
};
|
};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{
|
use std::collections::BTreeSet;
|
||||||
collections::{hash_map::DefaultHasher, BTreeSet},
|
|
||||||
hash::{Hash, Hasher},
|
|
||||||
};
|
|
||||||
#[derive(clap::StructOpt, Debug)]
|
#[derive(clap::StructOpt, Debug)]
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
#[clap(index = 1)]
|
#[clap(index = 1)]
|
||||||
@ -26,40 +25,18 @@ pub fn uniq(options: &Options) -> Result<String, KakError> {
|
|||||||
let new_selections: Vec<Option<SelectionWithDesc>> = selections
|
let new_selections: Vec<Option<SelectionWithDesc>> = selections
|
||||||
.into_iter()
|
.into_iter()
|
||||||
// Create a BTreeSet of hashes of selections. This way, string content is not stored, but uniqueness can be determined
|
// Create a BTreeSet of hashes of selections. This way, string content is not stored, but uniqueness can be determined
|
||||||
.scan(BTreeSet::new(), |state, s| {
|
.scan(BTreeSet::new(), |state, sd| {
|
||||||
// Strip whitespace if requested
|
let hash = utils::get_hash(
|
||||||
let mut key = if options.no_skip_whitespace {
|
&sd.content,
|
||||||
s.content.as_str()
|
!options.no_skip_whitespace,
|
||||||
} else {
|
options.regex.as_ref(),
|
||||||
s.content.trim()
|
options.ignore_case,
|
||||||
};
|
);
|
||||||
|
|
||||||
// If they requested a regex match, set the key to the string slice of that match
|
|
||||||
if let Some(regex_match) = (|| {
|
|
||||||
let captures = options.regex.as_ref()?.captures(key)?;
|
|
||||||
captures
|
|
||||||
.get(1)
|
|
||||||
.or_else(|| captures.get(0))
|
|
||||||
.map(|m| m.as_str())
|
|
||||||
})() {
|
|
||||||
key = regex_match;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore case if requested
|
|
||||||
let key = if options.ignore_case {
|
|
||||||
key.to_lowercase()
|
|
||||||
} else {
|
|
||||||
// TODO: Do I really need to clone this?
|
|
||||||
key.to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut hasher = DefaultHasher::new();
|
|
||||||
key.hash(&mut hasher);
|
|
||||||
|
|
||||||
// Try inserting to the hash
|
// Try inserting to the hash
|
||||||
if state.insert(hasher.finish()) {
|
if state.insert(hash) {
|
||||||
// True if this is a string we haven't seen before
|
// True if this is a string we haven't seen before
|
||||||
Some(Some(s))
|
Some(Some(sd))
|
||||||
} else {
|
} else {
|
||||||
// Nothing was inserted because we already saw this string
|
// Nothing was inserted because we already saw this string
|
||||||
// Return Some(None) so the iterator can continue
|
// Return Some(None) so the iterator can continue
|
||||||
|
54
src/utils.rs
Normal file
54
src/utils.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use kakplugin::Selection;
|
||||||
|
use regex::Regex;
|
||||||
|
use std::{
|
||||||
|
collections::hash_map::DefaultHasher,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) fn get_key(
|
||||||
|
selection: &Selection,
|
||||||
|
skip_whitespace: bool,
|
||||||
|
regex: Option<&Regex>,
|
||||||
|
ignore_case: bool,
|
||||||
|
) -> String {
|
||||||
|
// Strip whitespace if requested
|
||||||
|
let mut key = if skip_whitespace {
|
||||||
|
selection.as_str()
|
||||||
|
} else {
|
||||||
|
selection.trim()
|
||||||
|
};
|
||||||
|
|
||||||
|
// If they requested a regex match, set the key to the string slice of that match
|
||||||
|
if let Some(regex_match) = (|| {
|
||||||
|
let captures = regex.as_ref()?.captures(key)?;
|
||||||
|
captures
|
||||||
|
.get(1)
|
||||||
|
.or_else(|| captures.get(0))
|
||||||
|
.map(|m| m.as_str())
|
||||||
|
})() {
|
||||||
|
key = regex_match;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore case if requested
|
||||||
|
// Lowercase at the end to not mangle regex
|
||||||
|
if ignore_case {
|
||||||
|
key.to_lowercase()
|
||||||
|
} else {
|
||||||
|
// TODO: Do not perform an allocation here
|
||||||
|
key.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a key out of a selection based on options
|
||||||
|
pub(crate) fn get_hash(
|
||||||
|
selection: &Selection,
|
||||||
|
skip_whitespace: bool,
|
||||||
|
regex: Option<&Regex>,
|
||||||
|
ignore_case: bool,
|
||||||
|
) -> u64 {
|
||||||
|
let mut hasher = DefaultHasher::new();
|
||||||
|
|
||||||
|
get_key(selection, skip_whitespace, regex, ignore_case).hash(&mut hasher);
|
||||||
|
|
||||||
|
hasher.finish()
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user