aboutsummaryrefslogtreecommitdiff
path: root/rprt-engine/src
diff options
context:
space:
mode:
authortslil <tslil@posteo.de>2025-10-22 21:02:01 +0100
committertslil <tslil@posteo.de>2025-10-22 21:52:43 +0100
commit20674aa65148558fb849eb1bb9c8a5e4a0cf483d (patch)
treed2b54ae8b20ca0a7041b9d29f19f50944f47ed35 /rprt-engine/src
parent9f3e21628231f3fa91ab8ff45872a76e7e11fcc4 (diff)
Implement two basic selection functions
Diffstat (limited to 'rprt-engine/src')
-rw-r--r--rprt-engine/src/selection.rs110
-rw-r--r--rprt-engine/src/selection_function.rs77
-rw-r--r--rprt-engine/src/state.rs12
3 files changed, 132 insertions, 67 deletions
diff --git a/rprt-engine/src/selection.rs b/rprt-engine/src/selection.rs
index c15512d..ee83294 100644
--- a/rprt-engine/src/selection.rs
+++ b/rprt-engine/src/selection.rs
@@ -45,15 +45,15 @@ impl Interval {
#[derive(Debug, Clone)]
pub enum Selection {
Position {
+ buffer_id: BufferID,
pos: usize,
- buffer: BufferID,
},
Range {
- buffer: BufferID,
+ buffer_id: BufferID,
interval: Interval,
},
Ranges {
- buffer: BufferID,
+ buffer_id: BufferID,
ranges: Vec<Interval>,
},
MultiRanges {
@@ -91,33 +91,23 @@ impl Selection {
}
}
- pub fn ranges_disjoint(ranges: &[Interval]) -> bool {
- if ranges.len() < 1 {
- return true;
+ fn normalise(&mut self) {
+ if let Self::MultiRanges { multi_ranges } = self {
+ multi_ranges.retain(|_, v| !v.is_empty())
}
-
- let mut sorted_by_start: Vec<&Interval> = ranges.iter().collect::<Vec<_>>();
- sorted_by_start.sort_by_key(|i| i.start);
- sorted_by_start.windows(2).all(|w| w[0].is_disjoint(&w[1]))
}
- pub fn is_disjoint(&self) -> bool {
+ pub fn is_empty(&mut self) -> bool {
+ self.normalise();
match self {
- Self::Position { .. } => true,
- Self::Range { .. } => true,
- Self::Ranges { ranges, .. } => Self::ranges_disjoint(ranges),
- Self::MultiRanges { multi_ranges } => {
- for (_, intervals) in multi_ranges {
- if !Self::ranges_disjoint(intervals) {
- return false;
- }
- }
- true
- }
+ Self::Position { .. } => return false,
+ Self::Range { .. } => return false,
+ Self::Ranges { ranges, .. } => ranges.is_empty(),
+ Self::MultiRanges { multi_ranges } => multi_ranges.is_empty(),
}
}
- pub fn rank(&self) -> Rank {
+ fn rank(&self) -> Rank {
match self {
Self::Position { .. } => Rank::Zero,
Self::Range { .. } => Rank::One,
@@ -126,7 +116,7 @@ impl Selection {
}
}
- pub fn promote(&self, to_rank: Rank) -> Result<Self, SelectionError> {
+ fn promote(&self, to_rank: Rank) -> Result<Self, SelectionError> {
use Rank::*;
match (self, to_rank) {
@@ -136,26 +126,26 @@ impl Selection {
(Self::MultiRanges { .. }, Three) => Ok(self.clone()),
// Position
- (Self::Position { pos, buffer }, One) => Ok(Self::Range {
+ (Self::Position { pos, buffer_id }, One) => Ok(Self::Range {
interval: Interval {
start: pos + 0,
end: pos + 1,
capture_groups: Vec::new(),
},
- buffer: *buffer,
+ buffer_id: *buffer_id,
}),
- (Self::Position { pos, buffer }, Two) => Ok(Self::Ranges {
+ (Self::Position { pos, buffer_id }, Two) => Ok(Self::Ranges {
ranges: vec![Interval {
start: pos + 0,
end: pos + 1,
capture_groups: Vec::new(),
}],
- buffer: *buffer,
+ buffer_id: *buffer_id,
}),
- (Self::Position { pos, buffer }, Three) => {
+ (Self::Position { pos, buffer_id }, Three) => {
let mut map = HashMap::new();
map.insert(
- *buffer,
+ *buffer_id,
vec![Interval {
start: pos + 0,
end: pos + 1,
@@ -166,20 +156,32 @@ impl Selection {
}
// Range promotions
- (Self::Range { interval, buffer }, Two) => Ok(Self::Ranges {
+ (
+ Self::Range {
+ interval,
+ buffer_id,
+ },
+ Two,
+ ) => Ok(Self::Ranges {
ranges: vec![interval.clone()],
- buffer: *buffer,
+ buffer_id: *buffer_id,
}),
- (Self::Range { interval, buffer }, Three) => {
+ (
+ Self::Range {
+ interval,
+ buffer_id,
+ },
+ Three,
+ ) => {
let mut map = HashMap::new();
- map.insert(*buffer, vec![interval.clone()]);
+ map.insert(*buffer_id, vec![interval.clone()]);
Ok(Self::MultiRanges { multi_ranges: map })
}
// Ranges promotion
- (Self::Ranges { ranges, buffer }, Three) => {
+ (Self::Ranges { ranges, buffer_id }, Three) => {
let mut map = HashMap::new();
- map.insert(*buffer, ranges.clone());
+ map.insert(*buffer_id, ranges.clone());
Ok(Self::MultiRanges { multi_ranges: map })
}
@@ -191,11 +193,11 @@ impl Selection {
}
}
- pub fn buffers(&self) -> Vec<BufferID> {
+ fn buffers(&self) -> Vec<BufferID> {
match self {
- Self::Position { buffer, .. } => vec![*buffer],
- Self::Range { buffer, .. } => vec![*buffer],
- Self::Ranges { buffer, .. } => vec![*buffer],
+ Self::Position { buffer_id, .. } => vec![*buffer_id],
+ Self::Range { buffer_id, .. } => vec![*buffer_id],
+ Self::Ranges { buffer_id, .. } => vec![*buffer_id],
Self::MultiRanges { multi_ranges } => multi_ranges.keys().copied().collect(),
}
}
@@ -229,7 +231,7 @@ impl Selection {
match max_rank {
Rank::Two => {
let mut all_intervals = Vec::new();
- let buffer = *all_buffers.iter().next().unwrap();
+ let buffer_id = *all_buffers.iter().next().unwrap();
for sel in &promoted {
match sel {
@@ -240,7 +242,7 @@ impl Selection {
Ok(Self::Ranges {
ranges: all_intervals,
- buffer,
+ buffer_id,
})
}
Rank::Three => {
@@ -272,8 +274,8 @@ impl Selection {
}
pub fn vectorise<S, E>(
- fn_rank_zero: impl Fn(&S, &BufferID, usize) -> Result<Selection, E> + 'static,
- fn_rank_one: impl Fn(&S, &BufferID, &Interval) -> Result<Selection, E> + 'static,
+ fn_rank_zero: impl Fn(&S, BufferID, usize) -> Result<Selection, E> + 'static,
+ fn_rank_one: impl Fn(&S, BufferID, &Interval) -> Result<Selection, E> + 'static,
) -> impl Fn(&S, &Selection) -> Result<Selection, VectoriseError<E>>
where
E: std::error::Error + 'static,
@@ -281,27 +283,29 @@ impl Selection {
// look at this mess!
use VectoriseError::{ProcessingError, SelectionError};
move |state: &S, selection: &Selection| {
- let do_rank_one = |b: &usize, rs: &Vec<Interval>| {
+ let do_rank_one = |b: usize, rs: &Vec<Interval>| {
rs.iter()
.map(|int| fn_rank_one(state, b, int).map_err(ProcessingError))
.collect::<Result<_, _>>()
};
match selection {
- Self::Position { buffer, pos } => {
- fn_rank_zero(state, buffer, *pos).map_err(ProcessingError)
- }
- Self::Range { buffer, interval } => {
- fn_rank_one(state, buffer, interval).map_err(VectoriseError::ProcessingError)
+ &Self::Position { buffer_id, pos } => {
+ fn_rank_zero(state, buffer_id, pos).map_err(ProcessingError)
}
- Self::Ranges { buffer, ranges } => {
- let results = do_rank_one(buffer, ranges)?;
+ Self::Range {
+ interval,
+ buffer_id,
+ } => fn_rank_one(state, *buffer_id, interval)
+ .map_err(VectoriseError::ProcessingError),
+ Self::Ranges { buffer_id, ranges } => {
+ let results = do_rank_one(*buffer_id, ranges)?;
Self::union(results).map_err(SelectionError)
}
Self::MultiRanges { multi_ranges } => {
let all_ok: Vec<Vec<Self>> = multi_ranges
.iter()
- .map(|(buffer, ranges)| do_rank_one(buffer, ranges))
+ .map(|(buffer_id, ranges)| do_rank_one(*buffer_id, ranges))
.collect::<Result<_, _>>()?;
// It would seem that Rust has no built in monadic flatten, or in general cannot lift things to operate on Result... :(
let results: Vec<Self> = all_ok.into_iter().flatten().collect();
diff --git a/rprt-engine/src/selection_function.rs b/rprt-engine/src/selection_function.rs
index 6f05650..3da61c9 100644
--- a/rprt-engine/src/selection_function.rs
+++ b/rprt-engine/src/selection_function.rs
@@ -4,12 +4,15 @@ use crate::state::EditorState;
use thiserror::Error;
#[derive(Error, Debug)]
-pub enum SFError {}
+pub enum SFError {
+ #[error("Could not find buffer {0}")]
+ BufferNotFound(BufferID),
+}
struct SFComponents {
niladic: Box<dyn Fn(&EditorState) -> Result<Selection, SFError>>,
- monadic_rank0: Box<dyn Fn(&EditorState, &BufferID, usize) -> Result<Selection, SFError>>,
- monadic_rank1: Box<dyn Fn(&EditorState, &BufferID, &Interval) -> Result<Selection, SFError>>,
+ monadic_rank0: Box<dyn Fn(&EditorState, BufferID, usize) -> Result<Selection, SFError>>,
+ monadic_rank1: Box<dyn Fn(&EditorState, BufferID, &Interval) -> Result<Selection, SFError>>,
dyadic: Option<Box<dyn Fn(&EditorState, &Selection, &Selection) -> Result<Selection, SFError>>>,
}
@@ -31,13 +34,71 @@ impl From<SFComponents> for SelectionFunction<VectoriseError<SFError>> {
} else {
None
};
-
+ let niladic = Box::new(move |editor_state: &EditorState| {
+ (sfc.niladic)(editor_state).map_err(VectoriseError::ProcessingError)
+ });
+ let monadic = Box::new(Selection::vectorise(sfc.monadic_rank0, sfc.monadic_rank1));
Self {
- niladic: Box::new(move |editor_state: &EditorState| {
- (sfc.niladic)(editor_state).map_err(VectoriseError::ProcessingError)
+ niladic,
+ monadic,
+ dyadic,
+ }
+ }
+}
+
+impl SelectionFunction<VectoriseError<SFError>> {
+ pub fn empty() -> Self {
+ SFComponents {
+ niladic: Box::new(|_| Ok(Selection::empty())),
+ monadic_rank0: Box::new(|_, _, _| Ok(Selection::empty())),
+ monadic_rank1: Box::new(|_, _, _| Ok(Selection::empty())),
+ dyadic: None,
+ }
+ .into()
+ }
+
+ pub fn end_sequential() -> Self {
+ fn get_end_position(es: &EditorState, buffer_id: BufferID) -> Result<Selection, SFError> {
+ if let Some(buf) = es.get_buffer(buffer_id) {
+ Ok(Selection::Position {
+ buffer_id: buffer_id,
+ pos: buf.max_pos(),
+ })
+ } else {
+ Err(SFError::BufferNotFound(buffer_id))
+ }
+ }
+
+ SFComponents {
+ niladic: Box::new(|es| get_end_position(es, es.current_buffer_id)),
+ monadic_rank0: Box::new(|es, buffer_id, _| get_end_position(es, buffer_id)),
+ monadic_rank1: Box::new(|es, buffer_id, _| get_end_position(es, buffer_id)),
+ dyadic: None,
+ }
+ .into()
+ }
+
+ pub fn end_structural() -> Self {
+ SFComponents {
+ niladic: Box::new(|es| {
+ if let Some(buf) = es.current_buffer() {
+ Ok(Selection::Position {
+ buffer_id: es.current_buffer_id,
+ pos: buf.max_pos(),
+ })
+ } else {
+ Err(SFError::BufferNotFound(es.current_buffer_id))
+ }
+ }),
+ monadic_rank0: Box::new(|_, buffer_id, pos| Ok(Selection::Position { buffer_id, pos })),
+ monadic_rank1: Box::new(|_, buffer_id, int| {
+ Ok(Selection::Position {
+ buffer_id,
+ pos: int.end,
+ })
}),
- monadic: Box::new(Selection::vectorise(sfc.monadic_rank0, sfc.monadic_rank1)),
- dyadic: dyadic,
+ dyadic: None,
}
+ .into()
}
}
diff --git a/rprt-engine/src/state.rs b/rprt-engine/src/state.rs
index bc6fbb6..68283d0 100644
--- a/rprt-engine/src/state.rs
+++ b/rprt-engine/src/state.rs
@@ -65,7 +65,7 @@ impl StateChange {
#[derive(Debug)]
pub struct EditorState {
- current_buffer: BufferID,
+ pub current_buffer_id: BufferID,
current_selection: Selection,
buffers: HashMap<BufferID, Buffer>,
buffer_to_file: HashMap<BufferID, Option<PathBuf>>,
@@ -76,7 +76,7 @@ pub struct EditorState {
impl EditorState {
pub fn new() -> Self {
Self {
- current_buffer: 0,
+ current_buffer_id: 0,
current_selection: Selection::empty(),
buffers: HashMap::new(),
buffer_to_file: HashMap::new(),
@@ -106,12 +106,12 @@ impl EditorState {
buffer_id
}
- pub fn get_buffer(&self, buffer_id: BufferID) -> Option<&Buffer> {
- self.buffers.get(&buffer_id)
+ pub fn current_buffer(&self) -> Option<&Buffer> {
+ self.buffers.get(&self.current_buffer_id)
}
- pub fn get_buffer_mut(&mut self, buffer_id: BufferID) -> Option<&mut Buffer> {
- self.buffers.get_mut(&buffer_id)
+ pub fn get_buffer(&self, buffer_id: BufferID) -> Option<&Buffer> {
+ self.buffers.get(&buffer_id)
}
pub fn commit(&mut self, change: StateChange) {