unrecognized escape sequences no longer crash the shell

main
Jordan Orelli 10 months ago
parent 08b2b3be52
commit 3d71f25528

@ -23,8 +23,11 @@ pub enum InputError {
#[error("input record cannot convert to control character because it is an up event")] #[error("input record cannot convert to control character because it is an up event")]
ControlCharactersOnlyGoDownNotUp, ControlCharactersOnlyGoDownNotUp,
#[error("bad escape sequence")] #[error("unrecognized escape sequence: {0}")]
BadEscapeSequence, BadEscapeSequence(String),
#[error("fart")]
UnexpectedInputRecordDuringEscapeParting,
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]

@ -4,11 +4,12 @@ use crate::{
log::*, log::*,
}; };
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use log::error;
use std::{ use std::{
cell::{RefCell, RefMut}, cell::{RefCell, RefMut},
collections::VecDeque, collections::VecDeque,
fmt, fmt,
rc::Rc, rc::{Rc, Weak},
}; };
use windows::Win32::{Foundation::HANDLE, System::Console}; use windows::Win32::{Foundation::HANDLE, System::Console};
@ -181,8 +182,13 @@ impl Reader {
} }
if is_escape_start(&record) { if is_escape_start(&record) {
let escape = self.next_escape_sequence()?; match self.next_escape_sequence() {
return Ok(Event::Escape(escape)); Ok(escape) => return Ok(Event::Escape(escape)),
Err(e) => {
error!("{e}");
return self.next();
}
}
} }
let event: Event = record.into(); let event: Event = record.into();
@ -239,9 +245,12 @@ impl Reader {
panic!(); panic!();
} }
} }
let c = as_escape_character(&record).ok_or(InputError::BadEscapeSequence)?; let c = as_escape_character(&record)
if let Some(escape) = self.escapes.step(c) { .ok_or(InputError::UnexpectedInputRecordDuringEscapeParting)?;
return Ok(escape); match self.escapes.step(c) {
EscapeStep::Continue => {}
EscapeStep::End(escape) => return Ok(escape),
EscapeStep::Abort(s) => return Err(InputError::BadEscapeSequence(s).into()),
} }
} }
} }
@ -333,13 +342,14 @@ impl From<Console::INPUT_RECORD> for Event {
} }
/// A reference to a target node in a prefix tree, used for manipulating the prefix tree /// A reference to a target node in a prefix tree, used for manipulating the prefix tree
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct EscapeCursor { pub struct EscapeCursor {
target: Rc<EscapeNode>, target: Rc<EscapeNode>,
root: Rc<EscapeNode>, root: Rc<EscapeNode>,
} }
/// A node in a prefix tree. This prefix tree is used to parse strings into escape sequences /// A node in a prefix tree. This prefix tree is used to parse strings into escape sequences. This
/// prefix tree is special in that there are no values in the intermediate nodes of the tree.
#[derive(Debug)] #[derive(Debug)]
pub enum EscapeNode { pub enum EscapeNode {
Root { Root {
@ -347,15 +357,18 @@ pub enum EscapeNode {
}, },
Nonterminal { Nonterminal {
c: char, c: char,
parent: Weak<EscapeNode>,
children: RefCell<Vec<Rc<EscapeNode>>>, children: RefCell<Vec<Rc<EscapeNode>>>,
}, },
Terminal { Terminal {
c: char, c: char,
parent: Weak<EscapeNode>,
v: Escape, v: Escape,
}, },
} }
impl EscapeNode { impl EscapeNode {
/// Creates a new prefix tree mapping character sequences to structured escape codes
pub fn new() -> EscapeCursor { pub fn new() -> EscapeCursor {
let root = Rc::new(EscapeNode::Root { let root = Rc::new(EscapeNode::Root {
children: RefCell::new(Vec::new()), children: RefCell::new(Vec::new()),
@ -382,51 +395,44 @@ impl EscapeNode {
} }
} }
fn child(&self, c: char) -> Option<Rc<EscapeNode>> { fn parent(&self) -> Option<Rc<EscapeNode>> {
for child in self.children().iter_mut() { match self {
if child.char() == c { EscapeNode::Root { .. } => None,
return Some(Rc::clone(child)); EscapeNode::Nonterminal { parent, .. } => parent.upgrade(),
} EscapeNode::Terminal { parent, .. } => parent.upgrade(),
}
None
}
fn child_nonterminal(&self, c: char) -> Rc<EscapeNode> {
for child in self.children().iter_mut() {
if child.char() == c {
return Rc::clone(child);
}
} }
let child = Rc::new(EscapeNode::Nonterminal {
c,
children: RefCell::new(Vec::new()),
});
self.children().push(Rc::clone(&child));
child
} }
fn add_child_terminal(&self, c: char, v: Escape) { fn child(&self, c: char) -> Option<Rc<EscapeNode>> {
for child in self.children().iter_mut() { for child in self.children().iter_mut() {
if child.char() == c { if child.char() == c {
panic!(); return Some(Rc::clone(child));
} }
} }
let child = Rc::new(EscapeNode::Terminal { c, v }); None
self.children().push(child);
} }
} }
impl EscapeCursor { impl EscapeCursor {
fn step(&mut self, c: char) -> Option<Escape> { /// advances our cursor by one step. We look at the current position and descend the tree into
let child = self.target.child(c)?; /// the node described by the target character. If that node is a terminal node, we return that
/// node's value.
fn step(&mut self, c: char) -> EscapeStep {
let child = match self.target.child(c) {
Some(c) => c,
None => {
let path = self.path();
return EscapeStep::Abort(format!("{path}{c}"));
}
};
match child.as_ref() { match child.as_ref() {
EscapeNode::Terminal { v, .. } => { EscapeNode::Terminal { v, .. } => {
self.reset(); self.reset();
Some(*v) EscapeStep::End(*v)
} }
_ => { _ => {
self.target = child; self.target = child;
None EscapeStep::Continue
} }
} }
} }
@ -435,14 +441,36 @@ impl EscapeCursor {
match self.target.child(c) { match self.target.child(c) {
Some(child) => self.target = child, Some(child) => self.target = child,
None => { None => {
self.target = self.target.child_nonterminal(c); for child in self.target.clone().children().iter() {
if child.char() == c {
self.target = Rc::clone(child);
return;
}
}
let child = Rc::new(EscapeNode::Nonterminal {
c,
parent: Rc::downgrade(&self.target),
children: RefCell::new(Vec::new()),
});
self.target.children().push(Rc::clone(&child));
self.target = child;
} }
} }
} }
/// adds a terminal node into the tree as a child of the current node /// adds a terminal node into the tree as a child of the current node
fn add_terminal(&mut self, c: char, v: Escape) { fn add_terminal(&mut self, c: char, v: Escape) {
self.target.add_child_terminal(c, v); for child in self.target.children().iter_mut() {
if child.char() == c {
panic!();
}
}
let child = Rc::new(EscapeNode::Terminal {
c,
parent: Rc::downgrade(&self.target),
v,
});
self.target.children().push(child);
} }
/// resets the cursor back to the top of the tree /// resets the cursor back to the top of the tree
@ -467,6 +495,23 @@ impl EscapeCursor {
self.add_step(c); self.add_step(c);
} }
} }
/// renders as a string the path that takes us to the node to which we are currently pointed
fn path(&self) -> String {
let mut cursor = self.clone();
let mut chars = Vec::new();
while !cursor.is_at_root() {
chars.push(cursor.target.char());
cursor.target = cursor.target.parent().unwrap();
}
chars.iter().rev().collect()
}
}
enum EscapeStep {
Continue,
Abort(String),
End(Escape),
} }
/// generates a prefix tree used for parsing escape sequences /// generates a prefix tree used for parsing escape sequences

Loading…
Cancel
Save