feat: enable bracketed paste (#5)

This commit is contained in:
三咲雅 · Misaki Masa 2023-07-24 07:37:38 +08:00 committed by GitHub
parent 1f8c170359
commit a8a5ab7f8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 40 additions and 17 deletions

View File

@ -12,6 +12,7 @@ static mut TX: Option<UnboundedSender<Event>> = None;
pub enum Event { pub enum Event {
Quit, Quit,
Key(KeyEvent), Key(KeyEvent),
Paste(String),
Render(String), Render(String),
Resize(u16, u16), Resize(u16, u16),
Stop(bool, Option<oneshot::Sender<()>>), Stop(bool, Option<oneshot::Sender<()>>),

View File

@ -34,7 +34,7 @@ pub enum InputMode {
impl InputMode { impl InputMode {
#[inline] #[inline]
fn delta(&self) -> usize { (*self != InputMode::Insert) as usize } pub(super) fn delta(&self) -> usize { (*self != InputMode::Insert) as usize }
} }
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
@ -199,24 +199,26 @@ impl Input {
self.move_(snap.len() as isize) self.move_(snap.len() as isize)
} }
#[inline]
pub fn type_(&mut self, c: char) -> bool { pub fn type_(&mut self, c: char) -> bool {
let mut bits = [0; 4];
self.type_str(c.encode_utf8(&mut bits))
}
pub fn type_str(&mut self, s: &str) -> bool {
let snap = self.snap_mut(); let snap = self.snap_mut();
if snap.cursor < 1 { if snap.cursor < 1 {
snap.value.insert(0, c); snap.value.insert_str(0, s);
} else if snap.cursor == snap.count() {
snap.value.push(c);
} else { } else {
snap.value.insert(snap.idx(snap.cursor).unwrap(), c); snap.value.insert_str(snap.idx(snap.cursor).unwrap(), s);
} }
self.move_(1) self.move_(s.chars().count() as isize)
} }
pub fn backspace(&mut self) -> bool { pub fn backspace(&mut self) -> bool {
let snap = self.snap_mut(); let snap = self.snap_mut();
if snap.cursor < 1 { if snap.cursor < 1 {
return false; return false;
} else if snap.cursor == snap.count() {
snap.value.pop();
} else { } else {
snap.value.remove(snap.idx(snap.cursor - 1).unwrap()); snap.value.remove(snap.idx(snap.cursor - 1).unwrap());
} }

View File

@ -18,20 +18,25 @@ pub(super) struct InputSnap {
impl InputSnap { impl InputSnap {
pub(super) fn new(value: String) -> Self { pub(super) fn new(value: String) -> Self {
let cursor = value.chars().count(); let mut snap = Self {
let offset =
cursor.saturating_sub(Self::find_window(&value.chars().rev().collect::<String>(), 0).end);
Self {
value, value,
op: Default::default(), op: Default::default(),
start: Default::default(), start: Default::default(),
mode: Default::default(), mode: Default::default(),
offset, offset: usize::MAX,
cursor, cursor: usize::MAX,
};
snap.reset();
snap
} }
#[inline]
pub(super) fn reset(&mut self) {
self.cursor = self.cursor.min(self.value.chars().count().saturating_sub(self.mode.delta()));
self.offset =
self.offset.min(self.cursor.saturating_sub(Self::find_window(&self.rev(), 0).end));
} }
pub(super) fn insert(&mut self) -> bool { pub(super) fn insert(&mut self) -> bool {
@ -80,6 +85,9 @@ impl InputSnap {
&self.value[s.unwrap()..e.unwrap()] &self.value[s.unwrap()..e.unwrap()]
} }
#[inline]
pub(super) fn rev(&self) -> String { self.value.chars().rev().collect::<String>() }
#[inline] #[inline]
pub(super) fn range(&mut self, cursor: usize, include: bool) -> Option<Range<usize>> { pub(super) fn range(&mut self, cursor: usize, include: bool) -> Option<Range<usize>> {
self self

View File

@ -55,6 +55,7 @@ impl InputSnaps {
let value = mem::replace(&mut self.versions[self.idx].value, String::new()); let value = mem::replace(&mut self.versions[self.idx].value, String::new());
self.versions[self.idx] = self.current.clone(); self.versions[self.idx] = self.current.clone();
self.versions[self.idx].value = value; self.versions[self.idx].value = value;
self.versions[self.idx].reset();
} }
} }

View File

@ -3,7 +3,7 @@ use crossterm::event::KeyEvent;
use tokio::sync::oneshot::{self}; use tokio::sync::oneshot::{self};
use super::{root::Root, Ctx, Executor, Logs, Signals, Term}; use super::{root::Root, Ctx, Executor, Logs, Signals, Term};
use crate::{config::keymap::{Control, Key, KeymapLayer}, core::{files::FilesOp, Event}, emit, misc::absolute_path}; use crate::{config::keymap::{Control, Key, KeymapLayer}, core::{files::FilesOp, input::InputMode, Event}, emit, misc::absolute_path};
pub struct App { pub struct App {
cx: Ctx, cx: Ctx,
@ -23,6 +23,7 @@ impl App {
match event { match event {
Event::Quit => break, Event::Quit => break,
Event::Key(key) => app.dispatch_key(key), Event::Key(key) => app.dispatch_key(key),
Event::Paste(str) => app.dispatch_paste(str),
Event::Render(_) => app.dispatch_render(), Event::Render(_) => app.dispatch_render(),
Event::Resize(..) => app.dispatch_resize(), Event::Resize(..) => app.dispatch_resize(),
Event::Stop(state, tx) => app.dispatch_stop(state, tx), Event::Stop(state, tx) => app.dispatch_stop(state, tx),
@ -40,6 +41,15 @@ impl App {
} }
} }
fn dispatch_paste(&mut self, str: String) {
if self.cx.layer() == KeymapLayer::Input {
let input = &mut self.cx.input;
if input.mode() == InputMode::Insert && input.type_str(&str) {
emit!(Render);
}
}
}
fn dispatch_render(&mut self) { fn dispatch_render(&mut self) {
if let Some(term) = &mut self.term { if let Some(term) = &mut self.term {
let _ = term.draw(|f| { let _ = term.draw(|f| {

View File

@ -60,6 +60,7 @@ impl Signals {
Some(Ok(event)) = reader.next() => { Some(Ok(event)) = reader.next() => {
let event = match event { let event = match event {
CrosstermEvent::Key(key) => Event::Key(key), CrosstermEvent::Key(key) => Event::Key(key),
CrosstermEvent::Paste(str) => Event::Paste(str),
CrosstermEvent::Resize(cols, rows) => Event::Resize(cols, rows), CrosstermEvent::Resize(cols, rows) => Event::Resize(cols, rows),
_ => continue, _ => continue,
}; };