on master help sign in
Reimplement clipboard commands in terms of special regs

Since the clipboard provider now lives on the Registers type, we want to eliminate it from the Editor. We can do that and clean up the commands that interact with the clipboard by calling regular yank, paste and replace impls on the clipboard special registers. Eventually the clipboard commands could be removed once macro keybinding is supported.

commit4555a6b4332b48384d4bccfef527d26060c34037 authorMichael Davis <mcarsondavis@gmail.com> dateTue 11 Jul 2023, 10:23 (3 years ago) parent2d838d7
4 files changed+89−201
helix-term/src/commands.rs+64−163 helix-term/src/commands/typed.rs+21−34 helix-view/src/editor.rs−4 helix-view/src/register.rs+4
helix-term/src/commands.rs+64−163
@@ -32,7 +32,6 @@ use helix_core::{
3232 RopeReader, RopeSlice, Selection, SmallVec, Tendril, Transaction,
3333};
3434use helix_view::{
35− clipboard::ClipboardType,
3635 document::{FormatterError, Mode, SCRATCH_BUFFER_NAME},
3736 editor::{Action, CompleteAction},
3837 info::Info,
@@ -3759,7 +3758,12 @@ fn commit_undo_checkpoint(cx: &mut Context) {
37593758// Yank / Paste
37603759
37613760fn yank(cx: &mut Context) {
3762− let (view, doc) = current!(cx.editor);
3761+ yank_impl(cx.editor, cx.register.unwrap_or('"'));
3762+ exit_select_mode(cx);
3763+}
3764+
3765+fn yank_impl(editor: &mut Editor, register: char) {
3766+ let (view, doc) = current!(editor);
37633767 let text = doc.text().slice(..);
37643768
37653769 let values: Vec<String> = doc
@@ -3768,16 +3772,14 @@ fn yank(cx: &mut Context) {
37683772 .map(Cow::into_owned)
37693773 .collect();
37703774 let selections = values.len();
3771− let register = cx.register.unwrap_or('"');
37723775
3773− match cx.editor.registers.write(register, values) {
3774− Ok(_) => cx.editor.set_status(format!(
3775− "yanked {selections} selection(s) to register {register}",
3776+ match editor.registers.write(register, values) {
3777+ Ok(_) => editor.set_status(format!(
3778+ "yanked {selections} selection{} to register {register}",
3779+ if selections == 1 { "" } else { "s" }
37763780 )),
3777− Err(err) => cx.editor.set_error(err.to_string()),
3781+ Err(err) => editor.set_error(err.to_string()),
37783782 }
3779−
3780− exit_select_mode(cx);
37813783}
37823784
37833785fn yank_joined_impl(editor: &mut Editor, separator: &str, register: char) {
@@ -3798,100 +3800,50 @@ fn yank_joined_impl(editor: &mut Editor, separator: &str, register: char) {
37983800
37993801 match editor.registers.write(register, vec![joined]) {
38003802 Ok(_) => editor.set_status(format!(
3801− "joined and yanked {selections} selection(s) to register {register}",
3803+ "joined and yanked {selections} selection{} to register {register}",
3804+ if selections == 1 { "" } else { "s" }
38023805 )),
38033806 Err(err) => editor.set_error(err.to_string()),
38043807 }
38053808}
38063809
38073810fn yank_joined(cx: &mut Context) {
3808− let line_ending = doc!(cx.editor).line_ending;
3809− let register = cx.register.unwrap_or('"');
3810− yank_joined_impl(cx.editor, line_ending.as_str(), register);
3811+ let separator = doc!(cx.editor).line_ending.as_str();
3812+ yank_joined_impl(cx.editor, separator, cx.register.unwrap_or('"'));
38113813 exit_select_mode(cx);
38123814}
38133815
3814−fn yank_joined_to_clipboard_impl(
3815− editor: &mut Editor,
3816− separator: &str,
3817− clipboard_type: ClipboardType,
3818−) -> anyhow::Result<()> {
3819− let (view, doc) = current!(editor);
3820− let text = doc.text().slice(..);
3821−
3822− let values: Vec<String> = doc
3823− .selection(view.id)
3824− .fragments(text)
3825− .map(Cow::into_owned)
3826− .collect();
3827−
3828− let clipboard_text = match clipboard_type {
3829− ClipboardType::Clipboard => "system clipboard",
3830− ClipboardType::Selection => "primary clipboard",
3831− };
3832−
3833− let msg = format!(
3834− "joined and yanked {} selection(s) to {}",
3835− values.len(),
3836− clipboard_text,
3837− );
3838−
3839− let joined = values.join(separator);
3840−
3841− editor
3842− .clipboard_provider
3843− .set_contents(joined, clipboard_type)
3844− .context("Couldn't set system clipboard content")?;
3845−
3846− editor.set_status(msg);
3847−
3848− Ok(())
3816+fn yank_joined_to_clipboard(cx: &mut Context) {
3817+ let line_ending = doc!(cx.editor).line_ending;
3818+ yank_joined_impl(cx.editor, line_ending.as_str(), '*');
3819+ exit_select_mode(cx);
38493820}
38503821
3851−fn yank_joined_to_clipboard(cx: &mut Context) {
3822+fn yank_joined_to_primary_clipboard(cx: &mut Context) {
38523823 let line_ending = doc!(cx.editor).line_ending;
3853− let _ =
3854− yank_joined_to_clipboard_impl(cx.editor, line_ending.as_str(), ClipboardType::Clipboard);
3824+ yank_joined_impl(cx.editor, line_ending.as_str(), '+');
38553825 exit_select_mode(cx);
38563826}
38573827
3858−fn yank_main_selection_to_clipboard_impl(
3859− editor: &mut Editor,
3860− clipboard_type: ClipboardType,
3861−) -> anyhow::Result<()> {
3828+fn yank_primary_selection_impl(editor: &mut Editor, register: char) {
38623829 let (view, doc) = current!(editor);
38633830 let text = doc.text().slice(..);
38643831
3865− let message_text = match clipboard_type {
3866− ClipboardType::Clipboard => "yanked main selection to system clipboard",
3867− ClipboardType::Selection => "yanked main selection to primary clipboard",
3868− };
3869−
3870− let value = doc.selection(view.id).primary().fragment(text);
3832+ let selection = doc.selection(view.id).primary().fragment(text).to_string();
38713833
3872− if let Err(e) = editor
3873− .clipboard_provider
3874− .set_contents(value.into_owned(), clipboard_type)
3875− {
3876− bail!("Couldn't set system clipboard content: {}", e);
3834+ match editor.registers.write(register, vec![selection]) {
3835+ Ok(_) => editor.set_status(format!("yanked primary selection to register {register}",)),
3836+ Err(err) => editor.set_error(err.to_string()),
38773837 }
3878−
3879− editor.set_status(message_text);
3880− Ok(())
38813838}
38823839
38833840fn yank_main_selection_to_clipboard(cx: &mut Context) {
3884− let _ = yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Clipboard);
3885−}
3886−
3887−fn yank_joined_to_primary_clipboard(cx: &mut Context) {
3888− let line_ending = doc!(cx.editor).line_ending;
3889− let _ =
3890− yank_joined_to_clipboard_impl(cx.editor, line_ending.as_str(), ClipboardType::Selection);
3841+ yank_primary_selection_impl(cx.editor, '*');
3842+ exit_select_mode(cx);
38913843}
38923844
38933845fn yank_main_selection_to_primary_clipboard(cx: &mut Context) {
3894− let _ = yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Selection);
3846+ yank_primary_selection_impl(cx.editor, '+');
38953847 exit_select_mode(cx);
38963848}
38973849
@@ -3991,68 +3943,34 @@ pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) {
39913943 paste_impl(&[contents], doc, view, paste, count, cx.editor.mode);
39923944}
39933945
3994−fn paste_clipboard_impl(
3995− editor: &mut Editor,
3996− action: Paste,
3997− clipboard_type: ClipboardType,
3998− count: usize,
3999−) -> anyhow::Result<()> {
4000− let (view, doc) = current!(editor);
4001− match editor.clipboard_provider.get_contents(clipboard_type) {
4002− Ok(contents) => {
4003− paste_impl(&[contents], doc, view, action, count, editor.mode);
4004− Ok(())
4005− }
4006− Err(e) => Err(e.context("Couldn't get system clipboard contents")),
4007− }
4008−}
4009−
40103946fn paste_clipboard_after(cx: &mut Context) {
4011− let _ = paste_clipboard_impl(
4012− cx.editor,
4013− Paste::After,
4014− ClipboardType::Clipboard,
4015− cx.count(),
4016− );
3947+ paste(cx.editor, '*', Paste::After, cx.count());
40173948}
40183949
40193950fn paste_clipboard_before(cx: &mut Context) {
4020− let _ = paste_clipboard_impl(
4021− cx.editor,
4022− Paste::Before,
4023− ClipboardType::Clipboard,
4024− cx.count(),
4025− );
3951+ paste(cx.editor, '*', Paste::Before, cx.count());
40263952}
40273953
40283954fn paste_primary_clipboard_after(cx: &mut Context) {
4029− let _ = paste_clipboard_impl(
4030− cx.editor,
4031− Paste::After,
4032− ClipboardType::Selection,
4033− cx.count(),
4034− );
3955+ paste(cx.editor, '+', Paste::After, cx.count());
40353956}
40363957
40373958fn paste_primary_clipboard_before(cx: &mut Context) {
4038− let _ = paste_clipboard_impl(
4039− cx.editor,
4040− Paste::Before,
4041− ClipboardType::Selection,
4042− cx.count(),
4043− );
3959+ paste(cx.editor, '+', Paste::Before, cx.count());
40443960}
40453961
40463962fn replace_with_yanked(cx: &mut Context) {
4047− let count = cx.count();
4048− let reg_name = cx.register.unwrap_or('"');
3963+ replace_with_yanked_impl(cx.editor, cx.register.unwrap_or('"'), cx.count());
3964+ exit_select_mode(cx);
3965+}
40493966
4050− let Some(values) = cx.editor.registers
4051− .read(reg_name, cx.editor)
3967+fn replace_with_yanked_impl(editor: &mut Editor, register: char, count: usize) {
3968+ let Some(values) = editor.registers
3969+ .read(register, editor)
40523970 .filter(|values| values.len() > 0) else { return };
40533971 let values: Vec<_> = values.map(|value| value.to_string()).collect();
40543972
4055− let (view, doc) = current!(cx.editor);
3973+ let (view, doc) = current!(editor);
40563974 let repeat = std::iter::repeat(
40573975 values
40583976 .last()
@@ -4073,62 +3991,40 @@ fn replace_with_yanked(cx: &mut Context) {
40733991 });
40743992
40753993 doc.apply(&transaction, view.id);
4076− exit_select_mode(cx);
4077−}
4078−
4079−fn replace_selections_with_clipboard_impl(
4080− cx: &mut Context,
4081− clipboard_type: ClipboardType,
4082−) -> anyhow::Result<()> {
4083− let count = cx.count();
4084− let (view, doc) = current!(cx.editor);
4085−
4086− match cx.editor.clipboard_provider.get_contents(clipboard_type) {
4087− Ok(contents) => {
4088− let selection = doc.selection(view.id);
4089− let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
4090− (
4091− range.from(),
4092− range.to(),
4093− Some(contents.repeat(count).as_str().into()),
4094− )
4095− });
4096−
4097− doc.apply(&transaction, view.id);
4098− doc.append_changes_to_history(view);
4099− }
4100− Err(e) => return Err(e.context("Couldn't get system clipboard contents")),
4101− }
4102−
4103− exit_select_mode(cx);
4104− Ok(())
41053994}
41063995
41073996fn replace_selections_with_clipboard(cx: &mut Context) {
4108− let _ = replace_selections_with_clipboard_impl(cx, ClipboardType::Clipboard);
3997+ replace_with_yanked_impl(cx.editor, '*', cx.count());
41093998}
41103999
41114000fn replace_selections_with_primary_clipboard(cx: &mut Context) {
4112− let _ = replace_selections_with_clipboard_impl(cx, ClipboardType::Selection);
4001+ replace_with_yanked_impl(cx.editor, '+', cx.count());
41134002}
41144003
4115−fn paste(cx: &mut Context, pos: Paste) {
4116− let count = cx.count();
4117− let reg_name = cx.register.unwrap_or('"');
4118−
4119− let Some(values) = cx.editor.registers.read(reg_name, cx.editor) else { return };
4004+fn paste(editor: &mut Editor, register: char, pos: Paste, count: usize) {
4005+ let Some(values) = editor.registers.read(register, editor) else { return };
41204006 let values: Vec<_> = values.map(|value| value.to_string()).collect();
41214007
4122− let (view, doc) = current!(cx.editor);
4123− paste_impl(&values, doc, view, pos, count, cx.editor.mode);
4008+ let (view, doc) = current!(editor);
4009+ paste_impl(&values, doc, view, pos, count, editor.mode);
41244010}
41254011
41264012fn paste_after(cx: &mut Context) {
4127− paste(cx, Paste::After)
4013+ paste(
4014+ cx.editor,
4015+ cx.register.unwrap_or('"'),
4016+ Paste::After,
4017+ cx.count(),
4018+ );
41284019}
41294020
41304021fn paste_before(cx: &mut Context) {
4131− paste(cx, Paste::Before)
4022+ paste(
4023+ cx.editor,
4024+ cx.register.unwrap_or('"'),
4025+ Paste::Before,
4026+ cx.count(),
4027+ );
41324028}
41334029
41344030fn get_lines(doc: &Document, view_id: ViewId) -> Vec<usize> {
@@ -4885,7 +4781,12 @@ fn insert_register(cx: &mut Context) {
48854781 if let Some(ch) = event.char() {
48864782 cx.editor.autoinfo = None;
48874783 cx.register = Some(ch);
4888− paste(cx, Paste::Cursor);
4784+ paste(
4785+ cx.editor,
4786+ cx.register.unwrap_or('"'),
4787+ Paste::Cursor,
4788+ cx.count(),
4789+ );
48894790 }
48904791 })
48914792}
helix-term/src/commands/typed.rs+21−34
@@ -904,7 +904,8 @@ fn yank_main_selection_to_clipboard(
904904 return Ok(());
905905 }
906906
907− yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Clipboard)
907+ yank_primary_selection_impl(cx.editor, '*');
908+ Ok(())
908909}
909910
910911fn yank_joined(
@@ -938,7 +939,8 @@ fn yank_joined_to_clipboard(
938939 let doc = doc!(cx.editor);
939940 let default_sep = Cow::Borrowed(doc.line_ending.as_str());
940941 let separator = args.first().unwrap_or(&default_sep);
941− yank_joined_to_clipboard_impl(cx.editor, separator, ClipboardType::Clipboard)
942+ yank_joined_impl(cx.editor, separator, '*');
943+ Ok(())
942944}
943945
944946fn yank_main_selection_to_primary_clipboard(
@@ -950,7 +952,8 @@ fn yank_main_selection_to_primary_clipboard(
950952 return Ok(());
951953 }
952954
953− yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Selection)
955+ yank_primary_selection_impl(cx.editor, '+');
956+ Ok(())
954957}
955958
956959fn yank_joined_to_primary_clipboard(
@@ -965,7 +968,8 @@ fn yank_joined_to_primary_clipboard(
965968 let doc = doc!(cx.editor);
966969 let default_sep = Cow::Borrowed(doc.line_ending.as_str());
967970 let separator = args.first().unwrap_or(&default_sep);
968− yank_joined_to_clipboard_impl(cx.editor, separator, ClipboardType::Selection)
971+ yank_joined_impl(cx.editor, separator, '+');
972+ Ok(())
969973}
970974
971975fn paste_clipboard_after(
@@ -977,7 +981,8 @@ fn paste_clipboard_after(
977981 return Ok(());
978982 }
979983
980− paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard, 1)
984+ paste(cx.editor, '*', Paste::After, 1);
985+ Ok(())
981986}
982987
983988fn paste_clipboard_before(
@@ -989,7 +994,8 @@ fn paste_clipboard_before(
989994 return Ok(());
990995 }
991996
992− paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Clipboard, 1)
997+ paste(cx.editor, '*', Paste::Before, 1);
998+ Ok(())
993999}
9941000
9951001fn paste_primary_clipboard_after(
@@ -1001,7 +1007,8 @@ fn paste_primary_clipboard_after(
10011007 return Ok(());
10021008 }
10031009
1004− paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection, 1)
1010+ paste(cx.editor, '+', Paste::After, 1);
1011+ Ok(())
10051012}
10061013
10071014fn paste_primary_clipboard_before(
@@ -1013,30 +1020,8 @@ fn paste_primary_clipboard_before(
10131020 return Ok(());
10141021 }
10151022
1016− paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Selection, 1)
1017−}
1018−
1019−fn replace_selections_with_clipboard_impl(
1020− cx: &mut compositor::Context,
1021− clipboard_type: ClipboardType,
1022−) -> anyhow::Result<()> {
1023− let scrolloff = cx.editor.config().scrolloff;
1024− let (view, doc) = current!(cx.editor);
1025−
1026− match cx.editor.clipboard_provider.get_contents(clipboard_type) {
1027− Ok(contents) => {
1028− let selection = doc.selection(view.id);
1029− let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
1030− (range.from(), range.to(), Some(contents.as_str().into()))
1031− });
1032−
1033− doc.apply(&transaction, view.id);
1034− doc.append_changes_to_history(view);
1035− view.ensure_cursor_in_view(doc, scrolloff);
1036− Ok(())
1037− }
1038− Err(e) => Err(e.context("Couldn't get system clipboard contents")),
1039− }
1023+ paste(cx.editor, '+', Paste::Before, 1);
1024+ Ok(())
10401025}
10411026
10421027fn replace_selections_with_clipboard(
@@ -1048,7 +1033,8 @@ fn replace_selections_with_clipboard(
10481033 return Ok(());
10491034 }
10501035
1051− replace_selections_with_clipboard_impl(cx, ClipboardType::Clipboard)
1036+ replace_with_yanked_impl(cx.editor, '*', 1);
1037+ Ok(())
10521038}
10531039
10541040fn replace_selections_with_primary_clipboard(
@@ -1060,7 +1046,8 @@ fn replace_selections_with_primary_clipboard(
10601046 return Ok(());
10611047 }
10621048
1063− replace_selections_with_clipboard_impl(cx, ClipboardType::Selection)
1049+ replace_with_yanked_impl(cx.editor, '+', 1);
1050+ Ok(())
10641051}
10651052
10661053fn show_clipboard_provider(
@@ -1073,7 +1060,7 @@ fn show_clipboard_provider(
10731060 }
10741061
10751062 cx.editor
1076− .set_status(cx.editor.clipboard_provider.name().to_string());
1063+ .set_status(cx.editor.registers.clipboard_provider_name().to_string());
10771064 Ok(())
10781065}
10791066
helix-view/src/editor.rs−4
@@ -1,6 +1,5 @@
11use crate::{
22 align_view,
3− clipboard::{get_clipboard_provider, ClipboardProvider},
43 document::{DocumentSavedEventFuture, DocumentSavedEventResult, Mode, SavePoint},
54 graphics::{CursorKind, Rect},
65 info::Info,
@@ -875,8 +874,6 @@ pub struct Editor {
875874 pub debugger_events: SelectAll<UnboundedReceiverStream<dap::Payload>>,
876875 pub breakpoints: HashMap<PathBuf, Vec<Breakpoint>>,
877876
878− pub clipboard_provider: Box<dyn ClipboardProvider>,
879−
880877 pub syn_loader: Arc<syntax::Loader>,
881878 pub theme_loader: Arc<theme::Loader>,
882879 /// last_theme is used for theme previews. We store the current theme here,
@@ -1023,7 +1020,6 @@ impl Editor {
10231020 last_theme: None,
10241021 last_selection: None,
10251022 registers: Registers::default(),
1026− clipboard_provider: get_clipboard_provider(),
10271023 status_msg: None,
10281024 autoinfo: None,
10291025 idle_timer: Box::pin(sleep(conf.idle_timeout)),
helix-view/src/register.rs+4
@@ -215,6 +215,10 @@ impl Registers {
215215 )
216216 }
217217 }
218+
219+ pub fn clipboard_provider_name(&self) -> Cow<str> {
220+ self.clipboard_provider.name()
221+ }
218222}
219223
220224fn read_from_clipboard<'a>(