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:
parent
2deba1ece4
commit
85a6b178cf
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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!(
|
||||||
|
Loading…
Reference in New Issue
Block a user