mirror of
https://github.com/ilyakooo0/helix.git
synced 2024-09-11 16:07:00 +03:00
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.
This commit is contained in:
parent
5eb1a25d8a
commit
da2afe7353
@ -630,11 +630,19 @@ pub fn cursors(self, text: RopeSlice) -> Self {
|
|||||||
self.transform(|range| Range::point(range.cursor(text)))
|
self.transform(|range| Range::point(range.cursor(text)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fragments<'a>(&'a self, text: RopeSlice<'a>) -> impl Iterator<Item = Cow<str>> + 'a {
|
pub fn fragments<'a>(
|
||||||
|
&'a self,
|
||||||
|
text: RopeSlice<'a>,
|
||||||
|
) -> impl DoubleEndedIterator<Item = Cow<'a, str>> + ExactSizeIterator<Item = Cow<str>> + 'a
|
||||||
|
{
|
||||||
self.ranges.iter().map(move |range| range.fragment(text))
|
self.ranges.iter().map(move |range| range.fragment(text))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn slices<'a>(&'a self, text: RopeSlice<'a>) -> impl Iterator<Item = RopeSlice> + 'a {
|
pub fn slices<'a>(
|
||||||
|
&'a self,
|
||||||
|
text: RopeSlice<'a>,
|
||||||
|
) -> impl DoubleEndedIterator<Item = RopeSlice<'a>> + ExactSizeIterator<Item = RopeSlice<'a>> + 'a
|
||||||
|
{
|
||||||
self.ranges.iter().map(move |range| range.slice(text))
|
self.ranges.iter().map(move |range| range.slice(text))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,15 +11,31 @@
|
|||||||
/// behaviors when read or written to:
|
/// behaviors when read or written to:
|
||||||
///
|
///
|
||||||
/// * Black hole (`_`): all values read and written are discarded
|
/// * Black hole (`_`): all values read and written are discarded
|
||||||
|
/// * Selection indices (`#`): index number of each selection starting at 1
|
||||||
|
/// * Selection contents (`.`)
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Registers {
|
pub struct Registers {
|
||||||
inner: HashMap<char, Vec<String>>,
|
inner: HashMap<char, Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Registers {
|
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 {
|
match name {
|
||||||
'_' => Some(RegisterValues::new(iter::empty())),
|
'_' => 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
|
_ => self
|
||||||
.inner
|
.inner
|
||||||
.get(&name)
|
.get(&name)
|
||||||
@ -30,6 +46,7 @@ pub fn read<'a>(&'a self, name: char, _editor: &'a Editor) -> Option<RegisterVal
|
|||||||
pub fn write(&mut self, name: char, values: Vec<String>) -> Result<()> {
|
pub fn write(&mut self, name: char, values: Vec<String>) -> Result<()> {
|
||||||
match name {
|
match name {
|
||||||
'_' => Ok(()),
|
'_' => Ok(()),
|
||||||
|
'#' | '.' => Err(anyhow::anyhow!("Register {name} does not support writing")),
|
||||||
_ => {
|
_ => {
|
||||||
self.inner.insert(name, values);
|
self.inner.insert(name, values);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -40,6 +57,7 @@ pub fn write(&mut self, name: char, values: Vec<String>) -> Result<()> {
|
|||||||
pub fn push(&mut self, name: char, value: String) -> Result<()> {
|
pub fn push(&mut self, name: char, value: String) -> Result<()> {
|
||||||
match name {
|
match name {
|
||||||
'_' => Ok(()),
|
'_' => Ok(()),
|
||||||
|
'#' | '.' => Err(anyhow::anyhow!("Register {name} does not support pushing")),
|
||||||
_ => {
|
_ => {
|
||||||
self.inner.entry(name).or_insert_with(Vec::new).push(value);
|
self.inner.entry(name).or_insert_with(Vec::new).push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -66,7 +84,15 @@ pub fn iter_preview(&self) -> impl Iterator<Item = (char, &str)> {
|
|||||||
|
|
||||||
(*name, preview)
|
(*name, preview)
|
||||||
})
|
})
|
||||||
.chain([('_', "<empty>")].iter().copied())
|
.chain(
|
||||||
|
[
|
||||||
|
('_', "<empty>"),
|
||||||
|
('#', "<selection indices>"),
|
||||||
|
('.', "<selection contents>"),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.copied(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
@ -75,7 +101,7 @@ pub fn clear(&mut self) {
|
|||||||
|
|
||||||
pub fn remove(&mut self, name: char) -> bool {
|
pub fn remove(&mut self, name: char) -> bool {
|
||||||
match name {
|
match name {
|
||||||
'_' => false,
|
'_' | '#' | '.' => false,
|
||||||
_ => self.inner.remove(&name).is_some(),
|
_ => self.inner.remove(&name).is_some(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user