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))
}
}