on master help sign in
Implement register selection

User can select register to yank into with the " command. A new state is added to `Editor` and `commands::Context` structs. This state is managed by leveraging a new struct `RegisterSelection`.

commit68affa3c598723a8b9451ef3dcceda83ae161e39 authorBenoît CORTIER <benoit.cortier@fried-world.eu> dateFri 4 Jun 2021, 22:21 (5 years ago) parentd5de918
7 files changed+96−25
helix-core/src/register.rs+6−7 helix-term/src/commands.rs+30−15 helix-term/src/keymap.rs+2 helix-term/src/ui/editor.rs+6−2 helix-view/src/editor.rs+3−1 helix-view/src/lib.rs+2 helix-view/src/register_selection.rs+47
helix-core/src/register.rs+6−7
@@ -6,16 +6,15 @@ use std::{collections::HashMap, sync::RwLock};
66static REGISTRY: Lazy<RwLock<HashMap<char, Vec<String>>>> =
77 Lazy::new(|| RwLock::new(HashMap::new()));
88
9−pub fn get(register: char) -> Option<Vec<String>> {
9+/// Read register values.
10+pub fn get(register_name: char) -> Option<Vec<String>> {
1011 let registry = REGISTRY.read().unwrap();
11−
12− // TODO: no cloning
13− registry.get(&register).cloned()
12+ registry.get(&register_name).cloned() // TODO: no cloning
1413}
1514
15+/// Read register values.
1616// restoring: bool
17−pub fn set(register: char, values: Vec<String>) {
17+pub fn set(register_name: char, values: Vec<String>) {
1818 let mut registry = REGISTRY.write().unwrap();
19−
20− registry.insert(register, values);
19+ registry.insert(register_name, values);
2120}
helix-term/src/commands.rs+30−15
@@ -35,6 +35,7 @@ use crossterm::event::{KeyCode, KeyEvent};
3535use once_cell::sync::Lazy;
3636
3737pub struct Context<'a> {
38+ pub register: helix_view::RegisterSelection,
3839 pub count: usize,
3940 pub editor: &'a mut Editor,
4041
@@ -777,7 +778,7 @@ pub fn extend_line(cx: &mut Context) {
777778
778779// heuristic: append changes to history after each command, unless we're in insert mode
779780
780−fn _delete_selection(doc: &mut Document, view_id: ViewId) {
781+fn _delete_selection(reg: char, doc: &mut Document, view_id: ViewId) {
781782 // first yank the selection
782783 let values: Vec<String> = doc
783784 .selection(view_id)
@@ -785,8 +786,6 @@ fn _delete_selection(doc: &mut Document, view_id: ViewId) {
785786 .map(Cow::into_owned)
786787 .collect();
787788
788− // TODO: allow specifying reg
789− let reg = '"';
790789 register::set(reg, values);
791790
792791 // then delete
@@ -800,8 +799,9 @@ fn _delete_selection(doc: &mut Document, view_id: ViewId) {
800799}
801800
802801pub fn delete_selection(cx: &mut Context) {
802+ let reg = cx.register.name();
803803 let (view, doc) = cx.current();
804− _delete_selection(doc, view.id);
804+ _delete_selection(reg, doc, view.id);
805805
806806 doc.append_changes_to_history(view.id);
807807
@@ -810,8 +810,9 @@ pub fn delete_selection(cx: &mut Context) {
810810}
811811
812812pub fn change_selection(cx: &mut Context) {
813+ let reg = cx.register.name();
813814 let (view, doc) = cx.current();
814− _delete_selection(doc, view.id);
815+ _delete_selection(reg, doc, view.id);
815816 enter_insert_mode(doc);
816817}
817818
@@ -1893,11 +1894,13 @@ pub fn yank(cx: &mut Context) {
18931894 .map(Cow::into_owned)
18941895 .collect();
18951896
1896− // TODO: allow specifying reg
1897− let reg = '"';
1898− let msg = format!("yanked {} selection(s) to register {}", values.len(), reg);
1897+ let msg = format!(
1898+ "yanked {} selection(s) to register {}",
1899+ values.len(),
1900+ cx.register.name()
1901+ );
18991902
1900− register::set(reg, values);
1903+ register::set(cx.register.name(), values);
19011904
19021905 cx.editor.set_status(msg)
19031906}
@@ -1908,9 +1911,7 @@ enum Paste {
19081911 After,
19091912}
19101913
1911−fn _paste(doc: &mut Document, view: &View, action: Paste) -> Option<Transaction> {
1912− // TODO: allow specifying reg
1913− let reg = '"';
1914+fn _paste(reg: char, doc: &mut Document, view: &View, action: Paste) -> Option<Transaction> {
19141915 if let Some(values) = register::get(reg) {
19151916 let repeat = std::iter::repeat(
19161917 values
@@ -1956,18 +1957,20 @@ fn _paste(doc: &mut Document, view: &View, action: Paste) -> Option<Transaction>
19561957// default insert
19571958
19581959pub fn paste_after(cx: &mut Context) {
1960+ let reg = cx.register.name();
19591961 let (view, doc) = cx.current();
19601962
1961− if let Some(transaction) = _paste(doc, view, Paste::After) {
1963+ if let Some(transaction) = _paste(reg, doc, view, Paste::After) {
19621964 doc.apply(&transaction, view.id);
19631965 doc.append_changes_to_history(view.id);
19641966 }
19651967}
19661968
19671969pub fn paste_before(cx: &mut Context) {
1970+ let reg = cx.register.name();
19681971 let (view, doc) = cx.current();
19691972
1970− if let Some(transaction) = _paste(doc, view, Paste::Before) {
1973+ if let Some(transaction) = _paste(reg, doc, view, Paste::Before) {
19711974 doc.apply(&transaction, view.id);
19721975 doc.append_changes_to_history(view.id);
19731976 }
@@ -2426,6 +2429,18 @@ pub fn wclose(cx: &mut Context) {
24262429 cx.editor.close(view_id, /* close_buffer */ false);
24272430}
24282431
2432+pub fn select_register(cx: &mut Context) {
2433+ cx.on_next_key(move |cx, event| {
2434+ if let KeyEvent {
2435+ code: KeyCode::Char(ch),
2436+ ..
2437+ } = event
2438+ {
2439+ cx.editor.register.select(ch);
2440+ }
2441+ })
2442+}
2443+
24292444pub fn space_mode(cx: &mut Context) {
24302445 cx.on_next_key(move |cx, event| {
24312446 if let KeyEvent {
@@ -2439,7 +2454,7 @@ pub fn space_mode(cx: &mut Context) {
24392454 'b' => buffer_picker(cx),
24402455 'w' => window_mode(cx),
24412456 // ' ' => toggle_alternate_buffer(cx),
2442− // TODO: temporary since space mode took it's old key
2457+ // TODO: temporary since space mode took its old key
24432458 ' ' => keep_primary_selection(cx),
24442459 _ => (),
24452460 }
helix-term/src/keymap.rs+2
@@ -284,6 +284,8 @@ pub fn default() -> Keymaps {
284284
285285 key!(' ') => commands::space_mode,
286286 key!('z') => commands::view_mode,
287+
288+ key!('"') => commands::select_register,
287289 );
288290 // TODO: decide whether we want normal mode to also be select mode (kakoune-like), or whether
289291 // we keep this separate select mode. More keys can fit into normal mode then, but it's weird
helix-term/src/ui/editor.rs+6−2
@@ -537,6 +537,9 @@ impl EditorView {
537537 // if this fails, count was Some(0)
538538 // debug_assert!(cxt.count != 0);
539539
540+ // set the register
541+ cxt.register = cxt.editor.register.take();
542+
540543 if let Some(command) = self.keymap[&mode].get(&event) {
541544 command(cxt);
542545 }
@@ -575,11 +578,12 @@ impl Component for EditorView {
575578 let mode = doc.mode();
576579
577580 let mut cxt = commands::Context {
578− editor: &mut cx.editor,
581+ register: helix_view::RegisterSelection::default(),
579582 count: 1,
583+ editor: &mut cx.editor,
580584 callback: None,
581− callbacks: cx.callbacks,
582585 on_next_key_callback: None,
586+ callbacks: cx.callbacks,
583587 };
584588
585589 if let Some(on_next_key) = self.on_next_key.take() {
helix-view/src/editor.rs+3−1
@@ -1,4 +1,4 @@
1−use crate::{theme::Theme, tree::Tree, Document, DocumentId, View, ViewId};
1+use crate::{theme::Theme, tree::Tree, Document, DocumentId, RegisterSelection, View, ViewId};
22use tui::layout::Rect;
33
44use std::path::PathBuf;
@@ -13,6 +13,7 @@ pub struct Editor {
1313 pub tree: Tree,
1414 pub documents: SlotMap<DocumentId, Document>,
1515 pub count: Option<usize>,
16+ pub register: RegisterSelection,
1617 pub theme: Theme,
1718 pub language_servers: helix_lsp::Registry,
1819
@@ -57,6 +58,7 @@ impl Editor {
5758 tree: Tree::new(area),
5859 documents: SlotMap::with_key(),
5960 count: None,
61+ register: RegisterSelection::default(),
6062 theme,
6163 language_servers,
6264 status_msg: None,
helix-view/src/lib.rs+2
@@ -1,5 +1,6 @@
11pub mod document;
22pub mod editor;
3+pub mod register_selection;
34pub mod theme;
45pub mod tree;
56pub mod view;
@@ -10,5 +11,6 @@ new_key_type! { pub struct ViewId; }
1011
1112pub use document::Document;
1213pub use editor::Editor;
14+pub use register_selection::RegisterSelection;
1315pub use theme::Theme;
1416pub use view::View;
helix-view/src/register_selection.rsnew file+47
@@ -0,0 +1,47 @@
1+/// Register selection and configuration
2+///
3+/// This is a kind a of specialized `Option<char>` for register selection.
4+/// Point is to keep whether the register selection has been explicitely
5+/// set or not while being convenient by knowing the default register name.
6+pub struct RegisterSelection {
7+ selected: char,
8+ default_name: char,
9+}
10+
11+impl RegisterSelection {
12+ pub fn new(default_name: char) -> Self {
13+ Self {
14+ selected: default_name,
15+ default_name,
16+ }
17+ }
18+
19+ pub fn select(&mut self, name: char) {
20+ self.selected = name;
21+ }
22+
23+ pub fn take(&mut self) -> Self {
24+ Self {
25+ selected: std::mem::replace(&mut self.selected, self.default_name),
26+ default_name: self.default_name,
27+ }
28+ }
29+
30+ pub fn is_default(&self) -> bool {
31+ self.selected == self.default_name
32+ }
33+
34+ pub fn name(&self) -> char {
35+ self.selected
36+ }
37+}
38+
39+impl Default for RegisterSelection {
40+ fn default() -> Self {
41+ let default_name = '"';
42+ Self {
43+ selected: default_name,
44+ default_name,
45+ }
46+ }
47+}