New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add bracketed paste #3233
Add bracketed paste #3233
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3369,13 +3369,7 @@ enum Paste { | |
Cursor, | ||
} | ||
|
||
fn paste_impl( | ||
values: &[String], | ||
doc: &mut Document, | ||
view: &View, | ||
action: Paste, | ||
count: usize, | ||
) -> Option<Transaction> { | ||
fn paste_impl(values: &[String], doc: &mut Document, view: &View, action: Paste, count: usize) { | ||
let repeat = std::iter::repeat( | ||
values | ||
.last() | ||
|
@@ -3418,8 +3412,17 @@ fn paste_impl( | |
}; | ||
(pos, pos, values.next()) | ||
}); | ||
doc.apply(&transaction, view.id); | ||
} | ||
|
||
Some(transaction) | ||
pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) { | ||
let count = cx.count(); | ||
let (view, doc) = current!(cx.editor); | ||
let paste = match doc.mode { | ||
Mode::Insert | Mode::Select => Paste::Cursor, | ||
Mode::Normal => Paste::Before, | ||
}; | ||
paste_impl(&[contents], doc, view, paste, count); | ||
} | ||
|
||
fn paste_clipboard_impl( | ||
|
@@ -3429,18 +3432,11 @@ fn paste_clipboard_impl( | |
count: usize, | ||
) -> anyhow::Result<()> { | ||
let (view, doc) = current!(editor); | ||
|
||
match editor | ||
.clipboard_provider | ||
.get_contents(clipboard_type) | ||
.map(|contents| paste_impl(&[contents], doc, view, action, count)) | ||
{ | ||
Ok(Some(transaction)) => { | ||
doc.apply(&transaction, view.id); | ||
doc.append_changes_to_history(view.id); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't needed here as it's done in editor's event handling. |
||
match editor.clipboard_provider.get_contents(clipboard_type) { | ||
Ok(contents) => { | ||
paste_impl(&[contents], doc, view, action, count); | ||
Ok(()) | ||
} | ||
Ok(None) => Ok(()), | ||
Err(e) => Err(e.context("Couldn't get system clipboard contents")), | ||
} | ||
} | ||
|
@@ -3553,11 +3549,8 @@ fn paste(cx: &mut Context, pos: Paste) { | |
let (view, doc) = current!(cx.editor); | ||
let registers = &mut cx.editor.registers; | ||
|
||
if let Some(transaction) = registers | ||
.read(reg_name) | ||
.and_then(|values| paste_impl(values, doc, view, pos, count)) | ||
{ | ||
doc.apply(&transaction, view.id); | ||
if let Some(values) = registers.read(reg_name) { | ||
paste_impl(values, doc, view, pos, count); | ||
} | ||
} | ||
|
||
|
@@ -4849,7 +4842,7 @@ fn replay_macro(cx: &mut Context) { | |
cx.callback = Some(Box::new(move |compositor, cx| { | ||
for _ in 0..count { | ||
for &key in keys.iter() { | ||
compositor.handle_event(compositor::Event::Key(key), cx); | ||
compositor.handle_event(&compositor::Event::Key(key), cx); | ||
} | ||
} | ||
// The macro under replay is cleared at the end of the callback, not in the | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -936,7 +936,7 @@ impl EditorView { | |
impl EditorView { | ||
fn handle_mouse_event( | ||
&mut self, | ||
event: MouseEvent, | ||
event: &MouseEvent, | ||
cxt: &mut commands::Context, | ||
) -> EventResult { | ||
let config = cxt.editor.config(); | ||
|
@@ -946,7 +946,7 @@ impl EditorView { | |
column, | ||
modifiers, | ||
.. | ||
} = event; | ||
} = *event; | ||
|
||
let pos_and_view = |editor: &Editor, row, column| { | ||
editor.tree.views().find_map(|(view, _focus)| { | ||
|
@@ -1115,7 +1115,7 @@ impl EditorView { | |
impl Component for EditorView { | ||
fn handle_event( | ||
&mut self, | ||
event: Event, | ||
event: &Event, | ||
context: &mut crate::compositor::Context, | ||
) -> EventResult { | ||
let mut cx = commands::Context { | ||
|
@@ -1128,6 +1128,23 @@ impl Component for EditorView { | |
}; | ||
|
||
match event { | ||
Event::Paste(contents) => { | ||
cx.count = cx.editor.count; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I felt like it made more sense to use a pending count here, though I could also see leaving it for an upcoming command. |
||
commands::paste_bracketed_value(&mut cx, contents.clone()); | ||
cx.editor.count = None; | ||
|
||
let config = cx.editor.config(); | ||
let (view, doc) = current!(cx.editor); | ||
view.ensure_cursor_in_view(doc, config.scrolloff); | ||
|
||
// Store a history state if not in insert mode. Otherwise wait till we exit insert | ||
// to include any edits to the paste in the history state. | ||
if doc.mode() != Mode::Insert { | ||
doc.append_changes_to_history(view.id); | ||
} | ||
|
||
EventResult::Consumed(None) | ||
} | ||
Event::Resize(_width, _height) => { | ||
// Ignore this event, we handle resizing just before rendering to screen. | ||
// Handling it here but not re-rendering will cause flashing | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,12 +6,13 @@ use std::fmt; | |
|
||
pub use crate::keyboard::{KeyCode, KeyModifiers}; | ||
|
||
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because the paste data is on the heap, we have to lose this Copy. That's why there's all this introduction of references through the rest of the PR. |
||
#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash)] | ||
pub enum Event { | ||
FocusGained, | ||
FocusLost, | ||
Key(KeyEvent), | ||
Mouse(MouseEvent), | ||
Paste(String), | ||
Resize(u16, u16), | ||
} | ||
|
||
|
@@ -276,9 +277,7 @@ impl From<crossterm::event::Event> for Event { | |
crossterm::event::Event::Resize(w, h) => Self::Resize(w, h), | ||
crossterm::event::Event::FocusGained => Self::FocusGained, | ||
crossterm::event::Event::FocusLost => Self::FocusLost, | ||
crossterm::event::Event::Paste(_) => { | ||
unreachable!("crossterm shouldn't emit Paste events without them being enabled") | ||
} | ||
crossterm::event::Event::Paste(s) => Self::Paste(s), | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't function as an actual command as I didn't see a good way to pass the contents through the Context. I think it's nicer to have it as a standalone function, but maybe I'm missing a way to make it work more like a regular command?
Because it's not a command, it doesn't set editor.last_insert and won't be repeated with
.
. Since you can spam your paste key as easily as.
, I didn't think that was a big deal.