on master help sign in
Add bracketed paste (#3233)
commitf38ede8631b083c1c74d31b7658ad162d31c3972 authorCharlie Groves <c@sevorg.org> dateMon 29 Aug 2022, 00:48 (4 years ago) parent51b6223
11 files changed+82−57
helix-term/src/application.rs+14−8 helix-term/src/commands.rs+17−24 helix-term/src/compositor.rs+3−3 helix-term/src/ui/completion.rs+1−1 helix-term/src/ui/editor.rs+20−3 helix-term/src/ui/menu.rs+2−2 helix-term/src/ui/overlay.rs+1−1 helix-term/src/ui/picker.rs+13−7 helix-term/src/ui/popup.rs+2−2 helix-term/src/ui/prompt.rs+6−2 helix-view/src/input.rs+3−4
helix-term/src/application.rs+14−8
@@ -29,7 +29,10 @@ use std::{
2929use anyhow::{Context, Error};
3030
3131use crossterm::{
32− event::{DisableMouseCapture, EnableMouseCapture, Event as CrosstermEvent},
32+ event::{
33+ DisableBracketedPaste, DisableMouseCapture, EnableBracketedPaste, EnableMouseCapture,
34+ Event as CrosstermEvent,
35+ },
3336 execute, terminal,
3437 tty::IsTty,
3538};
@@ -425,14 +428,13 @@ impl Application {
425428 scroll: None,
426429 };
427430 // Handle key events
428− let should_redraw = match event {
429− Ok(CrosstermEvent::Resize(width, height)) => {
431+ let should_redraw = match event.unwrap() {
432+ CrosstermEvent::Resize(width, height) => {
430433 self.compositor.resize(width, height);
431434 self.compositor
432− .handle_event(Event::Resize(width, height), &mut cx)
435+ .handle_event(&Event::Resize(width, height), &mut cx)
433436 }
434− Ok(event) => self.compositor.handle_event(event.into(), &mut cx),
435− Err(x) => panic!("{}", x),
437+ event => self.compositor.handle_event(&event.into(), &mut cx),
436438 };
437439
438440 if should_redraw && !self.editor.should_close() {
@@ -788,7 +790,7 @@ impl Application {
788790 async fn claim_term(&mut self) -> Result<(), Error> {
789791 terminal::enable_raw_mode()?;
790792 let mut stdout = stdout();
791− execute!(stdout, terminal::EnterAlternateScreen)?;
793+ execute!(stdout, terminal::EnterAlternateScreen, EnableBracketedPaste)?;
792794 execute!(stdout, terminal::Clear(terminal::ClearType::All))?;
793795 if self.config.load().editor.mouse {
794796 execute!(stdout, EnableMouseCapture)?;
@@ -821,7 +823,11 @@ impl Application {
821823 // probably not a good idea to `unwrap()` inside a panic handler.
822824 // So we just ignore the `Result`s.
823825 let _ = execute!(std::io::stdout(), DisableMouseCapture);
824− let _ = execute!(std::io::stdout(), terminal::LeaveAlternateScreen);
826+ let _ = execute!(
827+ std::io::stdout(),
828+ terminal::LeaveAlternateScreen,
829+ DisableBracketedPaste
830+ );
825831 let _ = terminal::disable_raw_mode();
826832 hook(info);
827833 }));
helix-term/src/commands.rs+17−24
@@ -3369,13 +3369,7 @@ enum Paste {
33693369 Cursor,
33703370}
33713371
3372−fn paste_impl(
3373− values: &[String],
3374− doc: &mut Document,
3375− view: &View,
3376− action: Paste,
3377− count: usize,
3378−) -> Option<Transaction> {
3372+fn paste_impl(values: &[String], doc: &mut Document, view: &View, action: Paste, count: usize) {
33793373 let repeat = std::iter::repeat(
33803374 values
33813375 .last()
@@ -3418,8 +3412,17 @@ fn paste_impl(
34183412 };
34193413 (pos, pos, values.next())
34203414 });
3415+ doc.apply(&transaction, view.id);
3416+}
34213417
3422− Some(transaction)
3418+pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) {
3419+ let count = cx.count();
3420+ let (view, doc) = current!(cx.editor);
3421+ let paste = match doc.mode {
3422+ Mode::Insert | Mode::Select => Paste::Cursor,
3423+ Mode::Normal => Paste::Before,
3424+ };
3425+ paste_impl(&[contents], doc, view, paste, count);
34233426}
34243427
34253428fn paste_clipboard_impl(
@@ -3429,18 +3432,11 @@ fn paste_clipboard_impl(
34293432 count: usize,
34303433) -> anyhow::Result<()> {
34313434 let (view, doc) = current!(editor);
3432−
3433− match editor
3434− .clipboard_provider
3435− .get_contents(clipboard_type)
3436− .map(|contents| paste_impl(&[contents], doc, view, action, count))
3437− {
3438− Ok(Some(transaction)) => {
3439− doc.apply(&transaction, view.id);
3440− doc.append_changes_to_history(view.id);
3435+ match editor.clipboard_provider.get_contents(clipboard_type) {
3436+ Ok(contents) => {
3437+ paste_impl(&[contents], doc, view, action, count);
34413438 Ok(())
34423439 }
3443− Ok(None) => Ok(()),
34443440 Err(e) => Err(e.context("Couldn't get system clipboard contents")),
34453441 }
34463442}
@@ -3553,11 +3549,8 @@ fn paste(cx: &mut Context, pos: Paste) {
35533549 let (view, doc) = current!(cx.editor);
35543550 let registers = &mut cx.editor.registers;
35553551
3556− if let Some(transaction) = registers
3557− .read(reg_name)
3558− .and_then(|values| paste_impl(values, doc, view, pos, count))
3559− {
3560− doc.apply(&transaction, view.id);
3552+ if let Some(values) = registers.read(reg_name) {
3553+ paste_impl(values, doc, view, pos, count);
35613554 }
35623555}
35633556
@@ -4849,7 +4842,7 @@ fn replay_macro(cx: &mut Context) {
48494842 cx.callback = Some(Box::new(move |compositor, cx| {
48504843 for _ in 0..count {
48514844 for &key in keys.iter() {
4852− compositor.handle_event(compositor::Event::Key(key), cx);
4845+ compositor.handle_event(&compositor::Event::Key(key), cx);
48534846 }
48544847 }
48554848 // The macro under replay is cleared at the end of the callback, not in the
helix-term/src/compositor.rs+3−3
@@ -29,7 +29,7 @@ pub struct Context<'a> {
2929
3030pub trait Component: Any + AnyComponent {
3131 /// Process input events, return true if handled.
32− fn handle_event(&mut self, _event: Event, _ctx: &mut Context) -> EventResult {
32+ fn handle_event(&mut self, _event: &Event, _ctx: &mut Context) -> EventResult {
3333 EventResult::Ignored(None)
3434 }
3535 // , args: ()
@@ -157,10 +157,10 @@ impl Compositor {
157157 Some(self.layers.remove(idx))
158158 }
159159
160− pub fn handle_event(&mut self, event: Event, cx: &mut Context) -> bool {
160+ pub fn handle_event(&mut self, event: &Event, cx: &mut Context) -> bool {
161161 // If it is a key event and a macro is being recorded, push the key event to the recording.
162162 if let (Event::Key(key), Some((_, keys))) = (event, &mut cx.editor.macro_recording) {
163− keys.push(key);
163+ keys.push(*key);
164164 }
165165
166166 let mut callbacks = Vec::new();
helix-term/src/ui/completion.rs+1−1
@@ -298,7 +298,7 @@ impl Completion {
298298}
299299
300300impl Component for Completion {
301− fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
301+ fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
302302 // let the Editor handle Esc instead
303303 if let Event::Key(KeyEvent {
304304 code: KeyCode::Esc, ..
helix-term/src/ui/editor.rs+20−3
@@ -936,7 +936,7 @@ impl EditorView {
936936impl EditorView {
937937 fn handle_mouse_event(
938938 &mut self,
939− event: MouseEvent,
939+ event: &MouseEvent,
940940 cxt: &mut commands::Context,
941941 ) -> EventResult {
942942 let config = cxt.editor.config();
@@ -946,7 +946,7 @@ impl EditorView {
946946 column,
947947 modifiers,
948948 ..
949− } = event;
949+ } = *event;
950950
951951 let pos_and_view = |editor: &Editor, row, column| {
952952 editor.tree.views().find_map(|(view, _focus)| {
@@ -1115,7 +1115,7 @@ impl EditorView {
11151115impl Component for EditorView {
11161116 fn handle_event(
11171117 &mut self,
1118− event: Event,
1118+ event: &Event,
11191119 context: &mut crate::compositor::Context,
11201120 ) -> EventResult {
11211121 let mut cx = commands::Context {
@@ -1128,6 +1128,23 @@ impl Component for EditorView {
11281128 };
11291129
11301130 match event {
1131+ Event::Paste(contents) => {
1132+ cx.count = cx.editor.count;
1133+ commands::paste_bracketed_value(&mut cx, contents.clone());
1134+ cx.editor.count = None;
1135+
1136+ let config = cx.editor.config();
1137+ let (view, doc) = current!(cx.editor);
1138+ view.ensure_cursor_in_view(doc, config.scrolloff);
1139+
1140+ // Store a history state if not in insert mode. Otherwise wait till we exit insert
1141+ // to include any edits to the paste in the history state.
1142+ if doc.mode() != Mode::Insert {
1143+ doc.append_changes_to_history(view.id);
1144+ }
1145+
1146+ EventResult::Consumed(None)
1147+ }
11311148 Event::Resize(_width, _height) => {
11321149 // Ignore this event, we handle resizing just before rendering to screen.
11331150 // Handling it here but not re-rendering will cause flashing
helix-term/src/ui/menu.rs+2−2
@@ -225,9 +225,9 @@ impl<T: Item> Menu<T> {
225225use super::PromptEvent as MenuEvent;
226226
227227impl<T: Item + 'static> Component for Menu<T> {
228− fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
228+ fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
229229 let event = match event {
230− Event::Key(event) => event,
230+ Event::Key(event) => *event,
231231 _ => return EventResult::Ignored(None),
232232 };
233233
helix-term/src/ui/overlay.rs+1−1
@@ -61,7 +61,7 @@ impl<T: Component + 'static> Component for Overlay<T> {
6161 Some((width, height))
6262 }
6363
64− fn handle_event(&mut self, event: Event, ctx: &mut Context) -> EventResult {
64+ fn handle_event(&mut self, event: &Event, ctx: &mut Context) -> EventResult {
6565 self.content.handle_event(event, ctx)
6666 }
6767
helix-term/src/ui/picker.rs+13−7
@@ -260,7 +260,7 @@ impl<T: Item + 'static> Component for FilePicker<T> {
260260 }
261261 }
262262
263− fn handle_event(&mut self, event: Event, ctx: &mut Context) -> EventResult {
263+ fn handle_event(&mut self, event: &Event, ctx: &mut Context) -> EventResult {
264264 // TODO: keybinds for scrolling preview
265265 self.picker.handle_event(event, ctx)
266266 }
@@ -476,6 +476,14 @@ impl<T: Item> Picker<T> {
476476 pub fn toggle_preview(&mut self) {
477477 self.show_preview = !self.show_preview;
478478 }
479+
480+ fn prompt_handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
481+ if let EventResult::Consumed(_) = self.prompt.handle_event(event, cx) {
482+ // TODO: recalculate only if pattern changed
483+ self.score();
484+ }
485+ EventResult::Consumed(None)
486+ }
479487}
480488
481489// process:
@@ -489,9 +497,10 @@ impl<T: Item + 'static> Component for Picker<T> {
489497 Some(viewport)
490498 }
491499
492− fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
500+ fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
493501 let key_event = match event {
494− Event::Key(event) => event,
502+ Event::Key(event) => *event,
503+ Event::Paste(..) => return self.prompt_handle_event(event, cx),
495504 Event::Resize(..) => return EventResult::Consumed(None),
496505 _ => return EventResult::Ignored(None),
497506 };
@@ -548,10 +557,7 @@ impl<T: Item + 'static> Component for Picker<T> {
548557 self.toggle_preview();
549558 }
550559 _ => {
551− if let EventResult::Consumed(_) = self.prompt.handle_event(event, cx) {
552− // TODO: recalculate only if pattern changed
553− self.score();
554− }
560+ self.prompt_handle_event(event, cx);
555561 }
556562 }
557563
helix-term/src/ui/popup.rs+2−2
@@ -138,9 +138,9 @@ impl<T: Component> Popup<T> {
138138}
139139
140140impl<T: Component> Component for Popup<T> {
141− fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
141+ fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
142142 let key = match event {
143− Event::Key(event) => event,
143+ Event::Key(event) => *event,
144144 Event::Resize(_, _) => {
145145 // TODO: calculate inner area, call component's handle_event with that area
146146 return EventResult::Ignored(None);
helix-term/src/ui/prompt.rs+6−2
@@ -466,9 +466,13 @@ impl Prompt {
466466}
467467
468468impl Component for Prompt {
469− fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
469+ fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
470470 let event = match event {
471− Event::Key(event) => event,
471+ Event::Paste(data) => {
472+ self.insert_str(data);
473+ return EventResult::Consumed(None);
474+ }
475+ Event::Key(event) => *event,
472476 Event::Resize(..) => return EventResult::Consumed(None),
473477 _ => return EventResult::Ignored(None),
474478 };
helix-view/src/input.rs+3−4
@@ -6,12 +6,13 @@ use std::fmt;
66
77pub use crate::keyboard::{KeyCode, KeyModifiers};
88
9−#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
9+#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash)]
1010pub enum Event {
1111 FocusGained,
1212 FocusLost,
1313 Key(KeyEvent),
1414 Mouse(MouseEvent),
15+ Paste(String),
1516 Resize(u16, u16),
1617}
1718
@@ -276,9 +277,7 @@ impl From<crossterm::event::Event> for Event {
276277 crossterm::event::Event::Resize(w, h) => Self::Resize(w, h),
277278 crossterm::event::Event::FocusGained => Self::FocusGained,
278279 crossterm::event::Event::FocusLost => Self::FocusLost,
279− crossterm::event::Event::Paste(_) => {
280− unreachable!("crossterm shouldn't emit Paste events without them being enabled")
281− }
280+ crossterm::event::Event::Paste(s) => Self::Paste(s),
282281 }
283282 }
284283}