1
0
зеркало из https://github.com/glebtv/tui-textarea.git synced 2026-09-03 14:26:17 +03:00

move Input backends support to respective modules in input/

Этот коммит содержится в:
rhysd
2023-10-25 19:35:21 +09:00
родитель 80e1db129a
Коммит a19562a96f
5 изменённых файлов: 325 добавлений и 325 удалений

Просмотреть файл

@@ -1,325 +0,0 @@
#[cfg(any(feature = "crossterm", feature = "tuirs-crossterm"))]
use crate::crossterm::event::{
Event as CrosstermEvent, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent,
MouseEventKind as CrosstermMouseEventKind,
};
#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
#[cfg(any(feature = "termion", feature = "tuirs-termion"))]
use termion::event::{Event as TermionEvent, Key as TermionKey, MouseEvent as TermionMouseEvent};
#[cfg(feature = "termwiz")]
use termwiz::input::{
InputEvent as TermwizInputEvent, KeyEvent as TermwizKeyEvent,
MouseButtons as TermwizMouseButtons, MouseEvent as TermwizMouseEvent, PixelMouseEvent,
};
/// Backend-agnostic key input kind.
///
/// This type is marked as `#[non_exhaustive]` since more keys may be supported in the future.
#[non_exhaustive]
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub enum Key {
/// Normal letter key input.
Char(char),
/// F1, F2, F3, ... keys.
F(u8),
Backspace,
Enter,
Left,
Right,
Up,
Down,
Tab,
Delete,
Home,
End,
PageUp,
PageDown,
Esc,
/// Virtual key to scroll down by mouse
MouseScrollDown,
/// Virtual key to scroll up by mouse
MouseScrollUp,
/// An invalid key input (this key is always ignored by [`TextArea`](crate::TextArea)).
Null,
}
/// Backend-agnostic key input type.
///
/// When `crossterm`, `termion`, `termwiz` features are enabled, converting respective key input types into this
/// `Input` type is defined.
/// ```no_run
/// use tui_textarea::{TextArea, Input, Key};
/// use crossterm::event::{Event, read};
///
/// let event = read().unwrap();
///
/// // `Input::from` can convert backend-native event into `Input`
/// let input = Input::from(event.clone());
/// // or `Into::into`
/// let input: Input = event.clone().into();
/// // Conversion from `KeyEvent` value is also available
/// if let Event::Key(key) = event {
/// let input = Input::from(key);
/// }
/// ```
///
/// Creating `Input` instance directly can cause backend-agnostic input as follows.
///
/// ```
/// use tui_textarea::{TextArea, Input, Key};
///
/// let mut textarea = TextArea::default();
///
/// // Input Ctrl+A
/// textarea.input(Input {
/// key: Key::Char('a'),
/// ctrl: true,
/// alt: false,
/// });
/// ```
#[derive(Debug, Clone)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub struct Input {
/// Typed key.
pub key: Key,
/// Ctrl modifier key. `true` means Ctrl key was pressed.
pub ctrl: bool,
/// Alt modifier key. `true` means Alt key was pressed.
pub alt: bool,
}
impl Default for Input {
/// The default input is [`Key::Null`] without pressing any modifier keys, which means invalid input.
fn default() -> Self {
Input {
key: Key::Null,
ctrl: false,
alt: false,
}
}
}
#[cfg(any(feature = "crossterm", feature = "tuirs-crossterm"))]
impl From<CrosstermEvent> for Input {
/// Convert [`crossterm::event::Event`] to [`Input`].
fn from(event: CrosstermEvent) -> Self {
match event {
CrosstermEvent::Key(key) if key.kind != KeyEventKind::Release => Self::from(key),
CrosstermEvent::Mouse(mouse) => Self::from(mouse),
_ => Self::default(),
}
}
}
#[cfg(any(feature = "crossterm", feature = "tuirs-crossterm"))]
impl From<KeyEvent> for Input {
/// Convert [`crossterm::event::KeyEvent`] to [`Input`].
fn from(key: KeyEvent) -> Self {
let ctrl = key.modifiers.contains(KeyModifiers::CONTROL);
let alt = key.modifiers.contains(KeyModifiers::ALT);
let key = match key.code {
KeyCode::Char(c) => Key::Char(c),
KeyCode::Backspace => Key::Backspace,
KeyCode::Enter => Key::Enter,
KeyCode::Left => Key::Left,
KeyCode::Right => Key::Right,
KeyCode::Up => Key::Up,
KeyCode::Down => Key::Down,
KeyCode::Tab => Key::Tab,
KeyCode::Delete => Key::Delete,
KeyCode::Home => Key::Home,
KeyCode::End => Key::End,
KeyCode::PageUp => Key::PageUp,
KeyCode::PageDown => Key::PageDown,
KeyCode::Esc => Key::Esc,
KeyCode::F(x) => Key::F(x),
_ => Key::Null,
};
Self { key, ctrl, alt }
}
}
#[cfg(any(feature = "crossterm", feature = "tuirs-crossterm"))]
impl From<MouseEvent> for Input {
/// Convert [`crossterm::event::MouseEvent`] to [`Input`].
fn from(mouse: MouseEvent) -> Self {
let key = match mouse.kind {
CrosstermMouseEventKind::ScrollDown => Key::MouseScrollDown,
CrosstermMouseEventKind::ScrollUp => Key::MouseScrollUp,
_ => return Self::default(),
};
let ctrl = mouse.modifiers.contains(KeyModifiers::CONTROL);
let alt = mouse.modifiers.contains(KeyModifiers::ALT);
Self { key, ctrl, alt }
}
}
#[cfg(any(feature = "termion", feature = "tuirs-termion"))]
impl From<TermionEvent> for Input {
/// Convert [`termion::event::Event`] to [`Input`].
fn from(event: TermionEvent) -> Self {
match event {
TermionEvent::Key(key) => Self::from(key),
TermionEvent::Mouse(mouse) => Self::from(mouse),
_ => Self::default(),
}
}
}
#[cfg(any(feature = "termion", feature = "tuirs-termion"))]
impl From<TermionKey> for Input {
/// Convert [`termion::event::Key`] to [`Input`].
fn from(key: TermionKey) -> Self {
use TermionKey::*;
let mut ctrl = false;
let mut alt = false;
let key = match key {
Char('\n' | '\r') => Key::Enter,
Char(c) => Key::Char(c),
Ctrl(c) => {
ctrl = true;
Key::Char(c)
}
Alt(c) => {
alt = true;
Key::Char(c)
}
Backspace => Key::Backspace,
Left => Key::Left,
Right => Key::Right,
Up => Key::Up,
Down => Key::Down,
Home => Key::Home,
End => Key::End,
PageUp => Key::PageUp,
PageDown => Key::PageDown,
BackTab => Key::Tab,
Delete => Key::Delete,
Esc => Key::Esc,
F(x) => Key::F(x),
_ => Key::Null,
};
Input { key, ctrl, alt }
}
}
#[cfg(any(feature = "termion", feature = "tuirs-termion"))]
impl From<TermionMouseEvent> for Input {
/// Convert [`termion::event::MouseEvent`] to [`Input`].
fn from(mouse: TermionMouseEvent) -> Self {
use termion::event::MouseButton;
let key = match mouse {
TermionMouseEvent::Press(MouseButton::WheelUp, ..) => Key::MouseScrollUp,
TermionMouseEvent::Press(MouseButton::WheelDown, ..) => Key::MouseScrollDown,
_ => return Self::default(),
};
Self {
key,
ctrl: false,
alt: false,
}
}
}
#[cfg(feature = "termwiz")]
impl From<TermwizInputEvent> for Input {
/// Convert [`termwiz::input::InputEvent`] to [`Input`].
fn from(input: TermwizInputEvent) -> Self {
match input {
TermwizInputEvent::Key(key) => Self::from(key),
TermwizInputEvent::Mouse(mouse) => Self::from(mouse),
TermwizInputEvent::PixelMouse(mouse) => Self::from(mouse),
_ => Self::default(),
}
}
}
#[cfg(feature = "termwiz")]
impl From<TermwizKeyEvent> for Input {
/// Convert [`termwiz::input::KeyEvent`] to [`Input`].
fn from(key: TermwizKeyEvent) -> Self {
use termwiz::input::{KeyCode, Modifiers};
let TermwizKeyEvent { key, modifiers } = key;
let key = match key {
KeyCode::Char(c) => Key::Char(c),
KeyCode::Backspace => Key::Backspace,
KeyCode::Tab => Key::Tab,
KeyCode::Enter => Key::Enter,
KeyCode::Escape => Key::Esc,
KeyCode::PageUp => Key::PageUp,
KeyCode::PageDown => Key::PageDown,
KeyCode::End => Key::End,
KeyCode::Home => Key::Home,
KeyCode::LeftArrow => Key::Left,
KeyCode::RightArrow => Key::Right,
KeyCode::UpArrow => Key::Up,
KeyCode::DownArrow => Key::Down,
KeyCode::Delete => Key::Delete,
KeyCode::Function(x) => Key::F(x),
_ => Key::Null,
};
let ctrl = modifiers.contains(Modifiers::CTRL);
let alt = modifiers.contains(Modifiers::ALT);
Self { key, ctrl, alt }
}
}
#[cfg(feature = "termwiz")]
impl From<TermwizMouseButtons> for Key {
/// Convert [`termwiz::input::MouseButtons`] to [`Key`].
fn from(buttons: TermwizMouseButtons) -> Self {
if buttons.contains(TermwizMouseButtons::VERT_WHEEL) {
if buttons.contains(TermwizMouseButtons::WHEEL_POSITIVE) {
Key::MouseScrollUp
} else {
Key::MouseScrollDown
}
} else {
Key::Null
}
}
}
#[cfg(feature = "termwiz")]
impl From<TermwizMouseEvent> for Input {
/// Convert [`termwiz::input::MouseEvent`] to [`Input`].
fn from(mouse: TermwizMouseEvent) -> Self {
use termwiz::input::Modifiers;
let TermwizMouseEvent {
mouse_buttons,
modifiers,
..
} = mouse;
let key = Key::from(mouse_buttons);
let ctrl = modifiers.contains(Modifiers::CTRL);
let alt = modifiers.contains(Modifiers::ALT);
Self { key, ctrl, alt }
}
}
#[cfg(feature = "termwiz")]
impl From<PixelMouseEvent> for Input {
/// Convert [`termwiz::input::PixelMouseEvent`] to [`Input`].
fn from(mouse: PixelMouseEvent) -> Self {
use termwiz::input::Modifiers;
let PixelMouseEvent {
mouse_buttons,
modifiers,
..
} = mouse;
let key = Key::from(mouse_buttons);
let ctrl = modifiers.contains(Modifiers::CTRL);
let alt = modifiers.contains(Modifiers::ALT);
Self { key, ctrl, alt }
}
}

