on master help sign in
Reimplement clipboard commands in terms of special regs
4555a6bMichael Davis
helix-term/src/commands.rs+64−163
@@ -32,7 +32,6 @@ use helix_core::{
32 RopeReader, RopeSlice, Selection, SmallVec, Tendril, Transaction,
32 RopeReader, RopeSlice, Selection, SmallVec, Tendril, Transaction,
33};
33};
34use helix_view::{
34use helix_view::{
35− clipboard::ClipboardType,
36 document::{FormatterError, Mode, SCRATCH_BUFFER_NAME},
35 document::{FormatterError, Mode, SCRATCH_BUFFER_NAME},
37 editor::{Action, CompleteAction},
36 editor::{Action, CompleteAction},
38 info::Info,
37 info::Info,
@@ -3759,7 +3758,12 @@ fn commit_undo_checkpoint(cx: &mut Context) {
3759// Yank / Paste
3758// Yank / Paste
3760
3759
3761fn yank(cx: &mut Context) {
3760fn yank(cx: &mut Context) {
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) {
3762− let (view, doc) = current!(cx.editor);
3766+ let (view, doc) = current!(editor);
3763 let text = doc.text().slice(..);
3767 let text = doc.text().slice(..);
3764
3768
3765 let values: Vec<String> = doc
3769 let values: Vec<String> = doc
@@ -3768,16 +3772,14 @@ fn yank(cx: &mut Context) {
3768 .map(Cow::into_owned)
3772 .map(Cow::into_owned)
3769 .collect();
3773 .collect();
3770 let selections = values.len();
3774 let selections = values.len();
3771− let register = cx.register.unwrap_or('"');
3772
3775
3773− match cx.editor.registers.write(register, values) {
3776+ match editor.registers.write(register, values) {
3774− Ok(_) => cx.editor.set_status(format!(
3777+ Ok(_) => editor.set_status(format!(
3775− "yanked {selections} selection(s) to register {register}",
3778+ "yanked {selections} selection{} to register {register}",
3779+ if selections == 1 { "" } else { "s" }
3776 )),
3780 )),
3777− Err(err) => cx.editor.set_error(err.to_string()),
3781+ Err(err) => editor.set_error(err.to_string()),
3778 }
3782 }
3779−
3780− exit_select_mode(cx);
3781}
3783}
3782
3784
3783fn yank_joined_impl(editor: &mut Editor, separator: &str, register: char) {
3785fn 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) {
3798
3800
3799 match editor.registers.write(register, vec![joined]) {
3801 match editor.registers.write(register, vec![joined]) {
3800 Ok(_) => editor.set_status(format!(
3802 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" }
3802 )),
3805 )),
3803 Err(err) => editor.set_error(err.to_string()),
3806 Err(err) => editor.set_error(err.to_string()),
3804 }
3807 }
3805}
3808}
3806
3809
3807fn yank_joined(cx: &mut Context) {
3810fn yank_joined(cx: &mut Context) {
3808− let line_ending = doc!(cx.editor).line_ending;
3811+ let separator = doc!(cx.editor).line_ending.as_str();
3809− let register = cx.register.unwrap_or('"');
3812+ yank_joined_impl(cx.editor, separator, cx.register.unwrap_or('"'));
3810− yank_joined_impl(cx.editor, line_ending.as_str(), register);
3811 exit_select_mode(cx);
3813 exit_select_mode(cx);
3812}
3814}
3813
3815
3814−fn yank_joined_to_clipboard_impl(
3816+fn yank_joined_to_clipboard(cx: &mut Context) {
3815− editor: &mut Editor,
3817+ let line_ending = doc!(cx.editor).line_ending;
3816− separator: &str,
3818+ yank_joined_impl(cx.editor, line_ending.as_str(), '*');
3817− clipboard_type: ClipboardType,
3819+ exit_select_mode(cx);
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(())
3849}
3820}
3850
3821
3851−fn yank_joined_to_clipboard(cx: &mut Context) {
3822+fn yank_joined_to_primary_clipboard(cx: &mut Context) {
3852 let line_ending = doc!(cx.editor).line_ending;
3823 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(), '+');
3855 exit_select_mode(cx);
3825 exit_select_mode(cx);
3856}
3826}
3857
3827
3858−fn yank_main_selection_to_clipboard_impl(
3859− editor: &mut Editor,
3828+fn yank_primary_selection_impl(editor: &mut Editor, register: char) {
3860− clipboard_type: ClipboardType,
3861−) -> anyhow::Result<()> {
3862 let (view, doc) = current!(editor);
3829 let (view, doc) = current!(editor);
3863 let text = doc.text().slice(..);
3830 let text = doc.text().slice(..);
3864
3831
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();
3871
3833
3872− if let Err(e) = editor
3834+ match editor.registers.write(register, vec![selection]) {
3873− .clipboard_provider
3835+ Ok(_) => editor.set_status(format!("yanked primary selection to register {register}",)),
3874− .set_contents(value.into_owned(), clipboard_type)
3836+ Err(err) => editor.set_error(err.to_string()),
3875− {
3876− bail!("Couldn't set system clipboard content: {}", e);
3877 }
3837 }
3878−
3879− editor.set_status(message_text);
3880− Ok(())
3881}
3838}
3882
3839
3883fn yank_main_selection_to_clipboard(cx: &mut Context) {
3840fn yank_main_selection_to_clipboard(cx: &mut Context) {
3884− let _ = yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Clipboard);
3841+ yank_primary_selection_impl(cx.editor, '*');
3885−}
3842+ exit_select_mode(cx);
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);
3891}
3843}
3892
3844
3893fn yank_main_selection_to_primary_clipboard(cx: &mut Context) {
3845fn 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, '+');
3895 exit_select_mode(cx);
3847 exit_select_mode(cx);
3896}
3848}
3897
3849
@@ -3991,68 +3943,34 @@ pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) {
3991 paste_impl(&[contents], doc, view, paste, count, cx.editor.mode);
3943 paste_impl(&[contents], doc, view, paste, count, cx.editor.mode);
3992}
3944}
3993
3945
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−
4010fn paste_clipboard_after(cx: &mut Context) {
3946fn paste_clipboard_after(cx: &mut Context) {
4011− let _ = paste_clipboard_impl(
4012− cx.editor,
4013− Paste::After,
3947+ paste(cx.editor, '*', Paste::After, cx.count());
4014− ClipboardType::Clipboard,
4015− cx.count(),
4016− );
4017}
3948}
4018
3949
4019fn paste_clipboard_before(cx: &mut Context) {
3950fn paste_clipboard_before(cx: &mut Context) {
4020− let _ = paste_clipboard_impl(
4021− cx.editor,
4022− Paste::Before,
3951+ paste(cx.editor, '*', Paste::Before, cx.count());
4023− ClipboardType::Clipboard,
4024− cx.count(),
4025− );
4026}
3952}
4027
3953
4028fn paste_primary_clipboard_after(cx: &mut Context) {
3954fn paste_primary_clipboard_after(cx: &mut Context) {
4029− let _ = paste_clipboard_impl(
4030− cx.editor,
4031− Paste::After,
3955+ paste(cx.editor, '+', Paste::After, cx.count());
4032− ClipboardType::Selection,
4033− cx.count(),
4034− );
4035}
3956}
4036
3957
4037fn paste_primary_clipboard_before(cx: &mut Context) {
3958fn paste_primary_clipboard_before(cx: &mut Context) {
4038− let _ = paste_clipboard_impl(
4039− cx.editor,
4040− Paste::Before,
3959+ paste(cx.editor, '+', Paste::Before, cx.count());
4041− ClipboardType::Selection,
4042− cx.count(),
4043− );
4044}
3960}
4045
3961
4046fn replace_with_yanked(cx: &mut Context) {
3962fn 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+}
4049
3966
3967+fn replace_with_yanked_impl(editor: &mut Editor, register: char, count: usize) {
4050− let Some(values) = cx.editor.registers
3968+ let Some(values) = editor.registers
4051− .read(reg_name, cx.editor)
3969+ .read(register, editor)
4052 .filter(|values| values.len() > 0) else { return };
3970 .filter(|values| values.len() > 0) else { return };
4053 let values: Vec<_> = values.map(|value| value.to_string()).collect();
3971 let values: Vec<_> = values.map(|value| value.to_string()).collect();
4054
3972
4055− let (view, doc) = current!(cx.editor);
3973+ let (view, doc) = current!(editor);
4056 let repeat = std::iter::repeat(
3974 let repeat = std::iter::repeat(
4057 values
3975 values
4058 .last()
3976 .last()
@@ -4073,62 +3991,40 @@ fn replace_with_yanked(cx: &mut Context) {
4073 });
3991 });
4074
3992
4075 doc.apply(&transaction, view.id);
3993 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(())
4105}
3994}
4106
3995
4107fn replace_selections_with_clipboard(cx: &mut Context) {
3996fn 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());
4109}
3998}
4110
3999
4111fn replace_selections_with_primary_clipboard(cx: &mut Context) {
4000fn 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());
4113}
4002}
4114
4003
4115−fn paste(cx: &mut Context, pos: Paste) {
4004+fn paste(editor: &mut Editor, register: char, pos: Paste, count: usize) {
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 };
4005+ let Some(values) = editor.registers.read(register, editor) else { return };
4120 let values: Vec<_> = values.map(|value| value.to_string()).collect();
4006 let values: Vec<_> = values.map(|value| value.to_string()).collect();
4121
4007
4122− let (view, doc) = current!(cx.editor);
4008+ let (view, doc) = current!(editor);
4123− paste_impl(&values, doc, view, pos, count, cx.editor.mode);
4009+ paste_impl(&values, doc, view, pos, count, editor.mode);
4124}
4010}
4125
4011
4126fn paste_after(cx: &mut Context) {
4012fn paste_after(cx: &mut Context) {
4013+ paste(
4014+ cx.editor,
4015+ cx.register.unwrap_or('"'),
4127− paste(cx, Paste::After)
4016+ Paste::After,
4017+ cx.count(),
4018+ );
4128}
4019}
4129
4020
4130fn paste_before(cx: &mut Context) {
4021fn paste_before(cx: &mut Context) {
4022+ paste(
4023+ cx.editor,
4024+ cx.register.unwrap_or('"'),
4131− paste(cx, Paste::Before)
4025+ Paste::Before,
4026+ cx.count(),
4027+ );
4132}
4028}
4133
4029
4134fn get_lines(doc: &Document, view_id: ViewId) -> Vec<usize> {
4030fn get_lines(doc: &Document, view_id: ViewId) -> Vec<usize> {
@@ -4885,7 +4781,12 @@ fn insert_register(cx: &mut Context) {
4885 if let Some(ch) = event.char() {
4781 if let Some(ch) = event.char() {
4886 cx.editor.autoinfo = None;
4782 cx.editor.autoinfo = None;
4887 cx.register = Some(ch);
4783 cx.register = Some(ch);
4784+ paste(
4785+ cx.editor,
4786+ cx.register.unwrap_or('"'),
4888− paste(cx, Paste::Cursor);
4787+ Paste::Cursor,
4788+ cx.count(),
4789+ );
4889 }
4790 }
4890 })
4791 })
4891}
4792}
helix-term/src/commands/typed.rs+21−34
@@ -904,7 +904,8 @@ fn yank_main_selection_to_clipboard(
904 return Ok(());
904 return Ok(());
905 }
905 }
906
906
907− yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Clipboard)
907+ yank_primary_selection_impl(cx.editor, '*');
908+ Ok(())
908}
909}
909
910
910fn yank_joined(
911fn yank_joined(
@@ -938,7 +939,8 @@ fn yank_joined_to_clipboard(
938 let doc = doc!(cx.editor);
939 let doc = doc!(cx.editor);
939 let default_sep = Cow::Borrowed(doc.line_ending.as_str());
940 let default_sep = Cow::Borrowed(doc.line_ending.as_str());
940 let separator = args.first().unwrap_or(&default_sep);
941 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(())
942}
944}
943
945
944fn yank_main_selection_to_primary_clipboard(
946fn yank_main_selection_to_primary_clipboard(
@@ -950,7 +952,8 @@ fn yank_main_selection_to_primary_clipboard(
950 return Ok(());
952 return Ok(());
951 }
953 }
952
954
953− yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Selection)
955+ yank_primary_selection_impl(cx.editor, '+');
956+ Ok(())
954}
957}
955
958
956fn yank_joined_to_primary_clipboard(
959fn yank_joined_to_primary_clipboard(
@@ -965,7 +968,8 @@ fn yank_joined_to_primary_clipboard(
965 let doc = doc!(cx.editor);
968 let doc = doc!(cx.editor);
966 let default_sep = Cow::Borrowed(doc.line_ending.as_str());
969 let default_sep = Cow::Borrowed(doc.line_ending.as_str());
967 let separator = args.first().unwrap_or(&default_sep);
970 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(())
969}
973}
970
974
971fn paste_clipboard_after(
975fn paste_clipboard_after(
@@ -977,7 +981,8 @@ fn paste_clipboard_after(
977 return Ok(());
981 return Ok(());
978 }
982 }
979
983
980− paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard, 1)
984+ paste(cx.editor, '*', Paste::After, 1);
985+ Ok(())
981}
986}
982
987
983fn paste_clipboard_before(
988fn paste_clipboard_before(
@@ -989,7 +994,8 @@ fn paste_clipboard_before(
989 return Ok(());
994 return Ok(());
990 }
995 }
991
996
992− paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Clipboard, 1)
997+ paste(cx.editor, '*', Paste::Before, 1);
998+ Ok(())
993}
999}
994
1000
995fn paste_primary_clipboard_after(
1001fn paste_primary_clipboard_after(
@@ -1001,7 +1007,8 @@ fn paste_primary_clipboard_after(
1001 return Ok(());
1007 return Ok(());
1002 }
1008 }
1003
1009
1004− paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection, 1)
1010+ paste(cx.editor, '+', Paste::After, 1);
1011+ Ok(())
1005}
1012}
1006
1013
1007fn paste_primary_clipboard_before(
1014fn paste_primary_clipboard_before(
@@ -1013,30 +1020,8 @@ fn paste_primary_clipboard_before(
1013 return Ok(());
1020 return Ok(());
1014 }
1021 }
1015
1022
1016− paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Selection, 1)
1023+ paste(cx.editor, '+', Paste::Before, 1);
1017−}
1024+ Ok(())
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− }
1040}
1025}
1041
1026
1042fn replace_selections_with_clipboard(
1027fn replace_selections_with_clipboard(
@@ -1048,7 +1033,8 @@ fn replace_selections_with_clipboard(
1048 return Ok(());
1033 return Ok(());
1049 }
1034 }
1050
1035
1051− replace_selections_with_clipboard_impl(cx, ClipboardType::Clipboard)
1036+ replace_with_yanked_impl(cx.editor, '*', 1);
1037+ Ok(())
1052}
1038}
1053
1039
1054fn replace_selections_with_primary_clipboard(
1040fn replace_selections_with_primary_clipboard(
@@ -1060,7 +1046,8 @@ fn replace_selections_with_primary_clipboard(
1060 return Ok(());
1046 return Ok(());
1061 }
1047 }
1062
1048
1063− replace_selections_with_clipboard_impl(cx, ClipboardType::Selection)
1049+ replace_with_yanked_impl(cx.editor, '+', 1);
1050+ Ok(())
1064}
1051}
1065
1052
1066fn show_clipboard_provider(
1053fn show_clipboard_provider(
@@ -1073,7 +1060,7 @@ fn show_clipboard_provider(
1073 }
1060 }
1074
1061
1075 cx.editor
1062 cx.editor
1076− .set_status(cx.editor.clipboard_provider.name().to_string());
1063+ .set_status(cx.editor.registers.clipboard_provider_name().to_string());
1077 Ok(())
1064 Ok(())
1078}
1065}
1079
1066
helix-view/src/editor.rs−4
@@ -1,6 +1,5 @@
1use crate::{
1use crate::{
2 align_view,
2 align_view,
3− clipboard::{get_clipboard_provider, ClipboardProvider},
4 document::{DocumentSavedEventFuture, DocumentSavedEventResult, Mode, SavePoint},
3 document::{DocumentSavedEventFuture, DocumentSavedEventResult, Mode, SavePoint},
5 graphics::{CursorKind, Rect},
4 graphics::{CursorKind, Rect},
6 info::Info,
5 info::Info,
@@ -875,8 +874,6 @@ pub struct Editor {
875 pub debugger_events: SelectAll<UnboundedReceiverStream<dap::Payload>>,
874 pub debugger_events: SelectAll<UnboundedReceiverStream<dap::Payload>>,
876 pub breakpoints: HashMap<PathBuf, Vec<Breakpoint>>,
875 pub breakpoints: HashMap<PathBuf, Vec<Breakpoint>>,
877
876
878− pub clipboard_provider: Box<dyn ClipboardProvider>,
879−
880 pub syn_loader: Arc<syntax::Loader>,
877 pub syn_loader: Arc<syntax::Loader>,
881 pub theme_loader: Arc<theme::Loader>,
878 pub theme_loader: Arc<theme::Loader>,
882 /// last_theme is used for theme previews. We store the current theme here,
879 /// last_theme is used for theme previews. We store the current theme here,
@@ -1023,7 +1020,6 @@ impl Editor {
1023 last_theme: None,
1020 last_theme: None,
1024 last_selection: None,
1021 last_selection: None,
1025 registers: Registers::default(),
1022 registers: Registers::default(),
1026− clipboard_provider: get_clipboard_provider(),
1027 status_msg: None,
1023 status_msg: None,
1028 autoinfo: None,
1024 autoinfo: None,
1029 idle_timer: Box::pin(sleep(conf.idle_timeout)),
1025 idle_timer: Box::pin(sleep(conf.idle_timeout)),
helix-view/src/register.rs+4
@@ -215,6 +215,10 @@ impl Registers {
215 )
215 )
216 }
216 }
217 }
217 }
218+
219+ pub fn clipboard_provider_name(&self) -> Cow<str> {
220+ self.clipboard_provider.name()
221+ }
218}
222}
219
223
220fn read_from_clipboard<'a>(
224fn read_from_clipboard<'a>(