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}")]
IOError(#[from] io::Error),
#[error("input error: {0}")]
InputError(String),
}
impl Error {
@ -23,4 +26,8 @@ impl 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> {
// All buffered items have been processed, ask the OS for new event records
pub fn next(&mut self) -> Result<Event> {
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 {
unsafe {
Error::check(Console::ReadConsoleInputA(
@ -162,6 +174,49 @@ impl Reader {
self.buf_idx += 1;
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)]
@ -169,11 +224,9 @@ pub enum Event {
Focus(bool),
Menu(u32),
Key(key::Event),
Mouse{
x: i16,
y: i16,
},
Mouse { x: i16, y: i16 },
Size,
Left,
}
const ALT_KEYS: u32 = 0x0002 | 0x0001;

@ -5,20 +5,20 @@ use windows::Win32::System::Console;
pub struct Line {
chars: Vec<char>,
cursor: usize,
}
impl Line {
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) {
self.chars.clear()
self.cursor = 0;
self.chars.clear();
}
pub fn print(&self) -> Result<()> {
@ -33,4 +33,15 @@ impl Line {
}
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()?;
loop {
let rec = input.next()?;
let event: input::Event = rec.into();
match event {
match input.next()? {
input::Event::Key(event) => {
debug!("Key Event: {}", event);
if event.down {
continue;
}
debug!("Key Event: {}", event);
if event.code == key::ENTER {
newline(stdout)?;
@ -195,12 +193,18 @@ fn main() -> Result<()> {
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() {
line.insert(event.char);
let mut buf = [0 as u8; 8];
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 {
Error::check(Console::WriteConsoleW(
Error::check(Console::WriteConsoleA(
stdout,
s.as_bytes(),
None,
@ -209,7 +213,17 @@ fn main() -> Result<()> {
}
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(false) => {},
input::Event::Menu(_command_id) => {},

Loading…
Cancel
Save