@@ -4,8 +4,9 @@ use helix_core::{
44 movement::{self, Direction},
55 object, pos_at_coords,
66 regex::{self, Regex},
7− register, search, selection, Change, ChangeSet, Position, Range, Rope, RopeSlice, Selection,
8− SmallVec, Tendril, Transaction,
7+ register::{self, Register, Registers},
8+ search, selection, Change, ChangeSet, Position, Range, Rope, RopeSlice, Selection, SmallVec,
9+ Tendril, Transaction,
910};
1011
1112use helix_view::{
@@ -39,7 +40,7 @@ use crossterm::event::{KeyCode, KeyEvent};
3940use once_cell::sync::Lazy;
4041
4142pub struct Context<'a> {
42− pub register: helix_view::RegisterSelection,
43+ pub selected_register: helix_view::RegisterSelection,
4344 pub count: Option<std::num::NonZeroUsize>,
4445 pub editor: &'a mut Editor,
4546
@@ -65,6 +66,11 @@ impl<'a> Context<'a> {
6566 self.editor.current()
6667 }
6768
69+ #[inline]
70+ pub fn current_with_registers(&mut self) -> (&mut View, &mut Document, &mut Registers) {
71+ self.editor.current_with_registers()
72+ }
73+
6874 /// Push a new component onto the compositor.
6975 pub fn push_layer(&mut self, mut component: Box<dyn Component>) {
7076 self.callback = Some(Box::new(|compositor: &mut Compositor| {
@@ -631,7 +637,7 @@ pub fn select_all(cx: &mut Context) {
631637}
632638
633639pub 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| {
635641 let text = doc.text().slice(..);
636642 if let Some(selection) = selection::select_on_matches(text, doc.selection(view.id), ®ex)
637643 {
@@ -643,7 +649,7 @@ pub fn select_regex(cx: &mut Context) {
643649}
644650
645651pub 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| {
647653 let text = doc.text().slice(..);
648654 let selection = selection::split_on_matches(text, doc.selection(view.id), ®ex);
649655 doc.set_selection(view.id, selection);
@@ -714,20 +720,24 @@ pub fn search(cx: &mut Context) {
714720 let contents = doc.text().slice(..).to_string();
715721
716722 let view_id = view.id;
717− let prompt = ui::regex_prompt(cx, "search:".to_string(), move |view, doc, regex| {
718− search_impl(doc, view, &contents, ®ex, false);
719− // TODO: only store on enter (accept), not update
720− register::set('\\', vec![regex.as_str().to_string()]);
721− });
723+ let prompt = ui::regex_prompt(
724+ cx,
725+ "search:".to_string(),
726+ move |view, doc, registers, regex| {
727+ search_impl(doc, view, &contents, ®ex, false);
728+ // TODO: only store on enter (accept), not update
729+ registers.write('\\', vec![regex.as_str().to_string()]);
730+ },
731+ );
722732
723733 cx.push_layer(Box::new(prompt));
724734}
725735// can't search next for ""compose"" for some reason
726736
727737pub fn search_next_impl(cx: &mut Context, extend: bool) {
728− if let Some(query) = register::get('\\') {
738+ let (view, doc, registers) = cx.current_with_registers();
739+ if let Some(query) = registers.read('\\') {
729740 let query = query.first().unwrap();
730− let (view, doc) = cx.current();
731741 let contents = doc.text().slice(..).to_string();
732742 let regex = Regex::new(query).unwrap();
733743 search_impl(doc, view, &contents, ®ex, extend);
@@ -747,7 +757,7 @@ pub fn search_selection(cx: &mut Context) {
747757 let contents = doc.text().slice(..);
748758 let query = doc.selection(view.id).primary().fragment(contents);
749759 let regex = regex::escape(&query);
750− register::set('\\', vec![regex]);
760+ cx.editor.registers.write('\\', vec![regex]);
751761 search_next(cx);
752762}
753763
@@ -794,7 +804,7 @@ pub fn extend_line(cx: &mut Context) {
794804
795805// heuristic: append changes to history after each command, unless we're in insert mode
796806
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) {
798808 // first yank the selection
799809 let values: Vec<String> = doc
800810 .selection(view_id)
@@ -802,7 +812,7 @@ fn delete_selection_impl(reg: char, doc: &mut Document, view_id: ViewId) {
802812 .map(Cow::into_owned)
803813 .collect();
804814
805− register::set(reg, values);
815+ reg.write(values);
806816
807817 // then delete
808818 let transaction =
@@ -815,8 +825,9 @@ fn delete_selection_impl(reg: char, doc: &mut Document, view_id: ViewId) {
815825}
816826
817827pub fn delete_selection(cx: &mut Context) {
818− let reg = cx.register.name();
819− let (view, doc) = cx.current();
828+ let reg_name = cx.selected_register.name();
829+ let (view, doc, registers) = cx.current_with_registers();
830+ let reg = registers.get_or_insert(reg_name);
820831 delete_selection_impl(reg, doc, view.id);
821832
822833 doc.append_changes_to_history(view.id);
@@ -826,8 +837,9 @@ pub fn delete_selection(cx: &mut Context) {
826837}
827838
828839pub fn change_selection(cx: &mut Context) {
829− let reg = cx.register.name();
830− let (view, doc) = cx.current();
840+ let reg_name = cx.selected_register.name();
841+ let (view, doc, registers) = cx.current_with_registers();
842+ let reg = registers.get_or_insert(reg_name);
831843 delete_selection_impl(reg, doc, view.id);
832844 enter_insert_mode(doc);
833845}
@@ -2227,10 +2239,12 @@ pub fn yank(cx: &mut Context) {
22272239 let msg = format!(
22282240 "yanked {} selection(s) to register {}",
22292241 values.len(),
2230− cx.register.name()
2242+ cx.selected_register.name()
22312243 );
22322244
2233− register::set(cx.register.name(), values);
2245+ cx.editor
2246+ .registers
2247+ .write(cx.selected_register.name(), values);
22342248
22352249 cx.editor.set_status(msg)
22362250}
@@ -2241,47 +2255,48 @@ enum Paste {
22412255 After,
22422256}
22432257
2244−fn paste_impl(reg: char, doc: &mut Document, view: &View, action: Paste) -> Option<Transaction> {
2245− if let Some(values) = register::get(reg) {
2246− let repeat = std::iter::repeat(
2247− values
2248− .last()
2249− .map(|value| Tendril::from_slice(value))
2250− .unwrap(),
2251− );
2258+fn paste_impl(
2259+ values: &[String],
2260+ doc: &mut Document,
2261+ view: &View,
2262+ action: Paste,
2263+) -> Option<Transaction> {
2264+ let repeat = std::iter::repeat(
2265+ values
2266+ .last()
2267+ .map(|value| Tendril::from_slice(value))
2268+ .unwrap(),
2269+ );
22522270
2253− // if any of values ends \n it's linewise paste
2254− let linewise = values.iter().any(|value| value.ends_with('\n'));
2271+ // if any of values ends \n it's linewise paste
2272+ let linewise = values.iter().any(|value| value.ends_with('\n'));
22552273
2256− let mut values = values.into_iter().map(Tendril::from).chain(repeat);
2274+ let mut values = values.iter().cloned().map(Tendril::from).chain(repeat);
22572275
2258− let text = doc.text();
2276+ let text = doc.text();
22592277
2260− let transaction =
2261− Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
2262− let pos = match (action, linewise) {
2263− // paste linewise before
2264− (Paste::Before, true) => text.line_to_char(text.char_to_line(range.from())),
2265− // paste linewise after
2266− (Paste::After, true) => text.line_to_char(text.char_to_line(range.to()) + 1),
2267− // paste insert
2268− (Paste::Before, false) => range.from(),
2269− // paste append
2270− (Paste::After, false) => range.to() + 1,
2271− };
2272− (pos, pos, Some(values.next().unwrap()))
2273− });
2274− return Some(transaction);
2275− }
2276− None
2278+ let transaction = Transaction::change_by_selection(text, doc.selection(view.id), |range| {
2279+ let pos = match (action, linewise) {
2280+ // paste linewise before
2281+ (Paste::Before, true) => text.line_to_char(text.char_to_line(range.from())),
2282+ // paste linewise after
2283+ (Paste::After, true) => text.line_to_char(text.char_to_line(range.to()) + 1),
2284+ // paste insert
2285+ (Paste::Before, false) => range.from(),
2286+ // paste append
2287+ (Paste::After, false) => range.to() + 1,
2288+ };
2289+ (pos, pos, Some(values.next().unwrap()))
2290+ });
2291+
2292+ Some(transaction)
22772293}
22782294
22792295pub fn replace_with_yanked(cx: &mut Context) {
2280− let reg = cx.register.name();
2281−
2282− if let Some(values) = register::get(reg) {
2283− let (view, doc) = cx.current();
2296+ let reg_name = cx.selected_register.name();
2297+ let (view, doc, registers) = cx.current_with_registers();
22842298
2299+ if let Some(values) = registers.read(reg_name) {
22852300 if let Some(yank) = values.first() {
22862301 let transaction =
22872302 Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
@@ -2307,20 +2322,26 @@ pub fn replace_with_yanked(cx: &mut Context) {
23072322// default insert
23082323
23092324pub fn paste_after(cx: &mut Context) {
2310− let reg = cx.register.name();
2311− let (view, doc) = cx.current();
2325+ let reg_name = cx.selected_register.name();
2326+ let (view, doc, registers) = cx.current_with_registers();
23122327
2313− if let Some(transaction) = paste_impl(reg, doc, view, Paste::After) {
2328+ if let Some(transaction) = registers
2329+ .read(reg_name)
2330+ .and_then(|values| paste_impl(values, doc, view, Paste::After))
2331+ {
23142332 doc.apply(&transaction, view.id);
23152333 doc.append_changes_to_history(view.id);
23162334 }
23172335}
23182336
23192337pub fn paste_before(cx: &mut Context) {
2320− let reg = cx.register.name();
2321− let (view, doc) = cx.current();
2338+ let reg_name = cx.selected_register.name();
2339+ let (view, doc, registers) = cx.current_with_registers();
23222340
2323− if let Some(transaction) = paste_impl(reg, doc, view, Paste::Before) {
2341+ if let Some(transaction) = registers
2342+ .read(reg_name)
2343+ .and_then(|values| paste_impl(values, doc, view, Paste::Before))
2344+ {
23242345 doc.apply(&transaction, view.id);
23252346 doc.append_changes_to_history(view.id);
23262347 }
@@ -2494,7 +2515,7 @@ pub fn join_selections(cx: &mut Context) {
24942515
24952516pub fn keep_selections(cx: &mut Context) {
24962517 // 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| {
24982519 let text = doc.text().slice(..);
24992520
25002521 if let Some(selection) = selection::keep_matches(text, doc.selection(view.id), ®ex) {
@@ -2788,7 +2809,7 @@ pub fn select_register(cx: &mut Context) {
27882809 ..
27892810 } = event
27902811 {
2791− cx.editor.register.select(ch);
2812+ cx.editor.selected_register.select(ch);
27922813 }
27932814 })
27942815}