@@ -4,8 +4,9 @@ use helix_core::{
4 movement::{self, Direction},
4 movement::{self, Direction},
5 object, pos_at_coords,
5 object, pos_at_coords,
6 regex::{self, Regex},
6 regex::{self, Regex},
7+ register::{self, Register, Registers},
7− register, search, selection, Change, ChangeSet, Position, Range, Rope, RopeSlice, Selection,
8+ search, selection, Change, ChangeSet, Position, Range, Rope, RopeSlice, Selection, SmallVec,
8− SmallVec, Tendril, Transaction,
9+ Tendril, Transaction,
11use helix_view::{
12use helix_view::{
@@ -39,7 +40,7 @@ use crossterm::event::{KeyCode, KeyEvent};
39use once_cell::sync::Lazy;
40use once_cell::sync::Lazy;
41pub struct Context<'a> {
42pub struct Context<'a> {
42− pub register: helix_view::RegisterSelection,
43+ pub selected_register: helix_view::RegisterSelection,
43 pub count: Option<std::num::NonZeroUsize>,
44 pub count: Option<std::num::NonZeroUsize>,
44 pub editor: &'a mut Editor,
45 pub editor: &'a mut Editor,
@@ -65,6 +66,11 @@ impl<'a> Context<'a> {
65 self.editor.current()
66 self.editor.current()
70+ pub fn current_with_registers(&mut self) -> (&mut View, &mut Document, &mut Registers) {
71+ self.editor.current_with_registers()
68 /// Push a new component onto the compositor.
74 /// Push a new component onto the compositor.
69 pub fn push_layer(&mut self, mut component: Box<dyn Component>) {
75 pub fn push_layer(&mut self, mut component: Box<dyn Component>) {
70 self.callback = Some(Box::new(|compositor: &mut Compositor| {
76 self.callback = Some(Box::new(|compositor: &mut Compositor| {
@@ -631,7 +637,7 @@ pub fn select_all(cx: &mut Context) {
633pub fn select_regex(cx: &mut Context) {
639pub fn select_regex(cx: &mut Context) {
634− let prompt = ui::regex_prompt(cx, "select:".to_string(), move |view, doc, regex| {
640+ let prompt = ui::regex_prompt(cx, "select:".to_string(), move |view, doc, _, regex| {
635 let text = doc.text().slice(..);
641 let text = doc.text().slice(..);
636 if let Some(selection) = selection::select_on_matches(text, doc.selection(view.id), ®ex)
642 if let Some(selection) = selection::select_on_matches(text, doc.selection(view.id), ®ex)
@@ -643,7 +649,7 @@ pub fn select_regex(cx: &mut Context) {
645pub fn split_selection(cx: &mut Context) {
651pub fn split_selection(cx: &mut Context) {
646− let prompt = ui::regex_prompt(cx, "split:".to_string(), move |view, doc, regex| {
652+ let prompt = ui::regex_prompt(cx, "split:".to_string(), move |view, doc, _, regex| {
647 let text = doc.text().slice(..);
653 let text = doc.text().slice(..);
648 let selection = selection::split_on_matches(text, doc.selection(view.id), ®ex);
654 let selection = selection::split_on_matches(text, doc.selection(view.id), ®ex);
649 doc.set_selection(view.id, selection);
655 doc.set_selection(view.id, selection);
@@ -714,20 +720,24 @@ pub fn search(cx: &mut Context) {
714 let contents = doc.text().slice(..).to_string();
720 let contents = doc.text().slice(..).to_string();
716 let view_id = view.id;
722 let view_id = view.id;
717− let prompt = ui::regex_prompt(cx, "search:".to_string(), move |view, doc, regex| {
723+ let prompt = ui::regex_prompt(
725+ "search:".to_string(),
726+ move |view, doc, registers, regex| {
718− search_impl(doc, view, &contents, ®ex, false);
727+ search_impl(doc, view, &contents, ®ex, false);
719− // TODO: only store on enter (accept), not update
728+ // TODO: only store on enter (accept), not update
720− register::set('\\', vec![regex.as_str().to_string()]);
729+ registers.write('\\', vec![regex.as_str().to_string()]);
723 cx.push_layer(Box::new(prompt));
733 cx.push_layer(Box::new(prompt));
725// can't search next for ""compose"" for some reason
735// can't search next for ""compose"" for some reason
727pub fn search_next_impl(cx: &mut Context, extend: bool) {
737pub fn search_next_impl(cx: &mut Context, extend: bool) {
738+ let (view, doc, registers) = cx.current_with_registers();
728− if let Some(query) = register::get('\\') {
739+ if let Some(query) = registers.read('\\') {
729 let query = query.first().unwrap();
740 let query = query.first().unwrap();
730− let (view, doc) = cx.current();
731 let contents = doc.text().slice(..).to_string();
741 let contents = doc.text().slice(..).to_string();
732 let regex = Regex::new(query).unwrap();
742 let regex = Regex::new(query).unwrap();
733 search_impl(doc, view, &contents, ®ex, extend);
743 search_impl(doc, view, &contents, ®ex, extend);
@@ -747,7 +757,7 @@ pub fn search_selection(cx: &mut Context) {
747 let contents = doc.text().slice(..);
757 let contents = doc.text().slice(..);
748 let query = doc.selection(view.id).primary().fragment(contents);
758 let query = doc.selection(view.id).primary().fragment(contents);
749 let regex = regex::escape(&query);
759 let regex = regex::escape(&query);
750− register::set('\\', vec![regex]);
760+ cx.editor.registers.write('\\', vec![regex]);
751 search_next(cx);
761 search_next(cx);
@@ -794,7 +804,7 @@ pub fn extend_line(cx: &mut Context) {
795// heuristic: append changes to history after each command, unless we're in insert mode
805// heuristic: append changes to history after each command, unless we're in insert mode
797−fn delete_selection_impl(reg: char, doc: &mut Document, view_id: ViewId) {
807+fn delete_selection_impl(reg: &mut Register, doc: &mut Document, view_id: ViewId) {
798 // first yank the selection
808 // first yank the selection
799 let values: Vec<String> = doc
809 let values: Vec<String> = doc
800 .selection(view_id)
810 .selection(view_id)
@@ -802,7 +812,7 @@ fn delete_selection_impl(reg: char, doc: &mut Document, view_id: ViewId) {
802 .map(Cow::into_owned)
812 .map(Cow::into_owned)
803 .collect();
813 .collect();
805− register::set(reg, values);
815+ reg.write(values);
807 // then delete
817 // then delete
808 let transaction =
818 let transaction =
@@ -815,8 +825,9 @@ fn delete_selection_impl(reg: char, doc: &mut Document, view_id: ViewId) {
817pub fn delete_selection(cx: &mut Context) {
827pub fn delete_selection(cx: &mut Context) {
818− let reg = cx.register.name();
828+ let reg_name = cx.selected_register.name();
819− let (view, doc) = cx.current();
829+ let (view, doc, registers) = cx.current_with_registers();
830+ let reg = registers.get_or_insert(reg_name);
820 delete_selection_impl(reg, doc, view.id);
831 delete_selection_impl(reg, doc, view.id);
822 doc.append_changes_to_history(view.id);
833 doc.append_changes_to_history(view.id);
@@ -826,8 +837,9 @@ pub fn delete_selection(cx: &mut Context) {
828pub fn change_selection(cx: &mut Context) {
839pub fn change_selection(cx: &mut Context) {
829− let reg = cx.register.name();
840+ let reg_name = cx.selected_register.name();
830− let (view, doc) = cx.current();
841+ let (view, doc, registers) = cx.current_with_registers();
842+ let reg = registers.get_or_insert(reg_name);
831 delete_selection_impl(reg, doc, view.id);
843 delete_selection_impl(reg, doc, view.id);
832 enter_insert_mode(doc);
844 enter_insert_mode(doc);
@@ -2227,10 +2239,12 @@ pub fn yank(cx: &mut Context) {
2227 let msg = format!(
2239 let msg = format!(
2228 "yanked {} selection(s) to register {}",
2240 "yanked {} selection(s) to register {}",
2229 values.len(),
2241 values.len(),
2230− cx.register.name()
2242+ cx.selected_register.name()
2233− register::set(cx.register.name(), values);
2245+ cx.editor
2247+ .write(cx.selected_register.name(), values);
2235 cx.editor.set_status(msg)
2249 cx.editor.set_status(msg)
@@ -2241,47 +2255,48 @@ enum Paste {
2244−fn paste_impl(reg: char, doc: &mut Document, view: &View, action: Paste) -> Option<Transaction> {
2258+fn paste_impl(
2245− if let Some(values) = register::get(reg) {
2259+ values: &[String],
2260+ doc: &mut Document,
2263+) -> Option<Transaction> {
2246− let repeat = std::iter::repeat(
2264+ let repeat = std::iter::repeat(
2248− .last()
2266+ .last()
2249− .map(|value| Tendril::from_slice(value))
2267+ .map(|value| Tendril::from_slice(value))
2250− .unwrap(),
2268+ .unwrap(),
2253− // if any of values ends \n it's linewise paste
2271+ // if any of values ends \n it's linewise paste
2254− let linewise = values.iter().any(|value| value.ends_with('\n'));
2272+ let linewise = values.iter().any(|value| value.ends_with('\n'));
2256− let mut values = values.into_iter().map(Tendril::from).chain(repeat);
2274+ let mut values = values.iter().cloned().map(Tendril::from).chain(repeat);
2258− let text = doc.text();
2276+ let text = doc.text();
2261− Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
2278+ let transaction = Transaction::change_by_selection(text, doc.selection(view.id), |range| {
2262− let pos = match (action, linewise) {
2279+ let pos = match (action, linewise) {
2263− // paste linewise before
2280+ // paste linewise before
2264− (Paste::Before, true) => text.line_to_char(text.char_to_line(range.from())),
2281+ (Paste::Before, true) => text.line_to_char(text.char_to_line(range.from())),
2265− // paste linewise after
2282+ // paste linewise after
2266− (Paste::After, true) => text.line_to_char(text.char_to_line(range.to()) + 1),
2283+ (Paste::After, true) => text.line_to_char(text.char_to_line(range.to()) + 1),
2267− // paste insert
2284+ // paste insert
2268− (Paste::Before, false) => range.from(),
2285+ (Paste::Before, false) => range.from(),
2269− // paste append
2286+ // paste append
2270− (Paste::After, false) => range.to() + 1,
2287+ (Paste::After, false) => range.to() + 1,
2272− (pos, pos, Some(values.next().unwrap()))
2289+ (pos, pos, Some(values.next().unwrap()))
2274− return Some(transaction);
2292+ Some(transaction)
2279pub fn replace_with_yanked(cx: &mut Context) {
2295pub fn replace_with_yanked(cx: &mut Context) {
2280− let reg = cx.register.name();
2296+ let reg_name = cx.selected_register.name();
2281−
2297+ let (view, doc, registers) = cx.current_with_registers();
2282− if let Some(values) = register::get(reg) {
2283− let (view, doc) = cx.current();
2299+ if let Some(values) = registers.read(reg_name) {
2285 if let Some(yank) = values.first() {
2300 if let Some(yank) = values.first() {
2286 let transaction =
2301 let transaction =
2287 Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
2302 Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
@@ -2307,20 +2322,26 @@ pub fn replace_with_yanked(cx: &mut Context) {
2307// default insert
2322// default insert
2309pub fn paste_after(cx: &mut Context) {
2324pub fn paste_after(cx: &mut Context) {
2310− let reg = cx.register.name();
2325+ let reg_name = cx.selected_register.name();
2311− let (view, doc) = cx.current();
2326+ let (view, doc, registers) = cx.current_with_registers();
2328+ if let Some(transaction) = registers
2313− if let Some(transaction) = paste_impl(reg, doc, view, Paste::After) {
2330+ .and_then(|values| paste_impl(values, doc, view, Paste::After))
2314 doc.apply(&transaction, view.id);
2332 doc.apply(&transaction, view.id);
2315 doc.append_changes_to_history(view.id);
2333 doc.append_changes_to_history(view.id);
2319pub fn paste_before(cx: &mut Context) {
2337pub fn paste_before(cx: &mut Context) {
2320− let reg = cx.register.name();
2338+ let reg_name = cx.selected_register.name();
2321− let (view, doc) = cx.current();
2339+ let (view, doc, registers) = cx.current_with_registers();
2341+ if let Some(transaction) = registers
2323− if let Some(transaction) = paste_impl(reg, doc, view, Paste::Before) {
2343+ .and_then(|values| paste_impl(values, doc, view, Paste::Before))
2324 doc.apply(&transaction, view.id);
2345 doc.apply(&transaction, view.id);
2325 doc.append_changes_to_history(view.id);
2346 doc.append_changes_to_history(view.id);
@@ -2494,7 +2515,7 @@ pub fn join_selections(cx: &mut Context) {
2495pub fn keep_selections(cx: &mut Context) {
2516pub fn keep_selections(cx: &mut Context) {
2496 // keep selections matching regex
2517 // keep selections matching regex
2497− let prompt = ui::regex_prompt(cx, "keep:".to_string(), move |view, doc, regex| {
2518+ let prompt = ui::regex_prompt(cx, "keep:".to_string(), move |view, doc, _, regex| {
2498 let text = doc.text().slice(..);
2519 let text = doc.text().slice(..);
2500 if let Some(selection) = selection::keep_matches(text, doc.selection(view.id), ®ex) {
2521 if let Some(selection) = selection::keep_matches(text, doc.selection(view.id), ®ex) {
@@ -2788,7 +2809,7 @@ pub fn select_register(cx: &mut Context) {
2789 } = event
2810 } = event
2791− cx.editor.register.select(ch);
2812+ cx.editor.selected_register.select(ch);