Skip to content

Commit 8cb1d29

Browse files
committed
Add bracketed paste
1 parent 18909aa commit 8cb1d29

File tree

11 files changed

+86
-66
lines changed

11 files changed

+86
-66
lines changed

helix-term/src/application.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ use std::{
2929
use anyhow::{Context, Error};
3030

3131
use 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

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3368,13 +3368,7 @@ enum Paste {
33683368
Cursor,
33693369
}
33703370

3371-
fn paste_impl(
3372-
values: &[String],
3373-
doc: &mut Document,
3374-
view: &View,
3375-
action: Paste,
3376-
count: usize,
3377-
) -> Option<Transaction> {
3371+
fn paste_impl(values: &[String], doc: &mut Document, view: &View, action: Paste, count: usize) {
33783372
let repeat = std::iter::repeat(
33793373
values
33803374
.last()
@@ -3417,8 +3411,17 @@ fn paste_impl(
34173411
};
34183412
(pos, pos, values.next())
34193413
});
3414+
doc.apply(&transaction, view.id);
3415+
}
34203416

3421-
Some(transaction)
3417+
pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) {
3418+
let count = cx.count();
3419+
let (view, doc) = current!(cx.editor);
3420+
let paste = match doc.mode {
3421+
Mode::Insert | Mode::Select => Paste::Cursor,
3422+
Mode::Normal => Paste::Before,
3423+
};
3424+
paste_impl(&[contents], doc, view, paste, count);
34223425
}
34233426

34243427
fn paste_clipboard_impl(
@@ -3428,18 +3431,11 @@ fn paste_clipboard_impl(
34283431
count: usize,
34293432
) -> anyhow::Result<()> {
34303433
let (view, doc) = current!(editor);
3431-
3432-
match editor
3433-
.clipboard_provider
3434-
.get_contents(clipboard_type)
3435-
.map(|contents| paste_impl(&[contents], doc, view, action, count))
3436-
{
3437-
Ok(Some(transaction)) => {
3438-
doc.apply(&transaction, view.id);
3439-
doc.append_changes_to_history(view.id);
3434+
match editor.clipboard_provider.get_contents(clipboard_type) {
3435+
Ok(contents) => {
3436+
paste_impl(&[contents], doc, view, action, count);
34403437
Ok(())
34413438
}
3442-
Ok(None) => Ok(()),
34433439
Err(e) => Err(e.context("Couldn't get system clipboard contents")),
34443440
}
34453441
}
@@ -3552,11 +3548,8 @@ fn paste(cx: &mut Context, pos: Paste) {
35523548
let (view, doc) = current!(cx.editor);
35533549
let registers = &mut cx.editor.registers;
35543550

3555-
if let Some(transaction) = registers
3556-
.read(reg_name)
3557-
.and_then(|values| paste_impl(values, doc, view, pos, count))
3558-
{
3559-
doc.apply(&transaction, view.id);
3551+
if let Some(values) = registers.read(reg_name) {
3552+
paste_impl(values, doc, view, pos, count);
35603553
}
35613554
}
35623555

@@ -4848,7 +4841,7 @@ fn replay_macro(cx: &mut Context) {
48484841
cx.callback = Some(Box::new(move |compositor, cx| {
48494842
for _ in 0..count {
48504843
for &key in keys.iter() {
4851-
compositor.handle_event(compositor::Event::Key(key), cx);
4844+
compositor.handle_event(&compositor::Event::Key(key), cx);
48524845
}
48534846
}
48544847
// The macro under replay is cleared at the end of the callback, not in the

helix-term/src/compositor.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub struct Context<'a> {
2929

3030
pub 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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ impl Completion {
298298
}
299299

300300
impl 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

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -936,7 +936,7 @@ impl EditorView {
936936
impl 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)| {
@@ -1112,12 +1112,24 @@ impl EditorView {
11121112
_ => EventResult::Ignored(None),
11131113
}
11141114
}
1115+
1116+
fn complete_change(&mut self, cx: &mut commands::Context) {
1117+
let config = cx.editor.config();
1118+
let (view, doc) = current!(cx.editor);
1119+
view.ensure_cursor_in_view(doc, config.scrolloff);
1120+
1121+
// Store a history state if not in insert mode. This also takes care of
1122+
// committing changes when leaving insert mode.
1123+
if doc.mode() != Mode::Insert {
1124+
doc.append_changes_to_history(view.id);
1125+
}
1126+
}
11151127
}
11161128

11171129
impl Component for EditorView {
11181130
fn handle_event(
11191131
&mut self,
1120-
event: Event,
1132+
event: &Event,
11211133
context: &mut crate::compositor::Context,
11221134
) -> EventResult {
11231135
let mut cx = commands::Context {
@@ -1130,6 +1142,13 @@ impl Component for EditorView {
11301142
};
11311143

11321144
match event {
1145+
Event::Paste(contents) => {
1146+
cx.count = cx.editor.count;
1147+
commands::paste_bracketed_value(&mut cx, contents.clone());
1148+
cx.editor.count = None;
1149+
self.complete_change(&mut cx);
1150+
EventResult::Consumed(None)
1151+
}
11331152
Event::Resize(_width, _height) => {
11341153
// Ignore this event, we handle resizing just before rendering to screen.
11351154
// Handling it here but not re-rendering will cause flashing
@@ -1205,16 +1224,9 @@ impl Component for EditorView {
12051224
if cx.editor.should_close() {
12061225
return EventResult::Ignored(None);
12071226
}
1208-
let config = cx.editor.config();
1209-
let (view, doc) = current!(cx.editor);
1210-
view.ensure_cursor_in_view(doc, config.scrolloff);
1211-
1212-
// Store a history state if not in insert mode. This also takes care of
1213-
// committing changes when leaving insert mode.
1214-
if doc.mode() != Mode::Insert {
1215-
doc.append_changes_to_history(view.id);
1216-
}
1227+
self.complete_change(&mut cx);
12171228

1229+
let doc = doc!(cx.editor);
12181230
// mode transitions
12191231
match (mode, doc.mode()) {
12201232
(Mode::Normal, Mode::Insert) => {

helix-term/src/ui/menu.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,9 @@ impl<T: Item> Menu<T> {
225225
use super::PromptEvent as MenuEvent;
226226

227227
impl<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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ impl<T: Component> Popup<T> {
138138
}
139139

140140
impl<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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -466,9 +466,13 @@ impl Prompt {
466466
}
467467

468468
impl 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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ use std::fmt;
66

77
pub use crate::keyboard::{KeyCode, KeyModifiers};
88

9-
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
9+
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash)]
1010
pub 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
}

0 commit comments

Comments
 (0)