tui_input/backend/
crossterm.rs1#[cfg(feature = "ratatui-crossterm")]
2use ratatui::crossterm;
3
4use super::layout::layout;
5use crate::{Input, InputRequest, StateChanged};
6use crossterm::event::{
7 Event as CrosstermEvent, KeyCode, KeyEvent, KeyEventKind, KeyModifiers,
8};
9use crossterm::{
10 cursor::MoveTo,
11 queue,
12 style::{Attribute as CAttribute, Print, SetAttribute},
13};
14use std::io::{Result, Write};
15
16pub fn to_input_request(evt: &CrosstermEvent) -> Option<InputRequest> {
18 use InputRequest::*;
19 use KeyCode::*;
20 match evt {
21 CrosstermEvent::Key(KeyEvent {
22 code,
23 modifiers,
24 kind,
25 state: _,
26 }) if *kind == KeyEventKind::Press || *kind == KeyEventKind::Repeat => {
27 match (*code, *modifiers) {
28 (Backspace, KeyModifiers::NONE) | (Char('h'), KeyModifiers::CONTROL) => {
29 Some(DeletePrevChar)
30 }
31 (Delete, KeyModifiers::NONE) => Some(DeleteNextChar),
32 (Tab, KeyModifiers::NONE) => None,
33 (Left, KeyModifiers::NONE) | (Char('b'), KeyModifiers::CONTROL) => {
34 Some(GoToPrevChar)
35 }
36 (Left, KeyModifiers::CONTROL) | (Char('b'), KeyModifiers::META) => {
37 Some(GoToPrevWord)
38 }
39 (Right, KeyModifiers::NONE) | (Char('f'), KeyModifiers::CONTROL) => {
40 Some(GoToNextChar)
41 }
42 (Right, KeyModifiers::CONTROL) | (Char('f'), KeyModifiers::META) => {
43 Some(GoToNextWord)
44 }
45 (Char('u'), KeyModifiers::CONTROL) => Some(DeleteLine),
46
47 (Char('w'), KeyModifiers::CONTROL)
48 | (Char('d'), KeyModifiers::META)
49 | (Backspace, KeyModifiers::META)
50 | (Backspace, KeyModifiers::ALT) => Some(DeletePrevWord),
51
52 (Delete, KeyModifiers::CONTROL) => Some(DeleteNextWord),
53 (Char('k'), KeyModifiers::CONTROL) => Some(DeleteTillEnd),
54 (Char('y'), KeyModifiers::CONTROL) => Some(Yank),
55 (Char('a'), KeyModifiers::CONTROL) | (Home, KeyModifiers::NONE) => {
56 Some(GoToStart)
57 }
58 (Char('e'), KeyModifiers::CONTROL) | (End, KeyModifiers::NONE) => {
59 Some(GoToEnd)
60 }
61 (Char(c), KeyModifiers::NONE) => Some(InsertChar(c)),
62 (Char(c), KeyModifiers::SHIFT) => Some(InsertChar(c)),
63 (Char(c), modifiers)
64 if modifiers == KeyModifiers::CONTROL | KeyModifiers::ALT =>
65 {
66 Some(InsertChar(c))
67 }
68 (_, _) => None,
69 }
70 }
71 _ => None,
72 }
73}
74
75pub fn write<W: Write>(
77 stdout: &mut W,
78 value: &str,
79 cursor: usize,
80 (x, y): (u16, u16),
81 width: u16,
82) -> Result<()> {
83 let l = layout(value, cursor, width);
84 let pad = l.padding();
85 queue!(
86 stdout,
87 MoveTo(x, y),
88 SetAttribute(CAttribute::NoReverse),
89 Print(l.before),
90 SetAttribute(CAttribute::Reverse),
91 Print(l.cursor),
92 SetAttribute(CAttribute::NoReverse),
93 Print(l.after),
94 Print(pad)
95 )
96}
97
98pub trait EventHandler {
100 fn handle_event(&mut self, evt: &CrosstermEvent) -> Option<StateChanged>;
102}
103
104impl EventHandler for Input {
105 fn handle_event(&mut self, evt: &CrosstermEvent) -> Option<StateChanged> {
107 to_input_request(evt).and_then(|req| self.handle(req))
108 }
109}
110
111#[cfg(test)]
112mod tests;