56
src/input/crossterm.rs Обычный файл
Просмотреть файл

@@ -0,0 +1,56 @@
use super::{Input, Key};
use crate::crossterm::event::{
Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent, MouseEventKind,
};
impl From<Event> for Input {
/// Convert [`crossterm::event::Event`] to [`Input`].
fn from(event: Event) -> Self {
match event {
Event::Key(key) if key.kind != KeyEventKind::Release => Self::from(key),
Event::Mouse(mouse) => Self::from(mouse),
_ => Self::default(),
}
}
}
impl From<KeyEvent> for Input {
/// Convert [`crossterm::event::KeyEvent`] to [`Input`].
fn from(key: KeyEvent) -> Self {
let ctrl = key.modifiers.contains(KeyModifiers::CONTROL);
let alt = key.modifiers.contains(KeyModifiers::ALT);
let key = match key.code {
KeyCode::Char(c) => Key::Char(c),
KeyCode::Backspace => Key::Backspace,
KeyCode::Enter => Key::Enter,
KeyCode::Left => Key::Left,
KeyCode::Right => Key::Right,
KeyCode::Up => Key::Up,
KeyCode::Down => Key::Down,
KeyCode::Tab => Key::Tab,
KeyCode::Delete => Key::Delete,
KeyCode::Home => Key::Home,
KeyCode::End => Key::End,
KeyCode::PageUp => Key::PageUp,
KeyCode::PageDown => Key::PageDown,
KeyCode::Esc => Key::Esc,
KeyCode::F(x) => Key::F(x),
_ => Key::Null,
};
Self { key, ctrl, alt }
}
}
impl From<MouseEvent> for Input {
/// Convert [`crossterm::event::MouseEvent`] to [`Input`].
fn from(mouse: MouseEvent) -> Self {
let key = match mouse.kind {
MouseEventKind::ScrollDown => Key::MouseScrollDown,
MouseEventKind::ScrollUp => Key::MouseScrollUp,
_ => return Self::default(),
};
let ctrl = mouse.modifiers.contains(KeyModifiers::CONTROL);
let alt = mouse.modifiers.contains(KeyModifiers::ALT);
Self { key, ctrl, alt }
}
}

