rustic_rs/commands/tui/widgets/
text_input.rs

1use super::{Draw, Event, Frame, KeyCode, KeyEvent, ProcessEvent, Rect, SizedWidget, Style};
2
3use crossterm::event::KeyModifiers;
4use tui_textarea::{CursorMove, TextArea};
5
6pub struct TextInput {
7    textarea: TextArea<'static>,
8    lines: u16,
9    changeable: bool,
10}
11
12pub enum TextInputResult {
13    Cancel,
14    Input(String),
15    None,
16}
17
18impl TextInput {
19    pub fn new(text: Option<&str>, initial: &str, lines: u16, changeable: bool) -> Self {
20        let mut textarea = TextArea::default();
21        textarea.set_style(Style::default());
22        if let Some(text) = text {
23            textarea.set_placeholder_text(text);
24        }
25        _ = textarea.insert_str(initial);
26        if !changeable {
27            textarea.move_cursor(CursorMove::Top);
28        }
29        Self {
30            textarea,
31            lines,
32            changeable,
33        }
34    }
35}
36
37impl SizedWidget for TextInput {
38    fn height(&self) -> Option<u16> {
39        Some(self.lines)
40    }
41}
42
43impl Draw for TextInput {
44    fn draw(&mut self, area: Rect, f: &mut Frame<'_>) {
45        f.render_widget(&self.textarea, area);
46    }
47}
48
49impl ProcessEvent for TextInput {
50    type Result = TextInputResult;
51    fn input(&mut self, event: Event) -> TextInputResult {
52        if let Event::Key(key) = event {
53            let KeyEvent {
54                code, modifiers, ..
55            } = key;
56            if self.changeable {
57                match (code, modifiers) {
58                    (KeyCode::Esc, _) => return TextInputResult::Cancel,
59                    (KeyCode::Enter, _) if self.lines == 1 => {
60                        return TextInputResult::Input(self.textarea.lines().join("\n"));
61                    }
62                    (KeyCode::Char('s'), KeyModifiers::CONTROL) => {
63                        return TextInputResult::Input(self.textarea.lines().join("\n"));
64                    }
65                    _ => {
66                        _ = self.textarea.input(event);
67                    }
68                }
69            } else {
70                match (code, modifiers) {
71                    (KeyCode::Esc | KeyCode::Enter | KeyCode::Char('q' | 'x'), _) => {
72                        return TextInputResult::Cancel;
73                    }
74                    (KeyCode::Home, _) => {
75                        self.textarea.move_cursor(CursorMove::Top);
76                    }
77                    (KeyCode::End, _) => {
78                        self.textarea.move_cursor(CursorMove::Bottom);
79                    }
80                    (KeyCode::PageDown | KeyCode::PageUp | KeyCode::Up | KeyCode::Down, _) => {
81                        _ = self.textarea.input(key);
82                    }
83                    _ => {}
84                }
85            }
86        }
87        TextInputResult::None
88    }
89}