Add ability to do set operations on current selection only

This commit is contained in:
Austen Adler 2022-07-07 00:14:23 -04:00
parent 296ac24d81
commit ea32174522
3 changed files with 72 additions and 15 deletions

View File

@ -114,9 +114,10 @@ where
/// # Errors /// # Errors
/// ///
/// Will return `Err` if command fifo could not be opened, read from, or written to /// Will return `Err` if command fifo could not be opened, read from, or written to
pub fn set_selections_desc<'a, I>(selections: I) -> Result<(), KakError> pub fn set_selections_desc<'a, I, SD: 'a + std::fmt::Display>(selections: I) -> Result<(), KakError>
where where
I: IntoIterator<Item = &'a SelectionDesc>, I: IntoIterator<Item = SD>,
SD: AsRef<SelectionDesc>,
{ {
let mut selections_iter = selections.into_iter().peekable(); let mut selections_iter = selections.into_iter().peekable();
if selections_iter.peek().is_none() { if selections_iter.peek().is_none() {

View File

@ -49,6 +49,12 @@ impl SelectionDesc {
} }
} }
impl AsRef<SelectionDesc> for SelectionDesc {
fn as_ref(&self) -> &Self {
&self
}
}
impl fmt::Display for SelectionDesc { impl fmt::Display for SelectionDesc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{},{}", self.left, self.right) write!(f, "{},{}", self.left, self.right)

View File

@ -118,7 +118,16 @@ pub fn set(options: &Options) -> Result<String, KakError> {
&left_ordered_counts, &left_ordered_counts,
&right_ordered_counts, &right_ordered_counts,
)?, )?,
Operation::Intersect | Operation::Subtract | Operation::Union => print_result(&result)?, Operation::Union => print_result(&result)?,
Operation::Intersect | Operation::Subtract => {
if left_register == Register::Underscore {
// If the user asked for an intersection or subtraction from the current selection, we can update selection_descs only
reduce_selections(&options, &result)?
} else {
// The user asked for registers that *aren't* the current selection
print_result(&result)?
}
}
} }
Ok(match &operation { Ok(match &operation {
@ -133,6 +142,36 @@ pub fn set(options: &Options) -> Result<String, KakError> {
}) })
} }
/// Reduces selections to those that are in the key_set_operation_result
fn reduce_selections(
options: &Options,
key_set_operation_result: &LinkedHashSet<&Selection>,
) -> Result<(), KakError> {
kakplugin::restore_register(&Register::Caret)?;
let selections_with_desc = {
let mut r = get_selections_with_desc()?;
r.sort_by_key(|s| s.desc.sort());
r
};
eprintln!("Key set operation result: {:?}", key_set_operation_result);
set_selections_desc(selections_with_desc.into_iter().filter_map(|swd| {
// Does not matter if the operation was - or &
// Since key_set_operation_result contains elements that should be in the set,
// we can just use contains here
let key = into_key(options, swd.content)?;
if key_set_operation_result.contains(&key) {
Some(swd.desc)
} else {
eprintln!("Key {key} not found");
None
}
}))?;
Ok(())
}
fn print_result(key_set_operation_result: &LinkedHashSet<&Selection>) -> Result<(), KakError> { fn print_result(key_set_operation_result: &LinkedHashSet<&Selection>) -> Result<(), KakError> {
// Manually set selections so we don't have to allocate a string // Manually set selections so we don't have to allocate a string
let mut f = kakplugin::open_command_fifo()?; let mut f = kakplugin::open_command_fifo()?;
@ -225,23 +264,34 @@ fn to_ordered_counts(options: &Options, sels: Vec<Selection>) -> LinkedHashMap<S
let mut ret = LinkedHashMap::new(); let mut ret = LinkedHashMap::new();
for i in sels { for i in sels {
let key = if options.no_trim { match into_key(options, i) {
i Some(key) => {
} else { let entry: &mut usize = ret.entry(key).or_insert(0);
i.trim().to_string() *entry = entry.saturating_add(1);
}; }
None => {
if key.is_empty() { // We don't want to even pretend to look at empty keys
// 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 ret
} }
fn into_key(options: &Options, sel: Selection) -> Option<Selection> {
let key = if options.no_trim {
sel
} else {
sel.trim().to_string()
};
if key.is_empty() {
// Never treat an empty string as a key
None
} else {
Some(key)
}
}
fn key_set_operation<'a>( fn key_set_operation<'a>(
operation: &Operation, operation: &Operation,
left_keys: &LinkedHashSet<&'a Selection>, left_keys: &LinkedHashSet<&'a Selection>,