105
src/input/mod.rs Обычный файл
Просмотреть файл

@@ -0,0 +1,105 @@
#[cfg(any(feature = "crossterm", feature = "tuirs-crossterm"))]
mod crossterm;
#[cfg(any(feature = "termion", feature = "tuirs-termion"))]
mod termion;
#[cfg(feature = "termwiz")]
mod termwiz;
#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
/// Backend-agnostic key input kind.
///
/// This type is marked as `#[non_exhaustive]` since more keys may be supported in the future.
#[non_exhaustive]
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub enum Key {
/// Normal letter key input
Char(char),
/// F1, F2, F3, ... keys
F(u8),
/// Backspace key
Backspace,
/// Enter or return key
Enter,
/// Left arrow key
Left,
/// Right arrow key
Right,
/// Up arrow key
Up,
/// Down arrow key
Down,
/// Tab key
Tab,
/// Delete key
Delete,
/// Home key
Home,
/// End key
End,
/// Page up key
PageUp,
/// Page down key
PageDown,
/// Escape key
Esc,
/// Virtual key to scroll down by mouse
MouseScrollDown,
/// Virtual key to scroll up by mouse
MouseScrollUp,
/// An invalid key input (this key is always ignored by [`TextArea`](crate::TextArea))
Null,
}
impl Default for Key {
fn default() -> Self {
Key::Null
}
}
/// Backend-agnostic key input type.
///
/// When `crossterm`, `termion`, `termwiz` features are enabled, converting respective key input types into this
/// `Input` type is defined.
/// ```no_run
/// use tui_textarea::{TextArea, Input, Key};
/// use crossterm::event::{Event, read};
///
/// let event = read().unwrap();
///
/// // `Input::from` can convert backend-native event into `Input`
/// let input = Input::from(event.clone());
/// // or `Into::into`
/// let input: Input = event.clone().into();
/// // Conversion from `KeyEvent` value is also available
/// if let Event::Key(key) = event {
/// let input = Input::from(key);
/// }
/// ```
///
/// Creating `Input` instance directly can cause backend-agnostic input as follows.
///
/// ```
/// use tui_textarea::{TextArea, Input, Key};
///
/// let mut textarea = TextArea::default();
///
/// // Input Ctrl+A
/// textarea.input(Input {
/// key: Key::Char('a'),
/// ctrl: true,
/// alt: false,
/// });
/// ```
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub struct Input {
/// Typed key.
pub key: Key,
/// Ctrl modifier key. `true` means Ctrl key was pressed.
pub ctrl: bool,
/// Alt modifier key. `true` means Alt key was pressed.
pub alt: bool,
}

