From 5b303aa3a8a1185ccd8ea6059436a8273731275a Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Fri, 12 Nov 2021 16:34:49 -0500 Subject: implement moving the readline cursor --- src/readline.rs | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 7 deletions(-) (limited to 'src/readline.rs') diff --git a/src/readline.rs b/src/readline.rs index 37fc054..8d7a87f 100644 --- a/src/readline.rs +++ b/src/readline.rs @@ -1,10 +1,11 @@ use textmode::Textmode as _; -use unicode_width::UnicodeWidthChar as _; +use unicode_width::{UnicodeWidthChar as _, UnicodeWidthStr as _}; pub struct Readline { size: (u16, u16), prompt: String, input_line: String, + pos: usize, action: async_std::channel::Sender, } @@ -16,6 +17,7 @@ impl Readline { size: (24, 80), prompt: "$ ".into(), input_line: "".into(), + pos: 0, action, } } @@ -39,6 +41,8 @@ impl Readline { } textmode::Key::Ctrl(b'u') => self.clear_backwards(), textmode::Key::Backspace => self.backspace(), + textmode::Key::Left => self.cursor_left(), + textmode::Key::Right => self.cursor_right(), _ => {} } self.action @@ -59,6 +63,7 @@ impl Readline { out.move_to(self.size.0 - 1, 0); out.write_str(&self.prompt); out.write_str(&self.input_line); + out.move_to(self.size.0 - 1, self.prompt_width() + self.pos_width()); Ok(()) } @@ -71,22 +76,77 @@ impl Readline { } fn add_input(&mut self, s: &str) { - self.input_line.push_str(s); + self.input_line.insert_str(self.byte_pos(), s); + self.pos += s.chars().count(); } fn backspace(&mut self) { - let mut width = 0; - while width == 0 { - width = - self.input_line.pop().map_or(1, |c| c.width().unwrap_or(0)); + while self.pos > 0 { + self.pos -= 1; + let width = + self.input_line.remove(self.byte_pos()).width().unwrap_or(0); + if width > 0 { + break; + } } } fn clear_input(&mut self) { self.input_line.clear(); + self.pos = 0; } fn clear_backwards(&mut self) { - self.input_line.clear(); + self.input_line = self.input_line.chars().skip(self.pos).collect(); + self.pos = 0; + } + + fn cursor_left(&mut self) { + if self.pos == 0 { + return; + } + self.pos -= 1; + while let Some(c) = self.input_line.chars().nth(self.pos) { + if c.width().unwrap_or(0) == 0 { + self.pos -= 1; + } else { + break; + } + } + } + + fn cursor_right(&mut self) { + if self.pos == self.input_line.chars().count() { + return; + } + self.pos += 1; + while let Some(c) = self.input_line.chars().nth(self.pos) { + if c.width().unwrap_or(0) == 0 { + self.pos += 1; + } else { + break; + } + } + } + + fn prompt_width(&self) -> u16 { + self.prompt.width().try_into().unwrap() + } + + fn pos_width(&self) -> u16 { + self.input_line + .chars() + .take(self.pos) + .collect::() + .width() + .try_into() + .unwrap() + } + + fn byte_pos(&self) -> usize { + self.input_line + .char_indices() + .nth(self.pos) + .map_or(self.input_line.len(), |(i, _)| i) } } -- cgit v1.2.3-54-g00ecf