Refactor sorting selections
This commit is contained in:
parent
4bf376d802
commit
9b847eff0d
18
src/kak.rs
18
src/kak.rs
@ -14,6 +14,12 @@ pub struct SelectionWithDesc {
|
|||||||
pub desc: SelectionDesc,
|
pub desc: SelectionDesc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
|
pub struct SelectionWithSubselections {
|
||||||
|
pub selection: SelectionWithDesc,
|
||||||
|
pub subselections: Vec<SelectionWithDesc>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, PartialOrd, Ord, Eq, Debug)]
|
#[derive(PartialEq, PartialOrd, Ord, Eq, Debug)]
|
||||||
pub struct SelectionDesc {
|
pub struct SelectionDesc {
|
||||||
pub left: AnchorPosition,
|
pub left: AnchorPosition,
|
||||||
@ -115,6 +121,18 @@ pub fn get_selections_desc() -> Result<Vec<SelectionDesc>, KakMessage> {
|
|||||||
.collect::<Result<Vec<_>, KakMessage>>()
|
.collect::<Result<Vec<_>, KakMessage>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn get_selections_with_subselections(
|
||||||
|
// register: &str,
|
||||||
|
// ) -> Result<Vec<SelectionWithSubselections>, KakMessage> {
|
||||||
|
// // TODO: Escape register
|
||||||
|
// let subselections = get_selections_with_desc()?;
|
||||||
|
// exec(format!("\"{}z", register.replace('\'', "''")))?;
|
||||||
|
// let selections = get_selections_with_desc()?;
|
||||||
|
|
||||||
|
// for sel in selections {
|
||||||
|
// for i in subselections {}
|
||||||
|
// }
|
||||||
|
// }
|
||||||
/// # 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,
|
||||||
|
@ -13,7 +13,7 @@ mod errors;
|
|||||||
mod kak;
|
mod kak;
|
||||||
mod math_eval;
|
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;
|
||||||
@ -34,7 +34,7 @@ struct Cli {
|
|||||||
|
|
||||||
#[derive(Subcommand, Debug)]
|
#[derive(Subcommand, Debug)]
|
||||||
enum Commands {
|
enum Commands {
|
||||||
// Sort(sort::Options),
|
Sort(sort::Options),
|
||||||
Shuf(shuf::Options),
|
Shuf(shuf::Options),
|
||||||
Uniq(uniq::Options),
|
Uniq(uniq::Options),
|
||||||
#[clap(visible_aliases = &["bc", "eval"])]
|
#[clap(visible_aliases = &["bc", "eval"])]
|
||||||
@ -69,7 +69,7 @@ fn run() -> Result<KakMessage, KakMessage> {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
match &options.command {
|
match &options.command {
|
||||||
// Commands::Sort(o) => sort::sort(o),
|
Commands::Sort(o) => sort::sort(o),
|
||||||
Commands::Shuf(o) => shuf::shuf(o),
|
Commands::Shuf(o) => shuf::shuf(o),
|
||||||
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),
|
||||||
|
201
src/sort.rs
201
src/sort.rs
@ -1,9 +1,7 @@
|
|||||||
use crate::{
|
use crate::{get_selections_with_desc, kak, open_command_fifo, KakMessage, SelectionWithDesc};
|
||||||
get_selections_with_desc, kak, open_command_fifo, KakMessage, SelectionDesc, SelectionWithDesc,
|
|
||||||
};
|
|
||||||
use alphanumeric_sort::compare_str;
|
use alphanumeric_sort::compare_str;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{cmp::Ordering, io::Write, str::FromStr};
|
use std::{cmp::Ordering, io::Write};
|
||||||
|
|
||||||
#[derive(clap::StructOpt, Debug)]
|
#[derive(clap::StructOpt, Debug)]
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
@ -33,7 +31,7 @@ fn invert_bool(s: &str) -> Result<bool, &'static str> {
|
|||||||
|
|
||||||
struct SortableSelection<'a> {
|
struct SortableSelection<'a> {
|
||||||
/// The content of the selection
|
/// The content of the selection
|
||||||
content: &'a str,
|
selection: &'a SelectionWithDesc,
|
||||||
/// The string used to compare the content
|
/// The string used to compare the content
|
||||||
content_comparison: &'a str,
|
content_comparison: &'a str,
|
||||||
/// Any subselections
|
/// Any subselections
|
||||||
@ -41,77 +39,78 @@ 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>(
|
/// TODO: Implement sort by subselection
|
||||||
options: &'b Options,
|
// fn get_sortable_selections_subselections<'a, 'b, 'tmp, S: AsRef<str> + std::fmt::Debug + 'a>(
|
||||||
selections: Vec<SelectionWithDesc>,
|
// options: &'b Options,
|
||||||
subselections: Vec<SelectionWithDesc>,
|
// selections: Vec<SelectionWithDesc>,
|
||||||
) -> Result<Vec<SortableSelection<'a>>, KakMessage> {
|
// subselections: Vec<SelectionWithDesc>,
|
||||||
let mut sortable_selections = selections
|
// ) -> Result<Vec<SortableSelection<'a>>, KakMessage> {
|
||||||
.iter()
|
// let mut sortable_selections = selections
|
||||||
.zip(selections_desc.iter())
|
// .iter()
|
||||||
.map(|(s, sd)| {
|
// .zip(selections_desc.iter())
|
||||||
Ok((
|
// .map(|(s, sd)| {
|
||||||
to_sortable_selection(s.as_ref(), options),
|
// Ok((
|
||||||
SelectionDesc::from_str(sd.as_ref())?,
|
// to_sortable_selection(s.as_ref(), options),
|
||||||
))
|
// SelectionDesc::from_str(sd.as_ref())?,
|
||||||
})
|
// ))
|
||||||
.collect::<Result<Vec<(SortableSelection, SelectionDesc)>, KakMessage>>()?;
|
// })
|
||||||
|
// .collect::<Result<Vec<(SortableSelection, SelectionDesc)>, KakMessage>>()?;
|
||||||
|
|
||||||
let mut subselections = subselections
|
// let mut subselections = subselections
|
||||||
.iter()
|
// .iter()
|
||||||
.zip(subselections_desc.iter())
|
// .zip(subselections_desc.iter())
|
||||||
// Bind selection with associated description
|
// // Bind selection with associated description
|
||||||
// Sort descriptions so left is always <= right
|
// // Sort descriptions so left is always <= right
|
||||||
.map(|(s, sd)| Ok((s.as_ref(), SelectionDesc::from_str(sd.as_ref())?.sort())))
|
// .map(|(s, sd)| Ok((s.as_ref(), SelectionDesc::from_str(sd.as_ref())?.sort())))
|
||||||
.collect::<Result<Vec<(&str, SelectionDesc)>, KakMessage>>()?;
|
// .collect::<Result<Vec<(&str, SelectionDesc)>, KakMessage>>()?;
|
||||||
|
|
||||||
// Sort subselections by description
|
// // Sort subselections by description
|
||||||
subselections.sort_by(|(_, ssd_a), (_, ssd_b)| ssd_a.cmp(ssd_b));
|
// subselections.sort_by(|(_, ssd_a), (_, ssd_b)| ssd_a.cmp(ssd_b));
|
||||||
|
|
||||||
// For each selection, check if they contain any subselections
|
// // For each selection, check if they contain any subselections
|
||||||
// If so, add them to the subselections vector
|
// // If so, add them to the subselections vector
|
||||||
// TODO: This is O(n^2), but can be made more efficient since subselections is sorted
|
// // TODO: This is O(n^2), but can be made more efficient since subselections is sorted
|
||||||
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);
|
// s.subselections.push(i.0);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
sortable_selections.sort_by(|(a, _), (b, _)| {
|
// sortable_selections.sort_by(|(a, _), (b, _)| {
|
||||||
// First, check if there are any subselection comparisons to be made
|
// // First, check if there are any subselection comparisons to be made
|
||||||
// If one has more subselections than the other, stop comparing
|
// // If one has more subselections than the other, stop comparing
|
||||||
for (a_subsel, b_subsel) in a.subselections.iter().zip(b.subselections.iter()) {
|
// for (a_subsel, b_subsel) in a.subselections.iter().zip(b.subselections.iter()) {
|
||||||
match a_subsel.cmp(b_subsel) {
|
// match a_subsel.cmp(b_subsel) {
|
||||||
// These subselections are equal, so we can't do anything
|
// // These subselections are equal, so we can't do anything
|
||||||
Ordering::Equal => continue,
|
// Ordering::Equal => continue,
|
||||||
// We found a difference, so return the comparison
|
// // We found a difference, so return the comparison
|
||||||
o => return o,
|
// o => return o,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// No subselections mismatched, so compare the (possibly trimmed) content
|
// // No subselections mismatched, so compare the (possibly trimmed) content
|
||||||
a.content_comparison.cmp(b.content_comparison)
|
// a.content_comparison.cmp(b.content_comparison)
|
||||||
});
|
// });
|
||||||
|
|
||||||
Ok(sortable_selections.into_iter().map(|(s, _)| s).collect())
|
// Ok(sortable_selections.into_iter().map(|(s, _)| s).collect())
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn to_sortable_selection<'a, 'b>(
|
fn to_sortable_selection<'a, 'b>(
|
||||||
selection: &'a str,
|
selection: &'a SelectionWithDesc,
|
||||||
options: &'b Options,
|
options: &'b Options,
|
||||||
) -> SortableSelection<'a> {
|
) -> SortableSelection<'a> {
|
||||||
if options.no_skip_whitespace {
|
if options.no_skip_whitespace {
|
||||||
SortableSelection {
|
SortableSelection {
|
||||||
content: selection,
|
selection: &selection,
|
||||||
content_comparison: selection,
|
content_comparison: selection.content.as_str(),
|
||||||
subselections: vec![],
|
subselections: vec![],
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SortableSelection {
|
SortableSelection {
|
||||||
content: selection,
|
selection: &selection,
|
||||||
content_comparison: selection.trim(),
|
content_comparison: selection.content.as_str().trim(),
|
||||||
subselections: vec![],
|
subselections: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,46 +119,63 @@ fn to_sortable_selection<'a, 'b>(
|
|||||||
pub fn sort(options: &Options) -> Result<KakMessage, KakMessage> {
|
pub fn sort(options: &Options) -> Result<KakMessage, KakMessage> {
|
||||||
eprintln!("Got sort options: {:?}", options);
|
eprintln!("Got sort options: {:?}", options);
|
||||||
|
|
||||||
let subselections = options
|
// subselections is Some if the user requests it in subselections_register
|
||||||
|
// It will "exec z" to restore the selections before setting selections
|
||||||
|
// If subselections is None, "exec z" is not called
|
||||||
|
let subselections: Option<Vec<SelectionWithDesc>> = options
|
||||||
.subselections_register
|
.subselections_register
|
||||||
.map(|_r| -> Result<Vec<SelectionWithDesc>, KakMessage> {
|
.map::<Result<_, KakMessage>, _>(|c| {
|
||||||
let ret = get_selections_with_desc()?;
|
let subselections = get_selections_with_desc()?;
|
||||||
kak::exec("exec z")?;
|
kak::exec(&format!("exec {}", c))?;
|
||||||
Ok(ret)
|
Ok(subselections)
|
||||||
})
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
let selections = get_selections_with_desc()?;
|
let selections = get_selections_with_desc()?;
|
||||||
|
|
||||||
// let subselections: Option<(Vec<String>, Vec<String>)> = options
|
let mut zipped: Vec<SortableSelection<'_>> = match (&options.regex, &subselections) {
|
||||||
// .subselections_register
|
(Some(_), Some(_)) => {
|
||||||
// .map::<Result<(Vec<String>, Vec<String>), KakMessage>, _>(|_c| {
|
return Err("Cannot pass regex and subselections register"
|
||||||
// let subselections = kak::response("%val{selections}")?;
|
.to_string()
|
||||||
// let subselections_desc = kak::response("%val{selections_desc}")?;
|
.into())
|
||||||
// // kak_exec(&format!("exec z",))?;
|
}
|
||||||
// Ok((subselections, subselections_desc))
|
(None, None) => {
|
||||||
// })
|
// Do a regular sort on the content
|
||||||
// .transpose()?;
|
selections
|
||||||
// let selections = kak::response("%val{selections}")?;
|
.iter()
|
||||||
|
.map(|s| to_sortable_selection(s, options))
|
||||||
let mut zipped: Vec<SortableSelection<'_>> = match subselections {
|
.collect()
|
||||||
Some(subselections) => {
|
}
|
||||||
let selections_desc = kak::response("%val{selections_desc}")?;
|
(Some(regex), None) => {
|
||||||
|
// Sort based on the regular expression
|
||||||
get_sortable_selections_subselections(
|
selections
|
||||||
options,
|
.iter()
|
||||||
&selections,
|
.map(|s| {
|
||||||
&selections_desc,
|
let mut sortable_selection = to_sortable_selection(s, options);
|
||||||
subselections,
|
if let Some(regex_match) = (|| {
|
||||||
subselections_desc,
|
let captures = regex.captures(sortable_selection.content_comparison)?;
|
||||||
)?
|
captures
|
||||||
|
.get(1)
|
||||||
|
.or_else(|| captures.get(0))
|
||||||
|
.map(|m| m.as_str())
|
||||||
|
})() {
|
||||||
|
sortable_selection.content_comparison = regex_match;
|
||||||
|
}
|
||||||
|
|
||||||
|
sortable_selection
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
(None, _) => {
|
||||||
|
// Sort based on subselections
|
||||||
|
return Err(KakMessage(
|
||||||
|
"Not yet implemented".to_string(),
|
||||||
|
Some("Sort by subselection is not yet implemented".to_string()),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
None => selections
|
|
||||||
.iter()
|
|
||||||
.map(|s| to_sortable_selection(s, options))
|
|
||||||
.collect(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
zipped.sort_by(|a, b| {
|
zipped.sort_by(|a, b| {
|
||||||
|
// First, try sorting by subselection. This won't iterate anything if either is None (regex and default mode)
|
||||||
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 options.lexicographic_sort {
|
let comparison = if options.lexicographic_sort {
|
||||||
a_subselection.cmp(b_subselection)
|
a_subselection.cmp(b_subselection)
|
||||||
@ -172,6 +188,7 @@ pub fn sort(options: &Options) -> Result<KakMessage, KakMessage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise, default to comparing the content
|
||||||
if options.lexicographic_sort {
|
if options.lexicographic_sort {
|
||||||
a.content_comparison.cmp(b.content_comparison)
|
a.content_comparison.cmp(b.content_comparison)
|
||||||
} else {
|
} else {
|
||||||
@ -190,7 +207,7 @@ pub fn sort(options: &Options) -> Result<KakMessage, KakMessage> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for i in iter {
|
for i in iter {
|
||||||
let new_selection = i.content.replace('\'', "''");
|
let new_selection = i.selection.content.replace('\'', "''");
|
||||||
write!(f, " '{}'", new_selection)?;
|
write!(f, " '{}'", new_selection)?;
|
||||||
}
|
}
|
||||||
write!(f, " ; exec R;")?;
|
write!(f, " ; exec R;")?;
|
||||||
|
Loading…
Reference in New Issue
Block a user