use crate::{ buffer::BufferID, expression::SearchModifier, selection::{Interval, Selection}, selection_functions::types::{SelectionFunction, SelectionFunctionError, get_buffer}, state::EditorState, }; pub struct Character; impl SelectionFunction for Character { const NAME: &'static str = "character"; fn niladic( &self, param: &usize, es: &EditorState, ) -> Result { let buf = get_buffer(es, es.current_buffer_id)?; Ok(Selection::Scalar { buffer_id: es.current_buffer_id, pos: usize::min(*param, buf.max_pos()), }) } fn monadic_rank0( &self, _param: &usize, _es: &EditorState, buffer_id: BufferID, pos: usize, ) -> Result { Ok(Selection::Scalar { buffer_id, pos }) } fn monadic_rank1( &self, param: &usize, _es: &EditorState, buffer_id: BufferID, interval: &Interval, ) -> Result { Ok(Selection::Scalar { buffer_id, pos: usize::min(interval.start + *param, interval.end), }) } } pub struct SequentialCharacter; impl SelectionFunction for SequentialCharacter { const NAME: &'static str = "sequential_character"; fn niladic( &self, _param: &usize, _es: &EditorState, ) -> Result { Err(SelectionFunctionError::NoNiladicForm(";n")) } fn monadic_rank0( &self, param: &usize, es: &EditorState, buffer_id: BufferID, pos: usize, ) -> Result { let buf = get_buffer(es, buffer_id)?; Ok(Selection::Scalar { buffer_id, pos: usize::min(pos + *param, buf.max_pos()), }) } fn monadic_rank1( &self, param: &usize, es: &EditorState, buffer_id: BufferID, interval: &Interval, ) -> Result { let buf = get_buffer(es, buffer_id)?; Ok(Selection::Scalar { buffer_id, pos: usize::min(interval.end + *param, buf.max_pos()), }) } } pub struct ReverseCharacter; impl SelectionFunction for ReverseCharacter { const NAME: &'static str = "reverse_character"; fn niladic( &self, param: &usize, es: &EditorState, ) -> Result { let buf = get_buffer(es, es.current_buffer_id)?; Ok(Selection::Scalar { buffer_id: es.current_buffer_id, pos: if buf.max_pos() < *param { 0 } else { buf.max_pos() - *param }, }) } fn monadic_rank0( &self, _param: &usize, _es: &EditorState, buffer_id: BufferID, pos: usize, ) -> Result { Ok(Selection::Scalar { buffer_id, pos }) } fn monadic_rank1( &self, param: &usize, _es: &EditorState, buffer_id: BufferID, interval: &Interval, ) -> Result { Ok(Selection::Scalar { buffer_id, pos: if *param < interval.end { interval.end - *param } else { 0 }, }) } } pub struct SequentialReverseCharacter; impl SelectionFunction for SequentialReverseCharacter { const NAME: &'static str = "sequential_reverse_character"; fn niladic( &self, _param: &usize, _es: &EditorState, ) -> Result { Err(SelectionFunctionError::NoNiladicForm(";'n")) } fn monadic_rank0( &self, param: &usize, _es: &EditorState, buffer_id: BufferID, pos: usize, ) -> Result { Ok(Selection::Scalar { buffer_id, pos: if *param < pos { pos - *param } else { 0 }, }) } fn monadic_rank1( &self, param: &usize, _es: &EditorState, buffer_id: BufferID, interval: &Interval, ) -> Result { Ok(Selection::Scalar { buffer_id, pos: if *param < interval.end { interval.end - *param } else { 0 }, }) } } pub struct ReverseSequentialCharacter; impl SelectionFunction for ReverseSequentialCharacter { const NAME: &'static str = "reverse_sequential_character"; fn niladic( &self, _param: &usize, _es: &EditorState, ) -> Result { Err(SelectionFunctionError::NoNiladicForm("';n")) } fn monadic_rank0( &self, param: &usize, _es: &EditorState, buffer_id: BufferID, pos: usize, ) -> Result { Ok(Selection::Scalar { buffer_id, pos: if *param < pos { pos - *param } else { 0 }, }) } fn monadic_rank1( &self, param: &usize, _es: &EditorState, buffer_id: BufferID, interval: &Interval, ) -> Result { Ok(Selection::Scalar { buffer_id, pos: if *param < interval.start { interval.start - *param } else { 0 }, }) } } /// Dispatch on the search modifier and apply the matching character-family /// function to the supplied selections. pub fn selection_function_character( offset: usize, es: &EditorState, left: Option<&Selection>, right: Option<&Selection>, search_mod: Option, ) -> Result { match search_mod { None => Character.apply(&offset, es, left, right), Some(SearchModifier::Sequential) => SequentialCharacter.apply(&offset, es, left, right), Some(SearchModifier::Reverse) => ReverseCharacter.apply(&offset, es, left, right), Some(SearchModifier::SequentialReverse) => { SequentialReverseCharacter.apply(&offset, es, left, right) } Some(SearchModifier::ReverseSequential) => { ReverseSequentialCharacter.apply(&offset, es, left, right) } } }