use crate::{ buffer::{Buffer, BufferID}, expression::BuiltinSelectionFn, selection::{Interval, Selection, Vectorisable}, state::EditorState, }; use thiserror::Error; #[derive(Error, Debug)] pub enum SelectionFunctionError { #[error("Could not find buffer {0}")] BufferNotFound(BufferID), #[error("Function {0} has no dyadic form")] NoDyadicForm(&'static str), #[error("Function {0} has no niladic form")] NoNiladicForm(&'static str), #[error("Selection functions take their primary argument on the left")] NoLeftArgument, #[error("{0} is not yet implemented")] NotImplemented(BuiltinSelectionFn), } /// A selection function parameterised by `P` (the type of its parameter, /// e.g. `usize` for character offsets). /// /// Each concrete function is a zero-sized struct implementing this trait; /// the parameter value is passed at call time. The arity of the call /// (niladic/monadic/dyadic) is routed by [`SelectionFunction::apply`]. pub trait SelectionFunction

: Vectorisable { /// Name of the function, used in error messages. const NAME: &'static str; /// The monadic form applied to a rank-0 (scalar) element. fn monadic_rank0( &self, param: &P, es: &EditorState, buffer_id: BufferID, pos: usize, ) -> Result; /// The monadic form applied to a rank-1 (interval) element. fn monadic_rank1( &self, param: &P, es: &EditorState, buffer_id: BufferID, interval: &Interval, ) -> Result; /// The niladic form. fn niladic(&self, _param: &P, _es: &EditorState) -> Result { Err(SelectionFunctionError::NoNiladicForm(Self::NAME)) } /// The monadic form: vectorise over `left`. fn monadic( &self, param: &P, es: &EditorState, left: &Selection, ) -> Result { self.vectorise(param, es, left) } /// The dyadic form. fn dyadic( &self, _param: &P, _es: &EditorState, _left: &Selection, _right: &Selection, ) -> Result { Err(SelectionFunctionError::NoDyadicForm(Self::NAME)) } /// Route to the arity form matching the selections supplied. fn apply( &self, param: &P, es: &EditorState, left: Option<&Selection>, right: Option<&Selection>, ) -> Result { match (left, right) { (None, None) => self.niladic(param, es), (Some(left), None) => self.monadic(param, es, left), (Some(left), Some(right)) => self.dyadic(param, es, left, right), (None, Some(_)) => Err(SelectionFunctionError::NoLeftArgument), } } } /// Every selection function can vectorise a selection by applying its /// monadic rank-0/rank-1 forms to each element. impl + ?Sized> Vectorisable for F { fn rank0( &self, param: &P, es: &EditorState, buffer_id: BufferID, pos: usize, ) -> Result { self.monadic_rank0(param, es, buffer_id, pos) } fn rank1( &self, param: &P, es: &EditorState, buffer_id: BufferID, interval: &Interval, ) -> Result { self.monadic_rank1(param, es, buffer_id, interval) } } /// A selection function with no parameter. /// /// Blanket-implements [`SelectionFunction`] with `P = ()`, so /// unparameterised functions are callable through the same interface. pub trait UnparameterisedSelectionFunction { /// Name of the function, used in error messages. const NAME: &'static str; /// The monadic form applied to a rank-0 (scalar) element. fn monadic_rank0( &self, es: &EditorState, buffer_id: BufferID, pos: usize, ) -> Result; /// The monadic form applied to a rank-1 (interval) element. fn monadic_rank1( &self, es: &EditorState, buffer_id: BufferID, interval: &Interval, ) -> Result; /// The niladic form. fn niladic(&self, _es: &EditorState) -> Result { Err(SelectionFunctionError::NoNiladicForm(Self::NAME)) } /// The dyadic form. fn dyadic( &self, _es: &EditorState, _left: &Selection, _right: &Selection, ) -> Result { Err(SelectionFunctionError::NoDyadicForm(Self::NAME)) } } impl SelectionFunction<()> for F { const NAME: &'static str = ::NAME; fn monadic_rank0( &self, _param: &(), es: &EditorState, buffer_id: BufferID, pos: usize, ) -> Result { UnparameterisedSelectionFunction::monadic_rank0(self, es, buffer_id, pos) } fn monadic_rank1( &self, _param: &(), es: &EditorState, buffer_id: BufferID, interval: &Interval, ) -> Result { UnparameterisedSelectionFunction::monadic_rank1(self, es, buffer_id, interval) } fn niladic(&self, _param: &(), es: &EditorState) -> Result { UnparameterisedSelectionFunction::niladic(self, es) } fn dyadic( &self, _param: &(), es: &EditorState, left: &Selection, right: &Selection, ) -> Result { UnparameterisedSelectionFunction::dyadic(self, es, left, right) } } pub fn get_buffer( es: &EditorState, buffer_id: BufferID, ) -> Result<&Buffer, SelectionFunctionError> { if let Some(buf) = es.get_buffer(buffer_id) { Ok(buf) } else { Err(SelectionFunctionError::BufferNotFound(es.current_buffer_id)) } }