68
src/input/termion.rs Обычный файл
Просмотреть файл

@@ -0,0 +1,68 @@
use super::{Input, Key};
use termion::event::{Event, Key as KeyEvent, MouseEvent};
impl From<Event> for Input {
/// Convert [`termion::event::Event`] to [`Input`].
fn from(event: Event) -> Self {
match event {
Event::Key(key) => Self::from(key),
Event::Mouse(mouse) => Self::from(mouse),
_ => Self::default(),
}
}
}
impl From<KeyEvent> for Input {
/// Convert [`termion::event::Key`] to [`Input`].
fn from(key: KeyEvent) -> Self {
use KeyEvent::*;
let mut ctrl = false;
let mut alt = false;
let key = match key {
Char('\n' | '\r') => Key::Enter,
Char(c) => Key::Char(c),
Ctrl(c) => {
ctrl = true;
Key::Char(c)
}
Alt(c) => {
alt = true;
Key::Char(c)
}
Backspace => Key::Backspace,
Left => Key::Left,
Right => Key::Right,
Up => Key::Up,
Down => Key::Down,
Home => Key::Home,
End => Key::End,
PageUp => Key::PageUp,
PageDown => Key::PageDown,
BackTab => Key::Tab,
Delete => Key::Delete,
Esc => Key::Esc,
F(x) => Key::F(x),
_ => Key::Null,
};
Input { key, ctrl, alt }
}
}
impl From<MouseEvent> for Input {
/// Convert [`termion::event::MouseEvent`] to [`Input`].
fn from(mouse: MouseEvent) -> Self {
use termion::event::MouseButton;
let key = match mouse {
MouseEvent::Press(MouseButton::WheelUp, ..) => Key::MouseScrollUp,
MouseEvent::Press(MouseButton::WheelDown, ..) => Key::MouseScrollDown,
_ => return Self::default(),
};
Self {
key,
ctrl: false,
alt: false,
}
}
}

