Start working on new features
This commit is contained in:
parent
0aacd16f50
commit
8a3a77df55
@ -1,6 +1,10 @@
|
||||
use crate::KakError;
|
||||
use core::fmt::{Display, Formatter};
|
||||
use std::{fmt, str::FromStr};
|
||||
use std::{
|
||||
cmp::{max, min},
|
||||
fmt,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
pub type Selection = String;
|
||||
|
||||
@ -23,6 +27,50 @@ pub struct SelectionWithSubselections {
|
||||
pub subselections: Vec<SelectionWithDesc>,
|
||||
}
|
||||
|
||||
/// A selection desc that spans only one row
|
||||
///
|
||||
/// This type is required when doing operations that involve multiple lines, but logic cannot exist to see if, for example, 2 selection descs with row:1 col:1-10 and row:2 col:0-1 is adjacent
|
||||
#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Debug)]
|
||||
pub struct RowSelectionDesc {
|
||||
pub row: usize,
|
||||
pub left_col: usize,
|
||||
pub right_col: usize,
|
||||
}
|
||||
|
||||
// impl RowSelectionDesc {
|
||||
// pub fn
|
||||
// }
|
||||
|
||||
impl TryFrom<SelectionDesc> for RowSelectionDesc {
|
||||
type Error = KakError;
|
||||
fn try_from(sd: SelectionDesc) -> Result<Self, Self::Error> {
|
||||
if sd.left.row == sd.right.row {
|
||||
Ok(Self {
|
||||
row: sd.left.row,
|
||||
left_col: sd.left.col,
|
||||
right_col: sd.right.col,
|
||||
})
|
||||
} else {
|
||||
Err(KakError::MultiRowSelectionNotSupported)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<SelectionDesc> for RowSelectionDesc {
|
||||
fn into(self) -> SelectionDesc {
|
||||
SelectionDesc {
|
||||
left: AnchorPosition {
|
||||
row: self.row,
|
||||
col: self.left_col,
|
||||
},
|
||||
right: AnchorPosition {
|
||||
row: self.row,
|
||||
col: self.right_col,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Debug)]
|
||||
pub struct SelectionDesc {
|
||||
pub left: AnchorPosition,
|
||||
@ -48,37 +96,77 @@ impl SelectionDesc {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn contains(&self, b: &Self) -> bool {
|
||||
pub fn contains<ISD>(&self, other: ISD) -> bool
|
||||
where
|
||||
ISD: Into<Self>,
|
||||
{
|
||||
// Cursor and anchor can be flipped. Set a.0 to be leftmost cursor
|
||||
let sorted_a = self.sort();
|
||||
let sorted_b = b.sort();
|
||||
let (a, b) = (self.sort(), other.into().sort());
|
||||
|
||||
sorted_b.left >= sorted_a.left && sorted_b.right <= sorted_a.right
|
||||
b.left >= a.left && b.right <= a.right
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn intersect(&self, other: &Self) -> Option<Self> {
|
||||
// Set a and b to the leftmost and rightmost selection
|
||||
let (a, b) = (min(self, other).sort(), max(self, other).sort());
|
||||
|
||||
if a.contains(&b.left)
|
||||
|| a.contains(&b.right)
|
||||
|| b.contains(&a.left)
|
||||
|| b.contains(&a.right)
|
||||
{
|
||||
// Some(Self {})
|
||||
None
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn partial_union(&self, other: &Self) -> Option<Self> {
|
||||
// Set a and b to the leftmost and rightmost selection
|
||||
let (a, b) = (min(self, other).sort(), max(self, other).sort());
|
||||
eprintln!("Partial union args: a: {a:#?}, b: {b:#?}");
|
||||
|
||||
eprintln!(
|
||||
"Checking if {} contains {}: {}",
|
||||
a,
|
||||
b.left,
|
||||
a.contains(&b.left)
|
||||
);
|
||||
eprintln!(
|
||||
"Checking if {} contains {}: {}",
|
||||
b,
|
||||
a.right,
|
||||
b.contains(&a.right)
|
||||
);
|
||||
|
||||
// Either the left side of b is contained b a, or
|
||||
// This will not work when the right side of a is the end of line and the left side of b is beginning of line
|
||||
// This is because selection descs do not know when a selection desc is at the end of a line
|
||||
if a.contains(&b.left) || b.contains(&a.right)
|
||||
// If b's left is one col off from a's right
|
||||
// || (a.right.row == b_left.row && a.right.col == b.left.col.saturating_sub(1))
|
||||
// Or b's right is
|
||||
// || (a.left.row == b_left.row && a.left.col == b.right.col.saturating_sub(1))
|
||||
{
|
||||
Some(SelectionDesc {
|
||||
left: min(a.left, b.left),
|
||||
right: max(a.right, b.right),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn subtract(&self, b: &Self) -> MaybeSplit<Self> {
|
||||
// let sorted_self = self.sort();
|
||||
// let sorted_b = b.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) {
|
||||
match (sorted_b.contains(&self.left), sorted_b.contains(&self.right), self.contains(&sorted_b)) {
|
||||
(true, true, _) => {
|
||||
// self is contained by b
|
||||
// self is contained by sorted_b
|
||||
MaybeSplit::Nothing
|
||||
}
|
||||
(false, false, false) => {
|
||||
@ -92,14 +180,14 @@ impl SelectionDesc {
|
||||
Self {
|
||||
left: self.left,
|
||||
right: AnchorPosition {
|
||||
row: b.left.row,
|
||||
col: b.left.col.saturating_sub(1),
|
||||
row: sorted_b.left.row,
|
||||
col: sorted_b.left.col.saturating_sub(1),
|
||||
},
|
||||
},
|
||||
Self {
|
||||
left: AnchorPosition {
|
||||
row: b.right.row,
|
||||
col: b.right.col.saturating_add(1),
|
||||
row: sorted_b.right.row,
|
||||
col: sorted_b.right.col.saturating_add(1),
|
||||
},
|
||||
right: self.right,
|
||||
},
|
||||
@ -109,8 +197,8 @@ impl SelectionDesc {
|
||||
// Only self's left is contained
|
||||
MaybeSplit::Just(Self {
|
||||
left: AnchorPosition {
|
||||
row: b.right.row,
|
||||
col: b.right.col.saturating_add(1),
|
||||
row: sorted_b.right.row,
|
||||
col: sorted_b.right.col.saturating_add(1),
|
||||
},
|
||||
right: self.right,
|
||||
})
|
||||
@ -120,8 +208,8 @@ impl SelectionDesc {
|
||||
MaybeSplit::Just(Self {
|
||||
left: self.left,
|
||||
right: AnchorPosition {
|
||||
row: b.left.row,
|
||||
col: b.left.col.saturating_sub(1),
|
||||
row: sorted_b.left.row,
|
||||
col: sorted_b.left.col.saturating_sub(1),
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -129,6 +217,21 @@ impl SelectionDesc {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&SelectionDesc> for SelectionDesc {
|
||||
fn from(sd: &SelectionDesc) -> Self {
|
||||
sd.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&AnchorPosition> for SelectionDesc {
|
||||
fn from(ap: &AnchorPosition) -> Self {
|
||||
Self {
|
||||
left: ap.clone(),
|
||||
right: ap.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<SelectionDesc> for SelectionDesc {
|
||||
fn as_ref(&self) -> &Self {
|
||||
&self
|
||||
@ -552,6 +655,36 @@ mod test {
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
// Reversed
|
||||
macro_rules! sdr {
|
||||
($b:expr, $d:expr) => {{
|
||||
sd!(1, $d, 1, $b)
|
||||
}};
|
||||
($a:expr, $b:expr,$c:expr,$d:expr) => {{
|
||||
SelectionDesc {
|
||||
left: AnchorPosition { row: $c, col: $d },
|
||||
right: AnchorPosition { row: $a, col: $b },
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! mixed_test {
|
||||
($left:tt, $op:ident, $right:tt, $expected:expr) => {
|
||||
eprintln!("Testing ({}).{}({})", sd!$left, stringify!($op), &sd!$right);
|
||||
assert_eq!(sd!$left.$op(&sd!$right), $expected);
|
||||
|
||||
eprintln!("Testing ({}).{}({})", sd!$left, stringify!($op), &sdr!$right);
|
||||
assert_eq!(sd!$left.$op(&sdr!$right), $expected);
|
||||
|
||||
eprintln!("Testing ({}).{}({})", sdr!$left, stringify!($op), &sd!$right);
|
||||
assert_eq!(sdr!$left.$op(&sd!$right), $expected);
|
||||
|
||||
eprintln!("Testing ({}).{}({})", sdr!$left, stringify!($op), &sdr!$right);
|
||||
assert_eq!(sdr!$left.$op(&sdr!$right), $expected);
|
||||
}
|
||||
}
|
||||
|
||||
const SD: SelectionDesc = SelectionDesc {
|
||||
left: AnchorPosition { row: 18, col: 9 },
|
||||
right: AnchorPosition { row: 10, col: 1 },
|
||||
@ -566,9 +699,10 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_sort() {
|
||||
// Check if sorting works
|
||||
assert_eq!(SD.sort(), sd!(10, 1, 18, 9));
|
||||
assert_eq!(SD.sort(), SD.sort().sort());
|
||||
assert_eq!(sd!(10, 1, 18, 9).sort(), sd!(10, 1, 18, 9));
|
||||
assert_eq!(sdr!(10, 1, 18, 9).sort(), sd!(10, 1, 18, 9));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -590,6 +724,98 @@ mod test {
|
||||
assert!(!SD.contains(&sd!(10, 1, 18, 10)));
|
||||
assert!(!SD.contains(&sd!(9, 1, 18, 9)));
|
||||
assert!(!SD.contains(&sd!(10, 0, 18, 9)));
|
||||
|
||||
assert!(SD.contains(&sdr!(17, 9, 10, 1)));
|
||||
assert!(SD.contains(&sdr!(18, 8, 10, 1)));
|
||||
assert!(SD.contains(&sdr!(18, 9, 11, 1)));
|
||||
assert!(SD.contains(&sdr!(18, 9, 10, 2)));
|
||||
assert!(SD.contains(&sdr!(10, 1, 17, 9)));
|
||||
assert!(SD.contains(&sdr!(10, 1, 18, 8)));
|
||||
assert!(SD.contains(&sdr!(11, 1, 18, 9)));
|
||||
assert!(SD.contains(&sdr!(10, 2, 18, 9)));
|
||||
assert!(!SD.contains(&sdr!(19, 9, 10, 1)));
|
||||
assert!(!SD.contains(&sdr!(18, 10, 10, 1)));
|
||||
assert!(!SD.contains(&sdr!(18, 9, 9, 1)));
|
||||
assert!(!SD.contains(&sdr!(18, 9, 10, 0)));
|
||||
assert!(!SD.contains(&sdr!(10, 1, 19, 9)));
|
||||
assert!(!SD.contains(&sdr!(10, 1, 18, 10)));
|
||||
assert!(!SD.contains(&sdr!(9, 1, 18, 9)));
|
||||
assert!(!SD.contains(&sdr!(10, 0, 18, 9)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_partial_union() {
|
||||
// Testing a+b
|
||||
|
||||
// 01234567
|
||||
// a: ^_^
|
||||
// b: ^____^
|
||||
mixed_test!((1, 3), partial_union, (0, 5), Some(sd!(0, 5)));
|
||||
|
||||
// 01234567
|
||||
// a: ^__^
|
||||
// b: ^____^
|
||||
mixed_test!((0, 3), partial_union, (0, 5), Some(sd!(0, 5)));
|
||||
|
||||
// 01234567
|
||||
// a: ^___^
|
||||
// b: ^___^
|
||||
mixed_test!((1, 5), partial_union, (1, 5), Some(sd!(1, 5)));
|
||||
|
||||
// 01234567
|
||||
// a: ^_____^
|
||||
// b: ^____^
|
||||
mixed_test!((0, 6), partial_union, (0, 5), Some(sd!(0, 6)));
|
||||
|
||||
// 01234567
|
||||
// a: ^____^
|
||||
// b: ^____^
|
||||
mixed_test!((1, 6), partial_union, (0, 5), Some(sd!(0, 6)));
|
||||
|
||||
// 01234567
|
||||
// a: ^____^
|
||||
// b: ^____^
|
||||
mixed_test!((0, 5), partial_union, (1, 6), Some(sd!(0, 6)));
|
||||
|
||||
// 01234567
|
||||
// a: ^______^
|
||||
// b: ^____^
|
||||
mixed_test!((0, 7), partial_union, (1, 6), Some(sd!(0, 7)));
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
mixed_test!((3, 3), partial_union, (0, 5), Some(sd!(0, 5)));
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
mixed_test!((0, 0), partial_union, (0, 5), Some(sd!(0, 5)));
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
mixed_test!((0, 0), partial_union, (1, 6), Some(sd!(0, 6)));
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
mixed_test!((5, 5), partial_union, (0, 5), Some(sd!(0, 5)));
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
mixed_test!((6, 6), partial_union, (0, 5), Some(sd!(0, 6)));
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
mixed_test!((7, 7), partial_union, (0, 5), None);
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
mixed_test!((0, 0), partial_union, (2, 7), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -600,63 +826,72 @@ mod test {
|
||||
// a: ^_^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(1, 3).subtract(&sd!(0, 5)), MaybeSplit::Nothing);
|
||||
assert_eq!(sd!(1, 3).subtract(&sdr!(0, 5)), MaybeSplit::Nothing);
|
||||
|
||||
// 01234567
|
||||
// a: ^__^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(0, 3).subtract(&sd!(0, 5)), MaybeSplit::Nothing);
|
||||
assert_eq!(sd!(0, 3).subtract(&sdr!(0, 5)), MaybeSplit::Nothing);
|
||||
|
||||
// 01234567
|
||||
// a: ^___^
|
||||
// b: ^___^
|
||||
assert_eq!(sd!(1, 5).subtract(&sd!(1, 5)), MaybeSplit::Nothing);
|
||||
assert_eq!(sd!(1, 5).subtract(&sdr!(1, 5)), MaybeSplit::Nothing);
|
||||
|
||||
// 01234567
|
||||
// a: ^_____^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(0, 6).subtract(&sd!(0, 5)), MaybeSplit::Just(sd!(6, 6)));
|
||||
assert_eq!(sd!(0, 6).subtract(&sdr!(0, 5)), MaybeSplit::Just(sd!(6, 6)));
|
||||
|
||||
// 01234567
|
||||
// a: ^____^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(1, 6).subtract(&sd!(0, 5)), MaybeSplit::Just(sd!(6, 6)));
|
||||
assert_eq!(sd!(1, 6).subtract(&sdr!(0, 5)), MaybeSplit::Just(sd!(6, 6)));
|
||||
|
||||
// 01234567
|
||||
// a: ^____^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(0, 5).subtract(&sd!(1, 6)), MaybeSplit::Just(sd!(0, 0)));
|
||||
assert_eq!(sd!(0, 5).subtract(&sdr!(1, 6)), MaybeSplit::Just(sd!(0, 0)));
|
||||
|
||||
// 01234567
|
||||
// a: ^______^
|
||||
// b: ^____^
|
||||
assert_eq!(
|
||||
sd!(0, 7).subtract(&sd!(1, 6)),
|
||||
MaybeSplit::JustTwo(sd!(0, 0), sd!(7, 7))
|
||||
);
|
||||
assert_eq!(sd! (0, 7).subtract(&sd!(1, 6)), MaybeSplit::JustTwo(sd!(0, 0), sd!(7, 7)) );
|
||||
assert_eq!(sd! (0, 7).subtract(&sdr!(1, 6)), MaybeSplit::JustTwo(sd!(0, 0), sd!(7, 7)) );
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(3, 3).subtract(&sd!(0, 5)), MaybeSplit::Nothing);
|
||||
assert_eq!(sd!(3, 3).subtract(&sdr!(0, 5)), MaybeSplit::Nothing);
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(0, 0).subtract(&sd!(0, 5)), MaybeSplit::Nothing);
|
||||
assert_eq!(sd!(0, 0).subtract(&sdr!(0, 5)), MaybeSplit::Nothing);
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(0, 0).subtract(&sd!(1, 6)), MaybeSplit::Just(sd!(0, 0)));
|
||||
assert_eq!(sd!(0, 0).subtract(&sdr!(1, 6)), MaybeSplit::Just(sd!(0, 0)));
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(5, 5).subtract(&sd!(0, 5)), MaybeSplit::Nothing);
|
||||
assert_eq!(sd!(5, 5).subtract(&sdr!(0, 5)), MaybeSplit::Nothing);
|
||||
|
||||
// 01234567
|
||||
// a: ^
|
||||
// b: ^____^
|
||||
assert_eq!(sd!(6, 6).subtract(&sd!(0, 5)), MaybeSplit::Just(sd!(6, 6)));
|
||||
assert_eq!(sd!(6, 6).subtract(&sdr!(0, 5)), MaybeSplit::Just(sd!(6, 6)));
|
||||
}
|
||||
}
|
||||
|
19
src/box_.rs
19
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> {
|
||||
@ -55,6 +55,15 @@ fn bounding_box(_options: &Options) -> Result<Vec<SelectionDesc>, KakError> {
|
||||
})
|
||||
.ok_or_else(|| KakError::Custom(String::from("Selection is empty")))?;
|
||||
|
||||
// let (leftmost_row, rightmost_row) = selection_descs
|
||||
// .first()
|
||||
// .map(|sd| sd.left.row)
|
||||
// .zip(selection_descs.last().map(|sd| sd.right.row))
|
||||
// .ok_or_else(|| KakError::Custom(String::from("Selection is empty")))?;
|
||||
|
||||
// Get every line in the document
|
||||
// let document_selections_desc: Vec<SelectionDesc> = get_selections_desc(Some("%<a-s>"))?;
|
||||
|
||||
// Now, split on newline
|
||||
// TODO: Should I use <a-s>?
|
||||
// kakplugin::cmd(&format!("exec 'S\\n<ret>'"))?;
|
||||
|
Loading…
Reference in New Issue
Block a user