use crate::buffer::BufferID; use crate::selection::{Interval, 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, }, } type SFResult = Result>; fn rust_has_an_annoying_issue(r: Result) -> SFResult { r.map_err(Into::into) } 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 } => rust_has_an_annoying_issue({ $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_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 } => { rust_has_an_annoying_issue({ $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 complement_transform(es: &EditorState, result: Selection, _: &SFArguments) -> SFResult { fn complement_rank0( es: &EditorState, buffer_id: BufferID, pos: usize, ) -> Result { 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 { 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) } } // ---------------------------------------------------------------- pub fn empty_sequential(_: SFArguments) -> SFResult { Ok(Selection::empty()) } pub fn empy_structural(_: SFArguments) -> SFResult { Ok(Selection::empty()) } selection_function! { name: end_sequential, niladic: |es: &EditorState| { es.current_buffer().map(|buf| Selection::Position { buffer_id: es.current_buffer_id, pos: buf.max_pos() }).ok_or(SFError::BufferNotFound(es.current_buffer_id)) }, 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| { 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).into()) } }, monadic_rank0: |_, buffer_id, pos | Ok(Selection::Position { buffer_id, pos }), monadic_rank1: |_, buffer_id, int | Ok(Selection::Position { buffer_id, pos: int.end, }) } selection_function_param! { name: character_structural, param_type: usize, niladic: |(param, es): (usize, &EditorState)| { if let Some(buf) = es.current_buffer() { Ok(Selection::Position { buffer_id: es.current_buffer_id, pos: usize::min(param, buf.max_pos()), }) } else { Err(SFError::BufferNotFound(es.current_buffer_id).into()) } }, 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)| { if let Some(buf) = es.current_buffer() { Ok(Selection::Position { buffer_id: es.current_buffer_id, pos: usize::min(param, buf.max_pos()), }) } else { Err(SFError::BufferNotFound(es.current_buffer_id).into()) } }, monadic_rank0: |(param, es), buffer_id, pos| { if let Some(buf) = es.get_buffer(buffer_id) { Ok(Selection::Position {buffer_id, pos: usize::min(pos+*param, buf.max_pos())}) } else { Err(SFError::BufferNotFound(buffer_id).into()) } }, monadic_rank1: |(param, es), buffer_id, int| { if let Some(buf) = es.get_buffer(buffer_id) { Ok(Selection::Position {buffer_id, pos: usize::min(int.end+*param, buf.max_pos())}) } else { Err(SFError::BufferNotFound(buffer_id).into()) } } }