1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-22 22:42:48 +03:00

termwiz: recognize some bidi-related escape sequences

We don't do anything with these; this is just teaching
the parser how to recognize these codes.

refs: https://github.com/wez/wezterm/issues/784
This commit is contained in:
Wez Furlong 2022-01-18 22:35:49 -07:00
parent 2deba1ece4
commit 85a6b178cf
3 changed files with 92 additions and 1 deletions

View File

@ -412,6 +412,9 @@ impl<'a> Performer<'a> {
CSI::Device(dev) => self.state.perform_device(*dev), CSI::Device(dev) => self.state.perform_device(*dev),
CSI::Mouse(mouse) => error!("mouse report sent by app? {:?}", mouse), CSI::Mouse(mouse) => error!("mouse report sent by app? {:?}", mouse),
CSI::Window(window) => self.state.perform_csi_window(window), CSI::Window(window) => self.state.perform_csi_window(window),
CSI::SelectCharacterPath(path, _) => {
log::warn!("unhandled SelectCharacterPath {:?}", path);
}
CSI::Unspecified(unspec) => { CSI::Unspecified(unspec) => {
log::warn!("unknown unspecified CSI: {:?}", format!("{}", unspec)) log::warn!("unknown unspecified CSI: {:?}", format!("{}", unspec))
} }

View File

@ -27,12 +27,25 @@ pub enum CSI {
Window(Window), Window(Window),
/// ECMA-48 SCP
SelectCharacterPath(CharacterPath, i64),
/// Unknown or unspecified; should be rare and is rather /// Unknown or unspecified; should be rare and is rather
/// large, so it is boxed and kept outside of the enum /// large, so it is boxed and kept outside of the enum
/// body to help reduce space usage in the common cases. /// body to help reduce space usage in the common cases.
Unspecified(Box<Unspecified>), Unspecified(Box<Unspecified>),
} }
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CharacterPath {
/// 0
ImplementationDefault,
/// 1
LeftToRightOrTopToBottom,
/// 2
RightToLeftOrBottomToTop,
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Unspecified { pub struct Unspecified {
pub params: Vec<CsiParam>, pub params: Vec<CsiParam>,
@ -69,6 +82,18 @@ impl Display for CSI {
CSI::Mouse(mouse) => mouse.fmt(f)?, CSI::Mouse(mouse) => mouse.fmt(f)?,
CSI::Device(dev) => dev.fmt(f)?, CSI::Device(dev) => dev.fmt(f)?,
CSI::Window(window) => window.fmt(f)?, CSI::Window(window) => window.fmt(f)?,
CSI::SelectCharacterPath(path, n) => {
let a = match path {
CharacterPath::ImplementationDefault => 0,
CharacterPath::LeftToRightOrTopToBottom => 1,
CharacterPath::RightToLeftOrBottomToTop => 2,
};
match (a, n) {
(0, 0) => write!(f, " k")?,
(a, 0) => write!(f, "{} k", a)?,
(a, n) => write!(f, "{};{} k", a, n)?,
}
}
}; };
Ok(()) Ok(())
} }
@ -775,6 +800,8 @@ pub enum TerminalModeCode {
KeyboardAction = 2, KeyboardAction = 2,
/// https://vt100.net/docs/vt510-rm/IRM.html /// https://vt100.net/docs/vt510-rm/IRM.html
Insert = 4, Insert = 4,
/// <https://terminal-wg.pages.freedesktop.org/bidi/recommendation/escape-sequences.html>
BiDirectionalSupportMode = 8,
/// https://vt100.net/docs/vt510-rm/SRM.html /// https://vt100.net/docs/vt510-rm/SRM.html
/// But in the MS terminal this is cursor blinking. /// But in the MS terminal this is cursor blinking.
SendReceive = 12, SendReceive = 12,
@ -1576,6 +1603,7 @@ macro_rules! parse {
impl<'a> CSIParser<'a> { impl<'a> CSIParser<'a> {
fn parse_next(&mut self, params: &'a [CsiParam]) -> Result<CSI, ()> { fn parse_next(&mut self, params: &'a [CsiParam]) -> Result<CSI, ()> {
match (self.control, self.orig_params) { match (self.control, self.orig_params) {
('k', [.., CsiParam::P(b' ')]) => self.select_character_path(params),
('q', [.., CsiParam::P(b' ')]) => self.cursor_style(params), ('q', [.., CsiParam::P(b' ')]) => self.cursor_style(params),
('y', [.., CsiParam::P(b'*')]) => self.checksum_area(params), ('y', [.., CsiParam::P(b'*')]) => self.checksum_area(params),
@ -1704,6 +1732,32 @@ impl<'a> CSIParser<'a> {
} }
} }
fn select_character_path(&mut self, params: &'a [CsiParam]) -> Result<CSI, ()> {
fn path(n: i64) -> Result<CharacterPath, ()> {
Ok(match n {
0 => CharacterPath::ImplementationDefault,
1 => CharacterPath::LeftToRightOrTopToBottom,
2 => CharacterPath::RightToLeftOrBottomToTop,
_ => return Err(()),
})
}
match params {
[CsiParam::P(b' ')] => Ok(self.advance_by(
1,
params,
CSI::SelectCharacterPath(CharacterPath::ImplementationDefault, 0),
)),
[CsiParam::Integer(a), CsiParam::P(b' ')] => {
Ok(self.advance_by(2, params, CSI::SelectCharacterPath(path(*a)?, 0)))
}
[CsiParam::Integer(a), CsiParam::P(b';'), CsiParam::Integer(b), CsiParam::P(b' ')] => {
Ok(self.advance_by(4, params, CSI::SelectCharacterPath(path(*a)?, *b)))
}
_ => Err(()),
}
}
fn cursor_style(&mut self, params: &'a [CsiParam]) -> Result<CSI, ()> { fn cursor_style(&mut self, params: &'a [CsiParam]) -> Result<CSI, ()> {
match params { match params {
[CsiParam::Integer(p), CsiParam::P(b' ')] => match FromPrimitive::from_i64(*p) { [CsiParam::Integer(p), CsiParam::P(b' ')] => match FromPrimitive::from_i64(*p) {
@ -2711,6 +2765,22 @@ mod test {
); );
} }
#[test]
fn bidi_modes() {
assert_eq!(
parse('h', &[8], "\x1b[8h"),
vec![CSI::Mode(Mode::SetMode(TerminalMode::Code(
TerminalModeCode::BiDirectionalSupportMode
)))]
);
assert_eq!(
parse('l', &[8], "\x1b[8l"),
vec![CSI::Mode(Mode::ResetMode(TerminalMode::Code(
TerminalModeCode::BiDirectionalSupportMode
)))]
);
}
#[test] #[test]
fn mouse() { fn mouse() {
let res: Vec<_> = CSI::parse( let res: Vec<_> = CSI::parse(

View File

@ -531,7 +531,7 @@ mod test {
use crate::cell::{Intensity, Underline}; use crate::cell::{Intensity, Underline};
use crate::color::ColorSpec; use crate::color::ColorSpec;
use crate::escape::csi::{ use crate::escape::csi::{
DecPrivateMode, DecPrivateModeCode, Device, Mode, Sgr, Window, XtSmGraphics, CharacterPath, DecPrivateMode, DecPrivateModeCode, Device, Mode, Sgr, Window, XtSmGraphics,
XtSmGraphicsItem, XtermKeyModifierResource, XtSmGraphicsItem, XtermKeyModifierResource,
}; };
use crate::escape::{EscCode, OneBased}; use crate::escape::{EscCode, OneBased};
@ -871,6 +871,24 @@ mod test {
); );
} }
#[test]
fn bidi_modes() {
assert_eq!(
round_trip_parse("\x1b[1 k"),
vec![Action::CSI(CSI::SelectCharacterPath(
CharacterPath::LeftToRightOrTopToBottom,
0
))]
);
assert_eq!(
round_trip_parse("\x1b[2;1 k"),
vec![Action::CSI(CSI::SelectCharacterPath(
CharacterPath::RightToLeftOrBottomToTop,
1
))]
);
}
#[test] #[test]
fn xterm_key() { fn xterm_key() {
assert_eq!( assert_eq!(