use std::{borrow::Cow, collections::HashMap, iter}; use anyhow::Result; use crate::{document::SCRATCH_BUFFER_NAME, Editor}; /// A key-value store for saving sets of values. /// /// Each register corresponds to a `char`. Most chars can be used to store any set of /// values but a few chars are "special registers". Special registers have unique /// behaviors when read or written to: /// /// * Black hole (`_`): all values read and written are discarded /// * Selection indices (`#`): index number of each selection starting at 1 /// * Selection contents (`.`) /// * Document path (`%`): filename of the current buffer #[derive(Debug, Default)] pub struct Registers { inner: HashMap>, } impl Registers { pub fn read<'a>(&'a self, name: char, editor: &'a Editor) -> Option> { match name { '_' => Some(RegisterValues::new(iter::empty())), '#' => { let (view, doc) = current_ref!(editor); let selections = doc.selection(view.id).len(); // ExactSizeIterator is implemented for Range but // not RangeInclusive. Some(RegisterValues::new( (0..selections).map(|i| (i + 1).to_string().into()), )) } '.' => { let (view, doc) = current_ref!(editor); let text = doc.text().slice(..); Some(RegisterValues::new(doc.selection(view.id).fragments(text))) } '%' => { let doc = doc!(editor); let path = doc .path() .as_ref() .map(|p| p.to_string_lossy()) .unwrap_or_else(|| SCRATCH_BUFFER_NAME.into()); Some(RegisterValues::new(iter::once(path))) } _ => self .inner .get(&name) .map(|values| RegisterValues::new(values.iter().map(Cow::from))), } } pub fn write(&mut self, name: char, values: Vec) -> Result<()> { match name { '_' => Ok(()), '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support writing")), _ => { self.inner.insert(name, values); Ok(()) } } } pub fn push(&mut self, name: char, value: String) -> Result<()> { match name { '_' => Ok(()), '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support pushing")), _ => { self.inner.entry(name).or_insert_with(Vec::new).push(value); Ok(()) } } } pub fn first<'a>(&'a self, name: char, editor: &'a Editor) -> Option> { self.read(name, editor).and_then(|mut values| values.next()) } pub fn last<'a>(&'a self, name: char, editor: &'a Editor) -> Option> { self.read(name, editor).and_then(|values| values.last()) } pub fn iter_preview(&self) -> impl Iterator { self.inner .iter() .map(|(name, values)| { let preview = values .first() .and_then(|s| s.lines().next()) .unwrap_or(""); (*name, preview) }) .chain( [ ('_', ""), ('#', ""), ('.', ""), ('%', ""), ] .iter() .copied(), ) } pub fn clear(&mut self) { self.inner.clear() } pub fn remove(&mut self, name: char) -> bool { match name { '_' | '#' | '.' | '%' => false, _ => self.inner.remove(&name).is_some(), } } } // This is a wrapper of an iterator that is both double ended and exact size, // and can return either owned or borrowed values. Regular registers can // return borrowed values while some special registers need to return owned // values. pub struct RegisterValues<'a> { iter: Box> + 'a>, } impl<'a> RegisterValues<'a> { fn new( iter: impl DoubleEndedIterator> + ExactSizeIterator> + 'a, ) -> Self { Self { iter: Box::new(iter), } } } impl<'a> Iterator for RegisterValues<'a> { type Item = Cow<'a, str>; fn next(&mut self) -> Option { self.iter.next() } fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } impl<'a> DoubleEndedIterator for RegisterValues<'a> { fn next_back(&mut self) -> Option { self.iter.next_back() } } impl<'a> ExactSizeIterator for RegisterValues<'a> { fn len(&self) -> usize { self.iter.len() } } // Each RegisterValues iterator is both double ended and exact size. We can't // type RegisterValues as `Box` // because only one non-auto trait is allowed in trait objects. So we need to // create a new trait that covers both. `RegisterValues` wraps that type so that // trait only needs to live in this module and not be imported for all register // callsites. trait DoubleEndedExactSizeIterator: DoubleEndedIterator + ExactSizeIterator {} impl DoubleEndedExactSizeIterator for I {}