Add subtract function
This commit is contained in:
parent
4923a86b5f
commit
d69cec4d73
@ -91,9 +91,9 @@ pub fn get_selections_with_desc() -> Result<Vec<SelectionWithDesc>, KakError> {
|
||||
/// # Errors
|
||||
///
|
||||
/// Will return `Err` if command fifo could not be opened, read from, or written to
|
||||
pub fn set_selections<'a, I, S: 'a + ?Sized>(selections: I) -> Result<(), KakError>
|
||||
pub fn set_selections<'a, I, S: 'a>(selections: I) -> Result<(), KakError>
|
||||
where
|
||||
I: IntoIterator<Item = &'a S>,
|
||||
I: IntoIterator<Item = S>,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
let mut selections_iter = selections.into_iter().peekable();
|
||||
|
@ -15,7 +15,7 @@ pub struct SelectionWithSubselections {
|
||||
pub subselections: Vec<SelectionWithDesc>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, PartialOrd, Ord, Eq, Debug)]
|
||||
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Debug)]
|
||||
pub struct SelectionDesc {
|
||||
pub left: AnchorPosition,
|
||||
pub right: AnchorPosition,
|
||||
@ -47,6 +47,76 @@ impl SelectionDesc {
|
||||
|
||||
sorted_b.left >= sorted_a.left && sorted_b.right <= sorted_a.right
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn subtract(&self, b: &Self) -> Vec<Self> {
|
||||
// let sorted_self = self.sort();
|
||||
// let sorted_b = b.sort();
|
||||
|
||||
// My left is contained in b
|
||||
let left_contained = b.contains(&SelectionDesc {
|
||||
left: self.left,
|
||||
right: self.left,
|
||||
});
|
||||
// My right is contained in b
|
||||
let right_contained = b.contains(&SelectionDesc {
|
||||
left: self.right,
|
||||
right: self.right,
|
||||
});
|
||||
// b is contaned in self
|
||||
let b_contained = self.contains(b);
|
||||
|
||||
match (left_contained, right_contained, b_contained) {
|
||||
(true, true, _) => {
|
||||
// self is contained by b
|
||||
vec![]
|
||||
}
|
||||
(false, false, false) => {
|
||||
// There is no intersection
|
||||
// TODO: Why can't I clone myself?
|
||||
vec![self.clone()]
|
||||
}
|
||||
(false, false, true) => {
|
||||
// B is contained and it does not intersect with left or right
|
||||
vec![
|
||||
Self {
|
||||
left: self.left,
|
||||
right: AnchorPosition {
|
||||
row: b.left.row,
|
||||
col: b.left.col.saturating_sub(1),
|
||||
},
|
||||
},
|
||||
Self {
|
||||
left: AnchorPosition {
|
||||
row: b.right.row,
|
||||
col: b.right.col.saturating_add(1),
|
||||
},
|
||||
right: self.right,
|
||||
},
|
||||
]
|
||||
}
|
||||
(true, false, _) => {
|
||||
// Only self's left is contained
|
||||
vec![Self {
|
||||
left: AnchorPosition {
|
||||
row: b.right.row,
|
||||
col: b.right.col.saturating_add(1),
|
||||
},
|
||||
right: self.right,
|
||||
}]
|
||||
}
|
||||
(false, true, _) => {
|
||||
// Only self's right is contained
|
||||
vec![Self {
|
||||
left: self.left,
|
||||
right: AnchorPosition {
|
||||
row: b.left.row,
|
||||
col: b.left.col.saturating_sub(1),
|
||||
},
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<SelectionDesc> for SelectionDesc {
|
||||
@ -75,7 +145,7 @@ impl FromStr for SelectionDesc {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialOrd, PartialEq, Clone, Eq, Ord, Debug)]
|
||||
#[derive(PartialOrd, PartialEq, Copy, Clone, Eq, Ord, Debug)]
|
||||
pub struct AnchorPosition {
|
||||
pub row: usize,
|
||||
pub col: usize,
|
||||
@ -454,6 +524,18 @@ impl FromStr for Register {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
// Selection desc creator
|
||||
macro_rules! sd {
|
||||
($b:expr, $d:expr) => {{
|
||||
sd!(1,$b,1,$d)
|
||||
}};
|
||||
($a:expr, $b:expr,$c:expr,$d:expr) => {{
|
||||
SelectionDesc {
|
||||
left: AnchorPosition { row: $a, col: $b },
|
||||
right: AnchorPosition { row: $c, col: $d },
|
||||
}
|
||||
}};
|
||||
}
|
||||
const SD: SelectionDesc = SelectionDesc {
|
||||
left: AnchorPosition { row: 18, col: 9 },
|
||||
right: AnchorPosition { row: 10, col: 1 },
|
||||
@ -461,39 +543,104 @@ mod test {
|
||||
#[test]
|
||||
fn test_anchor_position() {
|
||||
// Check parsing
|
||||
assert_eq!(SelectionDesc::from_str("18.9,10.1").unwrap(), SD);
|
||||
assert_eq!(sd!(18,9,10,1), SD);
|
||||
// Check if multiple parsed ones match
|
||||
assert_eq!(
|
||||
SelectionDesc::from_str("18.9,10.1").unwrap(),
|
||||
SelectionDesc::from_str("18.9,10.1").unwrap()
|
||||
sd!(18,9,10,1),
|
||||
sd!(18,9,10,1)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sort() {
|
||||
// Check if sorting works
|
||||
assert_eq!(SD.sort(), SelectionDesc::from_str("10.1,18.9").unwrap());
|
||||
assert_eq!(SD.sort(), sd!(10,1,18,9));
|
||||
assert_eq!(SD.sort(), SD.sort().sort());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_contains() {
|
||||
assert!(SD.contains(&SD));
|
||||
assert!(SD.contains(&SelectionDesc::from_str("17.9,10.1").unwrap()));
|
||||
assert!(SD.contains(&SelectionDesc::from_str("18.8,10.1").unwrap()));
|
||||
assert!(SD.contains(&SelectionDesc::from_str("18.9,11.1").unwrap()));
|
||||
assert!(SD.contains(&SelectionDesc::from_str("18.9,10.2").unwrap()));
|
||||
assert!(SD.contains(&SelectionDesc::from_str("10.1,17.9").unwrap()));
|
||||
assert!(SD.contains(&SelectionDesc::from_str("10.1,18.8").unwrap()));
|
||||
assert!(SD.contains(&SelectionDesc::from_str("11.1,18.9").unwrap()));
|
||||
assert!(SD.contains(&SelectionDesc::from_str("10.2,18.9").unwrap()));
|
||||
assert!(!SD.contains(&SelectionDesc::from_str("19.9,10.1").unwrap()));
|
||||
assert!(!SD.contains(&SelectionDesc::from_str("18.10,10.1").unwrap()));
|
||||
assert!(!SD.contains(&SelectionDesc::from_str("18.9,9.1").unwrap()));
|
||||
assert!(!SD.contains(&SelectionDesc::from_str("18.9,10.0").unwrap()));
|
||||
assert!(!SD.contains(&SelectionDesc::from_str("10.1,19.9").unwrap()));
|
||||
assert!(!SD.contains(&SelectionDesc::from_str("10.1,18.10").unwrap()));
|
||||
assert!(!SD.contains(&SelectionDesc::from_str("9.1,18.9").unwrap()));
|
||||
assert!(!SD.contains(&SelectionDesc::from_str("10.0,18.9").unwrap()));
|
||||
assert!(SD.contains(&sd!(17,9,10,1)));
|
||||
assert!(SD.contains(&sd!(18,8,10,1)));
|
||||
assert!(SD.contains(&sd!(18,9,11,1)));
|
||||
assert!(SD.contains(&sd!(18,9,10,2)));
|
||||
assert!(SD.contains(&sd!(10,1,17,9)));
|
||||
assert!(SD.contains(&sd!(10,1,18,8)));
|
||||
assert!(SD.contains(&sd!(11,1,18,9)));
|
||||
assert!(SD.contains(&sd!(10,2,18,9)));
|
||||
assert!(!SD.contains(&sd!(19,9,10,1)));
|
||||
assert!(!SD.contains(&sd!(18,10,10,1)));
|
||||
assert!(!SD.contains(&sd!(18,9,9,1)));
|
||||
assert!(!SD.contains(&sd!(18,9,10,0)));
|
||||
assert!(!SD.contains(&sd!(10,1,19,9)));
|
||||
assert!(!SD.contains(&sd!(10,1,18,10)));
|
||||
assert!(!SD.contains(&sd!(9,1,18,9)));
|
||||
assert!(!SD.contains(&sd!(10,0,18,9)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_subtract() {
|
||||
// Testing a-b
|
||||
|
||||
// 01234567
|
||||
// a: ^_^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(1, 3).subtract(&sd!(0, 5)), vec![]);
|
||||
|
||||
// 01234567
|
||||
// a: ^__^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(0, 3).subtract(&sd!(0, 5)), vec![]);
|
||||
|
||||
// 01234567
|
||||
// a: ^___^
|
||||
// b: ^___^
|
||||
assert_eq!(sd!(1, 5).subtract(&sd!(1, 5)), vec![]);
|
||||
|
||||
// 01234567
|
||||
// a: ^_____^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(0, 6).subtract(&sd!(0, 5)), vec![sd!(6, 6)]);
|
||||
|
||||
// 01234567
|
||||
// a: ^____^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(1, 6).subtract(&sd!(0, 5)), vec![sd!(6, 6)]);
|
||||
|
||||
// 01234567
|
||||
// a: ^____^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(0, 5).subtract(&sd!(1, 6)), vec![sd!(0, 0)]);
|
||||
|
||||
// 01234567
|
||||
// a: ^______^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(0, 7).subtract(&sd!(1, 6)), vec![sd!(0, 0), sd!(7, 7)]);
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(3, 3).subtract(&sd!(0, 5)), vec![]);
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(0, 0).subtract(&sd!(0, 5)), vec![]);
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(0, 0).subtract(&sd!(1, 6)), vec![sd!(0, 0)]);
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(5, 5).subtract(&sd!(0, 5)), vec![]);
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(6, 6).subtract(&sd!(0, 5)), vec![sd!(6, 6)]);
|
||||
}
|
||||
}
|
||||
|
10
src/box_.rs
10
src/box_.rs
@ -5,11 +5,11 @@ use std::cmp::{max, min};
|
||||
#[derive(clap::StructOpt, Debug)]
|
||||
pub struct Options {
|
||||
// /// Bounding box mode, which selects the largest box to contain everything
|
||||
// #[clap(short, long, help = "Select the bonding box of all selections")]
|
||||
// bounding_box: bool,
|
||||
// /// Allow selecting trailing newlines
|
||||
// #[clap(short, long, help = "Allow selecting trailing newlines")]
|
||||
// preserve_newlines: bool,
|
||||
// #[clap(short, long, help = "Select the bonding box of all selections")]
|
||||
// bounding_box: bool,
|
||||
// /// Allow selecting trailing newlines
|
||||
// #[clap(short, long, help = "Allow selecting trailing newlines")]
|
||||
// preserve_newlines: bool,
|
||||
}
|
||||
|
||||
pub fn box_(options: &Options) -> Result<String, KakError> {
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
mod box_;
|
||||
mod errors;
|
||||
// mod invert;
|
||||
mod math_eval;
|
||||
mod set;
|
||||
mod shuf;
|
||||
|
@ -1,44 +1,33 @@
|
||||
use evalexpr::{eval, Value};
|
||||
use kakplugin::{get_selections, open_command_fifo, KakError};
|
||||
use kakplugin::{get_selections, open_command_fifo, set_selections, KakError, Selection};
|
||||
use std::io::Write;
|
||||
|
||||
// TODO: Context for log() and others
|
||||
|
||||
#[derive(clap::StructOpt, Debug)]
|
||||
pub struct Options;
|
||||
pub fn math_eval(_options: &Options) -> Result<String, KakError> {
|
||||
let selections = get_selections()?;
|
||||
|
||||
let mut f = open_command_fifo()?;
|
||||
write!(f, "reg '\"'")?;
|
||||
|
||||
let mut err = None;
|
||||
let mut err_count: usize = 0;
|
||||
|
||||
for i in selections.iter().map(|s| {
|
||||
// TODO: Do all of these need to be strings?
|
||||
match eval(s) {
|
||||
Ok(Value::Float(f)) => Some(f.to_string()),
|
||||
Ok(Value::Int(f)) => Some(f.to_string()),
|
||||
// TODO: Should this be none?
|
||||
Ok(_) => None,
|
||||
let selections = get_selections()?;
|
||||
|
||||
set_selections(selections.iter().map(|s| match eval(s) {
|
||||
Ok(Value::Float(f)) => f.to_string(),
|
||||
Ok(Value::Int(f)) => f.to_string(),
|
||||
Ok(_) => String::from(""),
|
||||
Err(e) => {
|
||||
eprintln!("Error: {:?}", e);
|
||||
if err.is_none() {
|
||||
err = Some(e);
|
||||
err_count = err_count.saturating_add(1);
|
||||
// Set the selection to empty
|
||||
String::from("")
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}) {
|
||||
// TODO: String allocation?
|
||||
let new_selection = i.map(|s| s.replace('\'', "''"));
|
||||
// .unwrap_or_else(|| "".to_string());
|
||||
write!(f, " '{}'", new_selection.as_deref().unwrap_or(""))?;
|
||||
}
|
||||
write!(f, " ; exec R;")?;
|
||||
f.flush()?;
|
||||
}))?;
|
||||
|
||||
Ok(format!("MathEval {} selections", selections.len()))
|
||||
Ok(if err_count == 0 {
|
||||
format!("Processed {} selections", selections.len())
|
||||
} else {
|
||||
format!(
|
||||
"Processed {} selections ({} errors)",
|
||||
selections.len().saturating_sub(err_count),
|
||||
err_count
|
||||
)
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user