96
src/input/termwiz.rs Обычный файл
Просмотреть файл

@@ -0,0 +1,96 @@
use super::{Input, Key};
use termwiz::input::{InputEvent, KeyEvent, MouseButtons, MouseEvent, PixelMouseEvent};
impl From<InputEvent> for Input {
/// Convert [`termwiz::input::InputEvent`] to [`Input`].
fn from(input: InputEvent) -> Self {
match input {
InputEvent::Key(key) => Self::from(key),
InputEvent::Mouse(mouse) => Self::from(mouse),
InputEvent::PixelMouse(mouse) => Self::from(mouse),
_ => Self::default(),
}
}
}
impl From<KeyEvent> for Input {
/// Convert [`termwiz::input::KeyEvent`] to [`Input`].
fn from(key: KeyEvent) -> Self {
use termwiz::input::{KeyCode, Modifiers};
let KeyEvent { key, modifiers } = key;
let key = match key {
KeyCode::Char(c) => Key::Char(c),
KeyCode::Backspace => Key::Backspace,
KeyCode::Tab => Key::Tab,
KeyCode::Enter => Key::Enter,
KeyCode::Escape => Key::Esc,
KeyCode::PageUp => Key::PageUp,
KeyCode::PageDown => Key::PageDown,
KeyCode::End => Key::End,
KeyCode::Home => Key::Home,
KeyCode::LeftArrow => Key::Left,
KeyCode::RightArrow => Key::Right,
KeyCode::UpArrow => Key::Up,
KeyCode::DownArrow => Key::Down,
KeyCode::Delete => Key::Delete,
KeyCode::Function(x) => Key::F(x),
_ => Key::Null,
};
let ctrl = modifiers.contains(Modifiers::CTRL);
let alt = modifiers.contains(Modifiers::ALT);
Self { key, ctrl, alt }
}
}
impl From<MouseButtons> for Key {
/// Convert [`termwiz::input::MouseButtons`] to [`Key`].
fn from(buttons: MouseButtons) -> Self {
if buttons.contains(MouseButtons::VERT_WHEEL) {
if buttons.contains(MouseButtons::WHEEL_POSITIVE) {
Key::MouseScrollUp
} else {
Key::MouseScrollDown
}
} else {
Key::Null
}
}
}
impl From<MouseEvent> for Input {
/// Convert [`termwiz::input::MouseEvent`] to [`Input`].
fn from(mouse: MouseEvent) -> Self {
use termwiz::input::Modifiers;
let MouseEvent {
mouse_buttons,
modifiers,
..
} = mouse;
let key = Key::from(mouse_buttons);
let ctrl = modifiers.contains(Modifiers::CTRL);
let alt = modifiers.contains(Modifiers::ALT);
Self { key, ctrl, alt }
}
}
impl From<PixelMouseEvent> for Input {
/// Convert [`termwiz::input::PixelMouseEvent`] to [`Input`].
fn from(mouse: PixelMouseEvent) -> Self {
use termwiz::input::Modifiers;
let PixelMouseEvent {
mouse_buttons,
modifiers,
..
} = mouse;
let key = Key::from(mouse_buttons);
let ctrl = modifiers.contains(Modifiers::CTRL);
let alt = modifiers.contains(Modifiers::ALT);
Self { key, ctrl, alt }
}
}