diff options
Diffstat (limited to 'rprt-engine/src/selection_functions')
6 files changed, 245 insertions, 0 deletions
diff --git a/rprt-engine/src/selection_functions/function_character.rs b/rprt-engine/src/selection_functions/function_character.rs new file mode 100644 index 0000000..3d9695f --- /dev/null +++ b/rprt-engine/src/selection_functions/function_character.rs @@ -0,0 +1,38 @@ +use crate::selection::Selection; +use crate::selection_function_param; +use crate::selection_functions::types::{get_buffer, SFArguments, SFError, SFResult}; +use crate::state::EditorState; + +selection_function_param! { + name: character_structural, + param_type: usize, + niladic: |(param, es): (usize, &EditorState)| { + let buf = get_buffer(es, es.current_buffer_id)?; + Ok(Selection::Position { + buffer_id: es.current_buffer_id, + pos: usize::min(param, buf.max_pos()) + + }) }, + monadic_rank0: |_, buffer_id, pos| Ok(Selection::Position {buffer_id, pos}), + monadic_rank1: |(param, _), buffer_id, int| Ok(Selection::Position {buffer_id, pos: usize::min(int.end, *param)}) +} + +selection_function_param! { + name: character_sequential, + param_type: usize, + niladic: |(param, es): (usize, &EditorState)| { + let buf = get_buffer(es, es.current_buffer_id)?; + Ok(Selection::Position { + buffer_id: es.current_buffer_id, + pos: usize::min(param, buf.max_pos()), + }) + }, + monadic_rank0: |(param, es), buffer_id, pos| { + let buf = get_buffer(es, buffer_id)?; + Ok(Selection::Position {buffer_id, pos: usize::min(pos+*param, buf.max_pos())}) + }, + monadic_rank1: |(param, es), buffer_id, int| { + let buf = get_buffer(es, buffer_id)?; + Ok(Selection::Position {buffer_id, pos: usize::min(int.end+*param, buf.max_pos())}) + } +} diff --git a/rprt-engine/src/selection_functions/function_empty.rs b/rprt-engine/src/selection_functions/function_empty.rs new file mode 100644 index 0000000..8290de3 --- /dev/null +++ b/rprt-engine/src/selection_functions/function_empty.rs @@ -0,0 +1,10 @@ +use crate::selection::Selection; +use crate::selection_functions::types::{SFArguments, SFResult}; + +pub fn empty_sequential(_: SFArguments) -> SFResult { + Ok(Selection::empty()) +} + +pub fn empy_structural(_: SFArguments) -> SFResult { + Ok(Selection::empty()) +} diff --git a/rprt-engine/src/selection_functions/function_end.rs b/rprt-engine/src/selection_functions/function_end.rs new file mode 100644 index 0000000..47cff79 --- /dev/null +++ b/rprt-engine/src/selection_functions/function_end.rs @@ -0,0 +1,37 @@ +use crate::selection::Selection; +use crate::selection_function; +use crate::selection_functions::types::{get_buffer, SFArguments, SFError, SFResult}; +use crate::state::EditorState; + +selection_function! { + name: end_sequential, + niladic: |es: &EditorState| { + let buf = get_buffer(es, es.current_buffer_id)?; + Ok(Selection::Position { + buffer_id: es.current_buffer_id, + pos: buf.max_pos() + }) + }, + monadic_rank0: |_, buffer_id, pos| { + Ok(Selection::Position { buffer_id, pos }) + }, + monadic_rank1: |_, buffer_id, interval| { + Ok(Selection::Position { + buffer_id, + pos: interval.end, + }) + } +} + +selection_function! { + name: end_structural, + niladic: |es: &EditorState| { + let buf = get_buffer(es, es.current_buffer_id)?; + Ok(Selection::Position { + buffer_id: es.current_buffer_id, + pos: buf.max_pos(), + }) + }, + monadic_rank0: |_, buffer_id, pos | Ok(Selection::Position { buffer_id, pos }), + monadic_rank1: |_, buffer_id, int | Ok(Selection::Position { buffer_id, pos: int.end }) +} diff --git a/rprt-engine/src/selection_functions/mod.rs b/rprt-engine/src/selection_functions/mod.rs new file mode 100644 index 0000000..3f64be4 --- /dev/null +++ b/rprt-engine/src/selection_functions/mod.rs @@ -0,0 +1,5 @@ +pub mod function_character; +pub mod function_empty; +pub mod function_end; +pub mod result_transformation; +pub mod types; diff --git a/rprt-engine/src/selection_functions/result_transformation.rs b/rprt-engine/src/selection_functions/result_transformation.rs new file mode 100644 index 0000000..89a071a --- /dev/null +++ b/rprt-engine/src/selection_functions/result_transformation.rs @@ -0,0 +1,77 @@ +use crate::buffer::BufferID; +use crate::selection::{Interval, Selection}; +use crate::selection_functions::types::{SFArguments, SFError, SFResult}; +use crate::state::EditorState; + +pub fn complement_transform(es: &EditorState, result: Selection, _: &SFArguments) -> SFResult { + fn complement_rank0( + es: &EditorState, + buffer_id: BufferID, + pos: usize, + ) -> Result<Selection, SFError> { + if let Some(buf) = es.get_buffer(buffer_id) { + let mut ranges = Vec::new(); + if pos > 0 { + ranges.push(Interval::new(0, pos)); + } + let max_pos = buf.max_pos(); + if pos + 1 < max_pos { + ranges.push(Interval::new(pos + 1, max_pos)); + } + Ok(Selection::Ranges { buffer_id, ranges }) + } else { + Err(SFError::BufferNotFound(buffer_id)) + } + } + + fn complement_rank1( + es: &EditorState, + buffer_id: BufferID, + interval: &Interval, + ) -> Result<Selection, SFError> { + if let Some(buf) = es.get_buffer(buffer_id) { + let max_pos = buf.max_pos(); + if interval.start == 0 && interval.end >= max_pos { + return Ok(Selection::empty()); + } + + let mut ranges = Vec::new(); + if interval.start == 0 { + if interval.end < max_pos { + ranges.push(Interval::new(interval.end, max_pos)); + } + } else if interval.end == max_pos { + ranges.push(Interval::new(0, interval.start)); + } else { + ranges.push(Interval::new(0, interval.start)); + ranges.push(Interval::new(interval.end, max_pos)); + } + Ok(Selection::Ranges { buffer_id, ranges }) + } else { + Err(SFError::BufferNotFound(buffer_id)) + } + } + + result.vectorise(es, complement_rank0, complement_rank1) +} + +pub fn conditional_transform( + _: &EditorState, + mut result: Selection, + arg: &SFArguments, +) -> SFResult { + if !result.is_empty() { + Ok(match arg { + // TODO: think about this niladic case? + SFArguments::Niladic { .. } => Selection::empty(), + SFArguments::Monadic { es: _, left } => left.clone(), + SFArguments::Dyadic { + es: _, + left, + right: _, + } => left.clone(), + }) + } else { + Ok(result) + } +} diff --git a/rprt-engine/src/selection_functions/types.rs b/rprt-engine/src/selection_functions/types.rs new file mode 100644 index 0000000..728d084 --- /dev/null +++ b/rprt-engine/src/selection_functions/types.rs @@ -0,0 +1,78 @@ +use crate::buffer::{Buffer, BufferID}; +use crate::selection::{Selection, VectoriseError}; +use crate::state::EditorState; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum SFError { + #[error("Could not find buffer {0}")] + BufferNotFound(BufferID), + #[error("Function {0} has no dyadic form")] + NoDyadicForm(&'static str), +} + +pub enum SFArguments<'a> { + Niladic { + es: &'a EditorState, + }, + Monadic { + es: &'a EditorState, + left: Selection, + }, + Dyadic { + es: &'a EditorState, + left: Selection, + right: Selection, + }, +} + +pub type SFResult = Result<Selection, VectoriseError<SFError>>; + +#[macro_export] +macro_rules! selection_function { + ( + name: $name:ident, + niladic: $niladic_body:expr, + monadic_rank0: $monadic_rank0_body:expr, + monadic_rank1: $monadic_rank1_body:expr + ) => { + pub fn $name(arg: SFArguments) -> SFResult { + match arg { + SFArguments::Niladic { es } => $niladic_body(es), + SFArguments::Monadic { es, left } => { + left.vectorise(es, $monadic_rank0_body, $monadic_rank1_body) + } + SFArguments::Dyadic { .. } => Err(SFError::NoDyadicForm(stringify!($name)).into()), + } + } + }; +} + +#[macro_export] +macro_rules! selection_function_param { + ( + name: $name:ident, + param_type: $P:ty, + niladic: $niladic_body:expr, + monadic_rank0: $monadic_rank0_body:expr, + monadic_rank1: $monadic_rank1_body:expr + ) => { + pub fn $name(param: $P, arg: SFArguments) -> SFResult { + match arg { + SFArguments::Niladic { es } => $niladic_body((param, es)), + SFArguments::Monadic { es, left } => { + left.vectorise(&(param, es), $monadic_rank0_body, $monadic_rank1_body) + } + SFArguments::Dyadic { .. } => Err(SFError::NoDyadicForm(stringify!($name)).into()), + } + } + }; +} + +pub fn get_buffer(es: &EditorState, buffer_id: BufferID) -> Result<&Buffer, SFError> { + if let Some(buf) = es.get_buffer(buffer_id) { + Ok(buf) + } else { + Err(SFError::BufferNotFound(es.current_buffer_id)) + } +} |
