on master help sign in
Implement register selection
68affa3Benoît CORTIER
helix-core/src/register.rs+6−7
@@ -6,16 +6,15 @@ use std::{collections::HashMap, sync::RwLock};
6static REGISTRY: Lazy<RwLock<HashMap<char, Vec<String>>>> =
6static REGISTRY: Lazy<RwLock<HashMap<char, Vec<String>>>> =
7 Lazy::new(|| RwLock::new(HashMap::new()));
7 Lazy::new(|| RwLock::new(HashMap::new()));
8
8
9+/// Read register values.
9−pub fn get(register: char) -> Option<Vec<String>> {
10+pub fn get(register_name: char) -> Option<Vec<String>> {
10 let registry = REGISTRY.read().unwrap();
11 let registry = REGISTRY.read().unwrap();
11−
12− // TODO: no cloning
12+ registry.get(&register_name).cloned() // TODO: no cloning
13− registry.get(&register).cloned()
14}
13}
15
14
15+/// Read register values.
16// restoring: bool
16// restoring: bool
17−pub fn set(register: char, values: Vec<String>) {
17+pub fn set(register_name: char, values: Vec<String>) {
18 let mut registry = REGISTRY.write().unwrap();
18 let mut registry = REGISTRY.write().unwrap();
19−
20− registry.insert(register, values);
19+ registry.insert(register_name, values);
21}
20}
helix-term/src/commands.rs+30−15
@@ -35,6 +35,7 @@ use crossterm::event::{KeyCode, KeyEvent};
35use once_cell::sync::Lazy;
35use once_cell::sync::Lazy;
36
36
37pub struct Context<'a> {
37pub struct Context<'a> {
38+ pub register: helix_view::RegisterSelection,
38 pub count: usize,
39 pub count: usize,
39 pub editor: &'a mut Editor,
40 pub editor: &'a mut Editor,
40
41
@@ -777,7 +778,7 @@ pub fn extend_line(cx: &mut Context) {
777
778
778// heuristic: append changes to history after each command, unless we're in insert mode
779// heuristic: append changes to history after each command, unless we're in insert mode
779
780
780−fn _delete_selection(doc: &mut Document, view_id: ViewId) {
781+fn _delete_selection(reg: char, doc: &mut Document, view_id: ViewId) {
781 // first yank the selection
782 // first yank the selection
782 let values: Vec<String> = doc
783 let values: Vec<String> = doc
783 .selection(view_id)
784 .selection(view_id)
@@ -785,8 +786,6 @@ fn _delete_selection(doc: &mut Document, view_id: ViewId) {
785 .map(Cow::into_owned)
786 .map(Cow::into_owned)
786 .collect();
787 .collect();
787
788
788− // TODO: allow specifying reg
789− let reg = '"';
790 register::set(reg, values);
789 register::set(reg, values);
791
790
792 // then delete
791 // then delete
@@ -800,8 +799,9 @@ fn _delete_selection(doc: &mut Document, view_id: ViewId) {
800}
799}
801
800
802pub fn delete_selection(cx: &mut Context) {
801pub fn delete_selection(cx: &mut Context) {
802+ let reg = cx.register.name();
803 let (view, doc) = cx.current();
803 let (view, doc) = cx.current();
804− _delete_selection(doc, view.id);
804+ _delete_selection(reg, doc, view.id);
805
805
806 doc.append_changes_to_history(view.id);
806 doc.append_changes_to_history(view.id);
807
807
@@ -810,8 +810,9 @@ pub fn delete_selection(cx: &mut Context) {
810}
810}
811
811
812pub fn change_selection(cx: &mut Context) {
812pub fn change_selection(cx: &mut Context) {
813+ let reg = cx.register.name();
813 let (view, doc) = cx.current();
814 let (view, doc) = cx.current();
814− _delete_selection(doc, view.id);
815+ _delete_selection(reg, doc, view.id);
815 enter_insert_mode(doc);
816 enter_insert_mode(doc);
816}
817}
817
818
@@ -1893,11 +1894,13 @@ pub fn yank(cx: &mut Context) {
1893 .map(Cow::into_owned)
1894 .map(Cow::into_owned)
1894 .collect();
1895 .collect();
1895
1896
1896− // TODO: allow specifying reg
1897+ let msg = format!(
1897− let reg = '"';
1898− let msg = format!("yanked {} selection(s) to register {}", values.len(), reg);
1898+ "yanked {} selection(s) to register {}",
1899+ values.len(),
1900+ cx.register.name()
1901+ );
1899
1902
1900− register::set(reg, values);
1903+ register::set(cx.register.name(), values);
1901
1904
1902 cx.editor.set_status(msg)
1905 cx.editor.set_status(msg)
1903}
1906}
@@ -1908,9 +1911,7 @@ enum Paste {
1908 After,
1911 After,
1909}
1912}
1910
1913
1911−fn _paste(doc: &mut Document, view: &View, action: Paste) -> Option<Transaction> {
1914+fn _paste(reg: char, doc: &mut Document, view: &View, action: Paste) -> Option<Transaction> {
1912− // TODO: allow specifying reg
1913− let reg = '"';
1914 if let Some(values) = register::get(reg) {
1915 if let Some(values) = register::get(reg) {
1915 let repeat = std::iter::repeat(
1916 let repeat = std::iter::repeat(
1916 values
1917 values
@@ -1956,18 +1957,20 @@ fn _paste(doc: &mut Document, view: &View, action: Paste) -> Option<Transaction>
1956// default insert
1957// default insert
1957
1958
1958pub fn paste_after(cx: &mut Context) {
1959pub fn paste_after(cx: &mut Context) {
1960+ let reg = cx.register.name();
1959 let (view, doc) = cx.current();
1961 let (view, doc) = cx.current();
1960
1962
1961− if let Some(transaction) = _paste(doc, view, Paste::After) {
1963+ if let Some(transaction) = _paste(reg, doc, view, Paste::After) {
1962 doc.apply(&transaction, view.id);
1964 doc.apply(&transaction, view.id);
1963 doc.append_changes_to_history(view.id);
1965 doc.append_changes_to_history(view.id);
1964 }
1966 }
1965}
1967}
1966
1968
1967pub fn paste_before(cx: &mut Context) {
1969pub fn paste_before(cx: &mut Context) {
1970+ let reg = cx.register.name();
1968 let (view, doc) = cx.current();
1971 let (view, doc) = cx.current();
1969
1972
1970− if let Some(transaction) = _paste(doc, view, Paste::Before) {
1973+ if let Some(transaction) = _paste(reg, doc, view, Paste::Before) {
1971 doc.apply(&transaction, view.id);
1974 doc.apply(&transaction, view.id);
1972 doc.append_changes_to_history(view.id);
1975 doc.append_changes_to_history(view.id);
1973 }
1976 }
@@ -2426,6 +2429,18 @@ pub fn wclose(cx: &mut Context) {
2426 cx.editor.close(view_id, /* close_buffer */ false);
2429 cx.editor.close(view_id, /* close_buffer */ false);
2427}
2430}
2428
2431
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+
2429pub fn space_mode(cx: &mut Context) {
2444pub fn space_mode(cx: &mut Context) {
2430 cx.on_next_key(move |cx, event| {
2445 cx.on_next_key(move |cx, event| {
2431 if let KeyEvent {
2446 if let KeyEvent {
@@ -2439,7 +2454,7 @@ pub fn space_mode(cx: &mut Context) {
2439 'b' => buffer_picker(cx),
2454 'b' => buffer_picker(cx),
2440 'w' => window_mode(cx),
2455 'w' => window_mode(cx),
2441 // ' ' => toggle_alternate_buffer(cx),
2456 // ' ' => 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
2443 ' ' => keep_primary_selection(cx),
2458 ' ' => keep_primary_selection(cx),
2444 _ => (),
2459 _ => (),
2445 }
2460 }
helix-term/src/keymap.rs+2
@@ -284,6 +284,8 @@ pub fn default() -> Keymaps {
284
284
285 key!(' ') => commands::space_mode,
285 key!(' ') => commands::space_mode,
286 key!('z') => commands::view_mode,
286 key!('z') => commands::view_mode,
287+
288+ key!('"') => commands::select_register,
287 );
289 );
288 // TODO: decide whether we want normal mode to also be select mode (kakoune-like), or whether
290 // TODO: decide whether we want normal mode to also be select mode (kakoune-like), or whether
289 // we keep this separate select mode. More keys can fit into normal mode then, but it's weird
291 // 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 {
537 // if this fails, count was Some(0)
537 // if this fails, count was Some(0)
538 // debug_assert!(cxt.count != 0);
538 // debug_assert!(cxt.count != 0);
539
539
540+ // set the register
541+ cxt.register = cxt.editor.register.take();
542+
540 if let Some(command) = self.keymap[&mode].get(&event) {
543 if let Some(command) = self.keymap[&mode].get(&event) {
541 command(cxt);
544 command(cxt);
542 }
545 }
@@ -575,11 +578,12 @@ impl Component for EditorView {
575 let mode = doc.mode();
578 let mode = doc.mode();
576
579
577 let mut cxt = commands::Context {
580 let mut cxt = commands::Context {
578− editor: &mut cx.editor,
581+ register: helix_view::RegisterSelection::default(),
579 count: 1,
582 count: 1,
583+ editor: &mut cx.editor,
580 callback: None,
584 callback: None,
581− callbacks: cx.callbacks,
582 on_next_key_callback: None,
585 on_next_key_callback: None,
586+ callbacks: cx.callbacks,
583 };
587 };
584
588
585 if let Some(on_next_key) = self.on_next_key.take() {
589 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};
2use tui::layout::Rect;
2use tui::layout::Rect;
3
3
4use std::path::PathBuf;
4use std::path::PathBuf;
@@ -13,6 +13,7 @@ pub struct Editor {
13 pub tree: Tree,
13 pub tree: Tree,
14 pub documents: SlotMap<DocumentId, Document>,
14 pub documents: SlotMap<DocumentId, Document>,
15 pub count: Option<usize>,
15 pub count: Option<usize>,
16+ pub register: RegisterSelection,
16 pub theme: Theme,
17 pub theme: Theme,
17 pub language_servers: helix_lsp::Registry,
18 pub language_servers: helix_lsp::Registry,
18
19
@@ -57,6 +58,7 @@ impl Editor {
57 tree: Tree::new(area),
58 tree: Tree::new(area),
58 documents: SlotMap::with_key(),
59 documents: SlotMap::with_key(),
59 count: None,
60 count: None,
61+ register: RegisterSelection::default(),
60 theme,
62 theme,
61 language_servers,
63 language_servers,
62 status_msg: None,
64 status_msg: None,
helix-view/src/lib.rs+2
@@ -1,5 +1,6 @@
1pub mod document;
1pub mod document;
2pub mod editor;
2pub mod editor;
3+pub mod register_selection;
3pub mod theme;
4pub mod theme;
4pub mod tree;
5pub mod tree;
5pub mod view;
6pub mod view;
@@ -10,5 +11,6 @@ new_key_type! { pub struct ViewId; }
10
11
11pub use document::Document;
12pub use document::Document;
12pub use editor::Editor;
13pub use editor::Editor;
14+pub use register_selection::RegisterSelection;
13pub use theme::Theme;
15pub use theme::Theme;
14pub use view::View;
16pub 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+}