unrecognized escape sequences no longer crash the shell

main
Jordan Orelli 9 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")]
ControlCharactersOnlyGoDownNotUp,
#[error("bad escape sequence")]
BadEscapeSequence,
#[error("unrecognized escape sequence: {0}")]
BadEscapeSequence(String),
#[error("fart")]
UnexpectedInputRecordDuringEscapeParting,
}
#[derive(Debug, Error)]

@ -4,11 +4,12 @@ use crate::{
log::*,
};
use anyhow::{Context, Result};
use log::error;
use std::{
cell::{RefCell, RefMut},
collections::VecDeque,
fmt,
rc::Rc,
rc::{Rc, Weak},
};
use windows::Win32::{Foundation::HANDLE, System::Console};
@ -181,8 +182,13 @@ impl Reader {
}
if is_escape_start(&record) {
let escape = self.next_escape_sequence()?;
return Ok(Event::Escape(escape));
match self.next_escape_sequence() {
Ok(escape) => return Ok(Event::Escape(escape)),
Err(e) => {
error!("{e}");
return self.next();
}
}
}
let event: Event = record.into();
@ -239,9 +245,12 @@ impl Reader {
panic!();
}
}
let c = as_escape_character(&record).ok_or(InputError::BadEscapeSequence)?;
if let Some(escape) = self.escapes.step(c) {
return Ok(escape);
let c = as_escape_character(&record)
.ok_or(InputError::UnexpectedInputRecordDuringEscapeParting)?;
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
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct EscapeCursor {
target: 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)]
pub enum EscapeNode {
Root {
@ -347,15 +357,18 @@ pub enum EscapeNode {
},
Nonterminal {
c: char,
parent: Weak<EscapeNode>,
children: RefCell<Vec<Rc<EscapeNode>>>,
},
Terminal {
c: char,
parent: Weak<EscapeNode>,
v: Escape,
},
}
impl EscapeNode {
/// Creates a new prefix tree mapping character sequences to structured escape codes
pub fn new() -> EscapeCursor {
let root = Rc::new(EscapeNode::Root {
children: RefCell::new(Vec::new()),
@ -382,51 +395,44 @@ impl EscapeNode {
}
}
fn child(&self, c: char) -> Option<Rc<EscapeNode>> {
for child in self.children().iter_mut() {
if child.char() == c {
return Some(Rc::clone(child));
}
}
None
}
fn child_nonterminal(&self, c: char) -> Rc<EscapeNode> {
for child in self.children().iter_mut() {
if child.char() == c {
return Rc::clone(child);
}
fn parent(&self) -> Option<Rc<EscapeNode>> {
match self {
EscapeNode::Root { .. } => None,
EscapeNode::Nonterminal { parent, .. } => parent.upgrade(),
EscapeNode::Terminal { parent, .. } => parent.upgrade(),
}
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() {
if child.char() == c {
panic!();
return Some(Rc::clone(child));
}
}
let child = Rc::new(EscapeNode::Terminal { c, v });
self.children().push(child);
None
}
}
impl EscapeCursor {
fn step(&mut self, c: char) -> Option<Escape> {
let child = self.target.child(c)?;
/// advances our cursor by one step. We look at the current position and descend the tree into
/// 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() {
EscapeNode::Terminal { v, .. } => {
self.reset();
Some(*v)
EscapeStep::End(*v)
}
_ => {
self.target = child;
None
EscapeStep::Continue
}
}
}
@ -435,14 +441,36 @@ impl EscapeCursor {
match self.target.child(c) {
Some(child) => self.target = child,
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
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
@ -467,6 +495,23 @@ impl EscapeCursor {
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

Loading…
Cancel
Save