diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 9bc5d003e..4a7a2dd40 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -3,6 +3,7 @@ pub mod graphemes; mod history; pub mod macros; mod position; +pub mod register; pub mod selection; pub mod state; pub mod syntax; diff --git a/helix-core/src/register.rs b/helix-core/src/register.rs new file mode 100644 index 000000000..0be0ce897 --- /dev/null +++ b/helix-core/src/register.rs @@ -0,0 +1,21 @@ +use crate::Tendril; +use once_cell::sync::Lazy; +use std::{collections::HashMap, sync::RwLock}; + +// TODO: could be an instance on Editor +static REGISTRY: Lazy>>> = + Lazy::new(|| RwLock::new(HashMap::new())); + +pub fn get(register: char) -> Option> { + let registry = REGISTRY.read().unwrap(); + + // TODO: no cloning + registry.get(®ister).cloned() +} + +// restoring: bool +pub fn set(register: char, values: Vec) { + let mut registry = REGISTRY.write().unwrap(); + + registry.insert(register, values); +} diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index 2251c77f3..bc6773303 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -110,7 +110,8 @@ impl Range { #[inline] pub fn fragment<'a>(&'a self, text: &'a RopeSlice) -> Cow<'a, str> { - Cow::from(text.slice(self.from()..self.to())) + // end inclusive + Cow::from(text.slice(self.from()..self.to() + 1)) } } diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index 13c0c50f9..33612ecfa 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -445,7 +445,7 @@ impl Transaction { /// Generate a transaction with a change per selection range. pub fn change_by_selection(state: &State, f: F) -> Self where - F: Fn(&Range) -> Change, + F: FnMut(&Range) -> Change, { Self::change(state, state.selection.ranges().iter().map(f)) } diff --git a/helix-view/src/commands.rs b/helix-view/src/commands.rs index 9a6d2e5d7..ca1e41c42 100644 --- a/helix-view/src/commands.rs +++ b/helix-view/src/commands.rs @@ -1,7 +1,7 @@ use helix_core::{ graphemes, regex::Regex, - selection, + register, selection, state::{Direction, Granularity, Mode, State}, ChangeSet, Range, Selection, Tendril, Transaction, }; @@ -443,3 +443,36 @@ pub fn undo(view: &mut View, _count: usize) { pub fn redo(view: &mut View, _count: usize) { view.history.redo(&mut view.state); } + +// Yank / Paste + +pub fn yank(view: &mut View, _count: usize) { + // TODO: should selections be made end inclusive? + let values = view + .state + .selection() + .fragments(&view.state.doc().slice(..)) + .map(|cow| cow.into_owned()) + .collect(); + + register::set('"', values); +} + +pub fn paste(view: &mut View, _count: usize) { + if let Some(values) = register::get('"') { + let repeat = std::iter::repeat( + values + .last() + .map(|value| Tendril::from_slice(value)) + .unwrap(), + ); + + let mut values = values.into_iter().map(Tendril::from).chain(repeat); + + let transaction = Transaction::change_by_selection(&view.state, |range| { + (range.head + 1, range.head + 1, Some(values.next().unwrap())) + }); + + transaction.apply(&mut view.state); + } +} diff --git a/helix-view/src/keymap.rs b/helix-view/src/keymap.rs index e108324e2..da5934eb3 100644 --- a/helix-view/src/keymap.rs +++ b/helix-view/src/keymap.rs @@ -147,6 +147,8 @@ pub fn default() -> Keymaps { vec![key!(';')] => commands::collapse_selection, vec![key!('u')] => commands::undo, vec![shift!('U')] => commands::redo, + vec![key!('y')] => commands::yank, + vec![key!('p')] => commands::paste, vec![Key { code: KeyCode::Esc, modifiers: Modifiers::NONE