Compare commits
1 commit
main
...
input-mode
Author | SHA1 | Date | |
---|---|---|---|
b909cd4559 |
2 changed files with 43 additions and 1 deletions
43
src/input.rs
43
src/input.rs
|
@ -9,14 +9,26 @@ use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
||||||
// TODO: add punctuation.
|
// TODO: add punctuation.
|
||||||
const SEPARATORS: [char; 3] = [' ', '\t', '\n'];
|
const SEPARATORS: [char; 3] = [' ', '\t', '\n'];
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum InputMode {
|
||||||
|
/// Insert mode. For inserting new text.
|
||||||
|
Insert,
|
||||||
|
|
||||||
|
/// Normal mode. For navigation and manipulation of text. Use Escape to come back to Normal
|
||||||
|
/// mode from any other mode.
|
||||||
|
Normal,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InputEvent {
|
pub enum InputEvent {
|
||||||
None,
|
None,
|
||||||
Exit,
|
Exit,
|
||||||
Text(String),
|
Text(String),
|
||||||
|
Mode(InputMode),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Input<W: Write> {
|
pub struct Input<W: Write> {
|
||||||
|
mode: InputMode,
|
||||||
stdout: W,
|
stdout: W,
|
||||||
string: Vec<char>,
|
string: Vec<char>,
|
||||||
clipboard: Vec<char>,
|
clipboard: Vec<char>,
|
||||||
|
@ -27,6 +39,7 @@ pub struct Input<W: Write> {
|
||||||
impl<W: Write> Input<W> {
|
impl<W: Write> Input<W> {
|
||||||
pub fn new(stdout: W) -> Input<W> {
|
pub fn new(stdout: W) -> Input<W> {
|
||||||
Input {
|
Input {
|
||||||
|
mode: InputMode::Insert,
|
||||||
stdout,
|
stdout,
|
||||||
string: Vec::new(),
|
string: Vec::new(),
|
||||||
clipboard: Vec::new(),
|
clipboard: Vec::new(),
|
||||||
|
@ -35,10 +48,15 @@ impl<W: Write> Input<W> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_mode(&mut self, mode: InputMode) {
|
||||||
|
self.mode = mode
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn from(stdout: W, input: &str) -> Input<W> {
|
fn from(stdout: W, input: &str) -> Input<W> {
|
||||||
let string: Vec<char> = input.chars().collect();
|
let string: Vec<char> = input.chars().collect();
|
||||||
Input {
|
Input {
|
||||||
|
mode: InputMode::Insert,
|
||||||
stdout,
|
stdout,
|
||||||
cursor: string.len(),
|
cursor: string.len(),
|
||||||
string,
|
string,
|
||||||
|
@ -73,8 +91,19 @@ impl<W: Write> Input<W> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_key(&mut self, code: KeyCode, modifiers: KeyModifiers) -> Result<InputEvent> {
|
pub fn handle_key(&mut self, code: KeyCode, modifiers: KeyModifiers) -> Result<InputEvent> {
|
||||||
|
// Escape always changes input mode back to Normal.
|
||||||
|
if let KeyCode::Esc = code {
|
||||||
|
return Ok(InputEvent::Mode(InputMode::Normal));
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.mode {
|
||||||
|
InputMode::Insert => self.handle_key_mode_input(code, modifiers),
|
||||||
|
_ => Ok(InputEvent::None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_key_mode_input(&mut self, code: KeyCode, modifiers: KeyModifiers) -> Result<InputEvent> {
|
||||||
match (code, modifiers) {
|
match (code, modifiers) {
|
||||||
(KeyCode::Esc, _) => return Ok(InputEvent::Exit),
|
|
||||||
(KeyCode::Char('d'), KeyModifiers::CONTROL) => return Ok(InputEvent::Exit),
|
(KeyCode::Char('d'), KeyModifiers::CONTROL) => return Ok(InputEvent::Exit),
|
||||||
(KeyCode::Char('l'), KeyModifiers::CONTROL) => {
|
(KeyCode::Char('l'), KeyModifiers::CONTROL) => {
|
||||||
self.stdout
|
self.stdout
|
||||||
|
@ -325,4 +354,16 @@ mod test {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mode_change_normal() -> Result<()> {
|
||||||
|
let mut stdout = Vec::new();
|
||||||
|
let mut input = Input::new(&mut stdout);
|
||||||
|
let event = input.handle_key(KeyCode::Esc, KeyModifiers::NONE)?;
|
||||||
|
match event {
|
||||||
|
InputEvent::Mode(mode) => assert_eq!(mode, InputMode::Normal),
|
||||||
|
evt => panic!("Wrong event: {evt:?}"),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,6 +149,7 @@ impl<'a> ChatTab<'a> {
|
||||||
Event::Key(event) => {
|
Event::Key(event) => {
|
||||||
match self.input.handle_key(event.code, event.modifiers) {
|
match self.input.handle_key(event.code, event.modifiers) {
|
||||||
Ok(InputEvent::Exit) => break,
|
Ok(InputEvent::Exit) => break,
|
||||||
|
Ok(InputEvent::Mode(mode)) => self.input.with_mode(mode),
|
||||||
Ok(InputEvent::Text(message)) => {
|
Ok(InputEvent::Text(message)) => {
|
||||||
/*
|
/*
|
||||||
let item = logger::Item::Message(logger::LogMessage {
|
let item = logger::Item::Message(logger::LogMessage {
|
||||||
|
|
Loading…
Reference in a new issue