working on moving left

this is the first actual line-editing and ansi escape handling w00t
parse-tree
Jordan Orelli 2 years ago
parent 755e16d045
commit b0138d6473

@ -9,6 +9,9 @@ pub enum Error {
#[error("i/o error: {0}")] #[error("i/o error: {0}")]
IOError(#[from] io::Error), IOError(#[from] io::Error),
#[error("input error: {0}")]
InputError(String),
} }
impl Error { impl Error {
@ -23,4 +26,8 @@ impl Error {
Err(Error::last_error()) Err(Error::last_error())
} }
} }
pub fn input_error<S: Into<String>>(msg: S) -> Self {
Error::InputError(msg.into())
}
} }

@ -145,8 +145,20 @@ impl Reader {
}) })
} }
pub fn next(&mut self) -> Result<Console::INPUT_RECORD> { pub fn next(&mut self) -> Result<Event> {
// All buffered items have been processed, ask the OS for new event records let rec = self.next_rec()?;
if rec.EventType as u32 == Console::KEY_EVENT {
unsafe {
let event = rec.Event.KeyEvent;
if event.wVirtualKeyCode == 0 && event.uChar.UnicodeChar == 27 {
return Ok(self.next_escape_sequence()?);
}
}
}
Ok(rec.into())
}
fn next_rec(&mut self) -> Result<Console::INPUT_RECORD> {
if self.buf_idx as u32 >= self.buf_len { if self.buf_idx as u32 >= self.buf_len {
unsafe { unsafe {
Error::check(Console::ReadConsoleInputA( Error::check(Console::ReadConsoleInputA(
@ -162,6 +174,49 @@ impl Reader {
self.buf_idx += 1; self.buf_idx += 1;
return Ok(rec); return Ok(rec);
} }
fn next_escape_sequence(&mut self) -> Result<Event> {
self.take_bracket()?;
match self.next_escape_char()? {
'D' => Ok(Event::Left),
e => Err(Error::input_error(format!("unexpected escape char: {}", e)).into()),
}
}
fn take_bracket(&mut self) -> Result<()> {
let rec = self.next_rec()?;
if rec.EventType as u32 != Console::KEY_EVENT {
Err(Error::input_error("failed to read escape sequence: not a key event").into())
} else {
unsafe {
let event = rec.Event.KeyEvent;
if event.wVirtualKeyCode == 0 && event.uChar.UnicodeChar == 91 {
Ok(())
} else {
Err(Error::input_error("failed to read escape sequence: not a [").into())
}
}
}
}
fn next_escape_char(&mut self) -> Result<char> {
let rec = self.next_rec()?;
if rec.EventType as u32 != Console::KEY_EVENT {
Err(
Error::input_error("failed to read char in escape sequence: not a key event")
.into(),
)
} else {
unsafe {
let n = rec.Event.KeyEvent.uChar.UnicodeChar as u32;
let c = char::from_u32(n);
c.ok_or_else(|| {
let msg = format!("escape key value is not a valid unicode character: {}", n);
Error::input_error(msg).into()
})
}
}
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -169,11 +224,9 @@ pub enum Event {
Focus(bool), Focus(bool),
Menu(u32), Menu(u32),
Key(key::Event), Key(key::Event),
Mouse{ Mouse { x: i16, y: i16 },
x: i16,
y: i16,
},
Size, Size,
Left,
} }
const ALT_KEYS: u32 = 0x0002 | 0x0001; const ALT_KEYS: u32 = 0x0002 | 0x0001;
@ -221,7 +274,7 @@ impl From<Console::INPUT_RECORD> for Event {
// pub dwButtonState: u32, // pub dwButtonState: u32,
// pub dwControlKeyState: u32, // pub dwControlKeyState: u32,
// pub dwEventFlags: u32, // pub dwEventFlags: u32,
Event::Mouse{ Event::Mouse {
x: event.dwMousePosition.X, x: event.dwMousePosition.X,
y: event.dwMousePosition.Y, y: event.dwMousePosition.Y,
} }

@ -5,20 +5,20 @@ use windows::Win32::System::Console;
pub struct Line { pub struct Line {
chars: Vec<char>, chars: Vec<char>,
cursor: usize,
} }
impl Line { impl Line {
pub fn new() -> Self { pub fn new() -> Self {
Self { chars: Vec::new() } Self {
} chars: Vec::new(),
cursor: 0,
/// adds a character to the end of the line }
pub fn append(&mut self, c: char) {
self.chars.push(c)
} }
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.chars.clear() self.cursor = 0;
self.chars.clear();
} }
pub fn print(&self) -> Result<()> { pub fn print(&self) -> Result<()> {
@ -33,4 +33,15 @@ impl Line {
} }
Ok(()) Ok(())
} }
pub fn back(&mut self) {
if self.cursor > 0 {
self.cursor -= 1;
}
}
pub fn insert(&mut self, c: char) {
self.chars.insert(self.cursor, c);
self.cursor += 1;
}
} }

@ -161,14 +161,12 @@ fn main() -> Result<()> {
prompt.print()?; prompt.print()?;
loop { loop {
let rec = input.next()?; match input.next()? {
let event: input::Event = rec.into();
match event {
input::Event::Key(event) => { input::Event::Key(event) => {
debug!("Key Event: {}", event);
if event.down { if event.down {
continue; continue;
} }
debug!("Key Event: {}", event);
if event.code == key::ENTER { if event.code == key::ENTER {
newline(stdout)?; newline(stdout)?;
@ -195,12 +193,18 @@ fn main() -> Result<()> {
continue; 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() { if !event.char.is_control() {
line.insert(event.char);
let mut buf = [0 as u8; 8]; let mut buf = [0 as u8; 8];
let s = event.char.encode_utf8(&mut buf); let s = event.char.encode_utf8(&mut buf);
s.chars().for_each(|c| line.append(c));
// write everything from the current line cursor out to the output buffer. Then
// rewind the cursor in the output buffer to where it was.
unsafe { unsafe {
Error::check(Console::WriteConsoleW( Error::check(Console::WriteConsoleA(
stdout, stdout,
s.as_bytes(), s.as_bytes(),
None, None,
@ -209,7 +213,17 @@ fn main() -> Result<()> {
} }
continue; continue;
} }
debug!("Unhandled Keyboard Event: {}", event);
} }
input::Event::Left => {
debug!("back!");
line.back();
unsafe {
let text = "\x1b[D";
Error::check(Console::WriteConsoleA(stdout, text.as_bytes(), None, None))?;
}
},
input::Event::Focus(true) => {}, input::Event::Focus(true) => {},
input::Event::Focus(false) => {}, input::Event::Focus(false) => {},
input::Event::Menu(_command_id) => {}, input::Event::Menu(_command_id) => {},

Loading…
Cancel
Save