aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helix-core/src/lib.rs1
-rw-r--r--helix-core/src/register.rs21
-rw-r--r--helix-core/src/selection.rs3
-rw-r--r--helix-core/src/transaction.rs2
-rw-r--r--helix-view/src/commands.rs35
-rw-r--r--helix-view/src/keymap.rs2
6 files changed, 61 insertions, 3 deletions
diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs
index 9bc5d003..4a7a2dd4 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 00000000..0be0ce89
--- /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<RwLock<HashMap<char, Vec<String>>>> =
+ Lazy::new(|| RwLock::new(HashMap::new()));
+
+pub fn get(register: char) -> Option<Vec<String>> {
+ let registry = REGISTRY.read().unwrap();
+
+ // TODO: no cloning
+ registry.get(&register).cloned()
+}
+
+// restoring: bool
+pub fn set(register: char, values: Vec<String>) {
+ 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 2251c77f..bc677330 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 13c0c50f..33612ecf 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<F>(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 9a6d2e5d..ca1e41c4 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 e108324e..da5934eb 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