diff --git a/src/line.rs b/src/line.rs index 3e0aa96..eb4d7c2 100644 --- a/src/line.rs +++ b/src/line.rs @@ -1,3 +1,5 @@ +use crate::log::*; + pub struct Line { /// the current contents of the line chars: Vec, @@ -17,11 +19,13 @@ impl Line { pub fn clear(&mut self) { self.cursor = 0; self.chars.clear(); + self.show_debug(); } pub fn pop(&mut self) -> String { let s: String = self.chars.iter().collect(); self.clear(); + self.show_debug(); s } @@ -32,6 +36,7 @@ impl Line { pub fn back(&mut self) -> bool { if self.cursor > 0 { self.cursor -= 1; + self.show_debug(); true } else { false @@ -39,18 +44,34 @@ impl Line { } pub fn backspace(&mut self) -> bool { - if self.cursor > 0 { - self.cursor -= 1; + if self.chars.len() > 0 { + if self.cursor > 0 { + self.cursor -= 1; + } self.chars.remove(self.cursor); + self.show_debug(); true } else { false } } + /// removes the elements left of the cursor, returning the count of removed elements + pub fn clear_left(&mut self) -> usize { + if self.cursor > 0 { + let n = self.chars.drain(..self.cursor).count(); + self.cursor = 0; + self.show_debug(); + n + } else { + 0 + } + } + pub fn forward(&mut self) -> bool { if self.cursor < self.chars.len() { self.cursor += 1; + self.show_debug(); true } else { false @@ -60,6 +81,7 @@ impl Line { pub fn insert(&mut self, c: char) { self.chars.insert(self.cursor, c); self.cursor += 1; + self.show_debug(); } pub fn tail(&self) -> String { @@ -71,4 +93,8 @@ impl Line { let chars = &self.chars[start..]; chars.iter().collect() } + + fn show_debug(&self) { + debug!(" {: <4} {: >5} {}", self.cursor, self.chars.len(), self.show()); + } } diff --git a/src/main.rs b/src/main.rs index bdf59a9..845c852 100644 --- a/src/main.rs +++ b/src/main.rs @@ -318,12 +318,14 @@ fn main() -> Result<()> { if event.code == key::BACKSPACE { if line.backspace() { - let text = format!("\x1b[2D"); unsafe { - Error::check(Console::WriteConsoleA(stdout, text.as_bytes(), None, None))?; + // move cursor back two spaces + Error::check(Console::WriteConsoleA(stdout, "\x1b[2D".as_bytes(), None, None))?; } let tail = format!("{} ", line.tail()); + let n = tail.chars().count(); unsafe { + // write the rest of the line plus a space to erase the last character Error::check(Console::WriteConsoleA( stdout, tail.as_bytes(), @@ -331,14 +333,26 @@ fn main() -> Result<()> { None, ))?; } - let text = format!("\x1b[1D"); - unsafe { - Error::check(Console::WriteConsoleA(stdout, text.as_bytes(), None, None))?; + + // after writing out the tail, rewind by the number of characters in + // the tail + if n > 1 { + let text = format!("\x1b[{}D", n-1); + unsafe { + Error::check(Console::WriteConsoleA(stdout, text.as_bytes(), None, None))?; + } + } else { + // honestly I can't remember how I figured this out + let text = format!(" \x1b[1D"); + unsafe { + Error::check(Console::WriteConsoleA(stdout, text.as_bytes(), None, None))?; + } } } continue; } + // CTRL-D to exit if event.ctrl && event.code == key::D { info!("» exit"); unsafe { @@ -347,6 +361,7 @@ fn main() -> Result<()> { return Ok(()); } + // CTRL-J to draw a cool little dot if event.ctrl && event.code == key::J { debug!("⎈ j: dot"); unsafe { @@ -357,6 +372,7 @@ fn main() -> Result<()> { continue; } + // CTRL-L to clear the screen if event.ctrl && event.code == key::L { info!("» clear"); let text = "\x1b[2J\x1b[0;0H"; @@ -370,6 +386,31 @@ fn main() -> Result<()> { continue; } + // CTRL-U to erase to the beginning of the line + if event.ctrl && event.code == key::U { + info!("» clear-left"); + let n = line.clear_left(); + if n > 0 { + // move left by the number of elements removed + let text = format!("\x1b[{}D", n); + unsafe { + Error::check(Console::WriteConsoleA(stdout, text.as_bytes(), None, None))?; + } + // draw the elements remaining, followed by a space for each removed + // element + let kept = line.show(); + let text = format!("{}{:width$}", kept, "", width = n); + unsafe { + Error::check(Console::WriteConsoleA(stdout, text.as_bytes(), None, None))?; + } + let text = format!("\x1b[{}D", n + kept.chars().count()); + unsafe { + Error::check(Console::WriteConsoleA(stdout, text.as_bytes(), None, None))?; + } + } + continue; + } + // TODO: something better here, this is crappy. I should be checking characters // based on their unicode categories, not this garbo if !event.char.is_control() {