Start work on potential iterator approach
This commit is contained in:
parent
92de282027
commit
ddcdd2b487
@ -13,6 +13,7 @@ keywords = ["cli", "kakoune"]
|
||||
regex = "1"
|
||||
clap = {version = "3", features = ["derive", "env"]}
|
||||
alphanumeric-sort = "1"
|
||||
# shellwords = {version = "1", path = "../../../git/rust-shellwords/"}
|
||||
shellwords = "1"
|
||||
rand = "0.8"
|
||||
evalexpr = "7"
|
||||
|
12
src/kak.rs
12
src/kak.rs
@ -1,4 +1,5 @@
|
||||
use crate::{get_var, KakMessage};
|
||||
// use shellwords::ShellWordsIterator;
|
||||
use std::{
|
||||
fmt,
|
||||
fs::{self, File, OpenOptions},
|
||||
@ -261,6 +262,17 @@ pub fn response(msg: &str) -> Result<Vec<String>, KakMessage> {
|
||||
Ok(selections)
|
||||
}
|
||||
|
||||
// pub fn response_iter(msg: &str) -> Result<ShellWordsIterator, KakMessage> {
|
||||
// exec(&format!(
|
||||
// "echo -quoting shell -to-file {} -- {msg}",
|
||||
// get_var("kak_response_fifo")?
|
||||
// ))?;
|
||||
|
||||
// Ok(shellwords::split_iter(&fs::read_to_string(&get_var(
|
||||
// "kak_response_fifo",
|
||||
// )?)?))
|
||||
// }
|
||||
|
||||
/// # Errors
|
||||
///
|
||||
/// Will return `Err` if command fifo could not be opened
|
||||
|
102
src/xargs.rs
Normal file
102
src/xargs.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use crate::{
|
||||
get_selections_desc, set_selections, set_selections_desc, KakMessage, SelectionWithDesc,
|
||||
};
|
||||
use regex::Regex;
|
||||
use std::{
|
||||
collections::{hash_map::DefaultHasher, BTreeSet},
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
#[derive(clap::StructOpt, Debug)]
|
||||
pub struct Options {
|
||||
}
|
||||
pub fn xargs(options: &Options) -> Result<KakMessage, KakMessage> {
|
||||
let mut child = Command::new("xargs")
|
||||
.args(["-0"])
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn().expect("Failed to spawn child process");
|
||||
|
||||
let mut stdin = child.stdin.take().expect("Failed to open stdin");
|
||||
std::thread::spawn(move || {
|
||||
for s in crate::get_selections_with_desc()? {
|
||||
stdin.write_all(s.selection).expect("Failed to write to stdin");
|
||||
stdin.write_all('\0').expect("Failed to write to stdin");
|
||||
}
|
||||
|
||||
})
|
||||
// Sort selections so the first element is the xargsue one, not an arbitrary one based on primary selection
|
||||
selections.sort_by_key(|s| s.desc.sort());
|
||||
|
||||
// Set the new selection types
|
||||
let new_selections: Vec<Option<SelectionWithDesc>> = selections
|
||||
.into_iter()
|
||||
// Create a BTreeSet of hashes of selections. This way, string content is not stored, but xargsueness can be determined
|
||||
.scan(BTreeSet::new(), |state, s| {
|
||||
// Strip whitespace if requested
|
||||
let mut key = if options.no_skip_whitespace {
|
||||
s.content.as_str()
|
||||
} else {
|
||||
s.content.trim()
|
||||
};
|
||||
|
||||
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
|
||||
if state.insert(hasher.finish()) {
|
||||
// True if this is a string we haven't seen before
|
||||
Some(Some(s))
|
||||
} else {
|
||||
// Nothing was inserted because we already saw this string
|
||||
// Return Some(None) so the iterator can continue
|
||||
Some(None)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Preallocate so the content and string have the same type, but allocation is not repeated
|
||||
// TODO: Do we really have to do this?
|
||||
let empty_string = String::default();
|
||||
set_selections(new_selections.iter().map(|i| match i {
|
||||
Some(s) => &s.content,
|
||||
None => &empty_string,
|
||||
}))?;
|
||||
|
||||
// Deselect all `None` strings (all rows that have been seen before)
|
||||
let mut new_selections_desc = get_selections_desc()?;
|
||||
new_selections_desc.sort();
|
||||
set_selections_desc(
|
||||
// Refresh seelections_desc because positions have changed
|
||||
new_selections_desc
|
||||
.iter()
|
||||
.zip(new_selections.iter())
|
||||
// If the string was emptied (None), then do not set `sd`
|
||||
.filter_map(|(sd, s)| if s.is_some() { Some(sd) } else { None }),
|
||||
)?;
|
||||
|
||||
let old_count = new_selections.len();
|
||||
let new_count = new_selections.iter().flatten().count();
|
||||
|
||||
Ok(KakMessage(
|
||||
format!("{} xargs selections out of {}", new_count, old_count),
|
||||
None,
|
||||
))
|
||||
}
|
Loading…
Reference in New Issue
Block a user