summaryrefslogtreecommitdiffstats
path: root/src/readline.rs
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2021-11-12 16:34:49 -0500
committerJesse Luehrs <doy@tozt.net>2021-11-12 16:34:49 -0500
commit5b303aa3a8a1185ccd8ea6059436a8273731275a (patch)
tree923e00aaf4698420d2efcb0fb3f6a6cb960ee6c2 /src/readline.rs
parentcab27fc4ead3becc39185443dfa1f2fb51291fa4 (diff)
downloadnbsh-5b303aa3a8a1185ccd8ea6059436a8273731275a.tar.gz
nbsh-5b303aa3a8a1185ccd8ea6059436a8273731275a.zip
implement moving the readline cursor
Diffstat (limited to 'src/readline.rs')
-rw-r--r--src/readline.rs74
1 files changed, 67 insertions, 7 deletions
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<crate::action::Action>,
}
@@ -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::<String>()
+ .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)
}
}