aboutsummaryrefslogtreecommitdiff
path: root/helix-view/src/register.rs
diff options
context:
space:
mode:
authorMichael Davis2023-07-10 21:43:16 +0000
committerBlaž Hrastnik2023-07-31 06:05:38 +0000
commitda2afe7353066743e30592f03a7a55f24df4dd5c (patch)
treead8bd23402b1e9675e8eb4dd3a0fdf591883c8ba /helix-view/src/register.rs
parent5eb1a25d8a0aeb202358b5b5a3b44bb5f43eced6 (diff)
Add '#' and '.' special registers
These come from Kakoune: * '#' is the selection index register. It's read-only and produces the selection index numbers, 1-indexed. * '.' is the selection contents register. It is also read-only and mirrors the contents of the current selections when read. We switch the iterators returned from Selection's `fragments` and `slices` methods to ExactSizeIterators because: * The selection contents register can simply return the fragments iterator. * ExactSizeIterator is already implemented for iterators over Vecs, so it's essentially free. * The `len` method can be useful on its own.
Diffstat (limited to 'helix-view/src/register.rs')
-rw-r--r--helix-view/src/register.rs32
1 files changed, 29 insertions, 3 deletions
diff --git a/helix-view/src/register.rs b/helix-view/src/register.rs
index ca495ada..892d396f 100644
--- a/helix-view/src/register.rs
+++ b/helix-view/src/register.rs
@@ -11,15 +11,31 @@ use crate::Editor;
/// 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 (`.`)
#[derive(Debug, Default)]
pub struct Registers {
inner: HashMap<char, Vec<String>>,
}
impl Registers {
- pub fn read<'a>(&'a self, name: char, _editor: &'a Editor) -> Option<RegisterValues<'a>> {
+ pub fn read<'a>(&'a self, name: char, editor: &'a Editor) -> Option<RegisterValues<'a>> {
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<usize> but
+ // not RangeInclusive<usize>.
+ 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)))
+ }
_ => self
.inner
.get(&name)
@@ -30,6 +46,7 @@ impl Registers {
pub fn write(&mut self, name: char, values: Vec<String>) -> Result<()> {
match name {
'_' => Ok(()),
+ '#' | '.' => Err(anyhow::anyhow!("Register {name} does not support writing")),
_ => {
self.inner.insert(name, values);
Ok(())
@@ -40,6 +57,7 @@ impl Registers {
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(())
@@ -66,7 +84,15 @@ impl Registers {
(*name, preview)
})
- .chain([('_', "<empty>")].iter().copied())
+ .chain(
+ [
+ ('_', "<empty>"),
+ ('#', "<selection indices>"),
+ ('.', "<selection contents>"),
+ ]
+ .iter()
+ .copied(),
+ )
}
pub fn clear(&mut self) {
@@ -75,7 +101,7 @@ impl Registers {
pub fn remove(&mut self, name: char) -> bool {
match name {
- '_' => false,
+ '_' | '#' | '.' => false,
_ => self.inner.remove(&name).is_some(),
}
}