mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 21:32:13 +03:00
Wrap up synchronized output handling, parser changes
This commit hooks up DECRQM so that we can report that we implement
synchronized updates, and then refines the code that manages sending
data to the terminal model; the first cut at synchronized updates
was a bit simplistic, and now we make a point of "flushing" pending
actions when we start a sync point, and again as soon as we release
the sync point.
This smooths out the jaggies around the orca that I mentioned in
dcbbda7702
and while testing this, I realized that recent parser changes had
mangled processing bundled dec private mode sequences where multiple
modes were specified in the same overall escape sequence. I've
added the missing unit test case for this and made that work again.
refs: https://github.com/wez/wezterm/issues/955
refs: https://github.com/wez/wezterm/issues/882
This commit is contained in:
parent
a249021920
commit
365a68dfb8
@ -116,23 +116,35 @@ fn parse_buffered_data(pane_id: PaneId, dead: &Arc<AtomicBool>, mut rx: FileDesc
|
||||
}
|
||||
Ok(size) => {
|
||||
parser.parse(&buf[0..size], |action| {
|
||||
let mut flush = false;
|
||||
match &action {
|
||||
Action::CSI(CSI::Mode(Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::SynchronizedOutput,
|
||||
)))) => {
|
||||
hold = true;
|
||||
|
||||
// Flush prior actions
|
||||
if !actions.is_empty() {
|
||||
send_actions_to_mux(pane_id, dead, std::mem::take(&mut actions));
|
||||
}
|
||||
}
|
||||
Action::CSI(CSI::Mode(Mode::ResetDecPrivateMode(
|
||||
DecPrivateMode::Code(DecPrivateModeCode::SynchronizedOutput),
|
||||
))) => {
|
||||
hold = false;
|
||||
flush = true;
|
||||
}
|
||||
Action::CSI(CSI::Device(dev)) if matches!(**dev, Device::SoftReset) => {
|
||||
hold = false;
|
||||
flush = true;
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
actions.push(action)
|
||||
actions.push(action);
|
||||
|
||||
if flush && !actions.is_empty() {
|
||||
send_actions_to_mux(pane_id, dead, std::mem::take(&mut actions));
|
||||
}
|
||||
});
|
||||
if !actions.is_empty() && !hold {
|
||||
send_actions_to_mux(pane_id, dead, std::mem::take(&mut actions));
|
||||
|
@ -7,7 +7,7 @@ use anyhow::bail;
|
||||
use image::imageops::FilterType;
|
||||
use image::ImageFormat;
|
||||
use log::{debug, error};
|
||||
use num_traits::FromPrimitive;
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use ordered_float::NotNan;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
@ -1869,6 +1869,37 @@ impl TerminalState {
|
||||
}
|
||||
}
|
||||
|
||||
fn decqrm_response(&mut self, mode: Mode, mut recognized: bool, enabled: bool) {
|
||||
let (is_dec, number) = match &mode {
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(code)) => (true, code.to_u16().unwrap()),
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Unspecified(code)) => {
|
||||
recognized = false;
|
||||
(true, *code)
|
||||
}
|
||||
Mode::QueryMode(TerminalMode::Code(code)) => (false, code.to_u16().unwrap()),
|
||||
Mode::QueryMode(TerminalMode::Unspecified(code)) => {
|
||||
recognized = false;
|
||||
(false, *code)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let prefix = if is_dec { "?" } else { "" };
|
||||
|
||||
let status = if recognized {
|
||||
if enabled {
|
||||
1 // set
|
||||
} else {
|
||||
2 // reset
|
||||
}
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
log::trace!("{:?} -> recognized={} status={}", mode, recognized, status);
|
||||
write!(self.writer, "\x1b[{}{};{}$y", prefix, number, status).ok();
|
||||
}
|
||||
|
||||
fn perform_csi_mode(&mut self, mode: Mode) {
|
||||
match mode {
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||
@ -1877,6 +1908,11 @@ impl TerminalState {
|
||||
| Mode::ResetDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::StartBlinkingCursor,
|
||||
)) => {}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::StartBlinkingCursor,
|
||||
)) => {
|
||||
self.decqrm_response(mode, true, false);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::AutoRepeat))
|
||||
| Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::AutoRepeat)) => {
|
||||
@ -1895,6 +1931,12 @@ impl TerminalState {
|
||||
self.reverse_wraparound_mode = false;
|
||||
}
|
||||
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::ReverseWraparound,
|
||||
)) => {
|
||||
self.decqrm_response(mode, true, self.reverse_wraparound_mode);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::LeftRightMarginMode,
|
||||
)) => {
|
||||
@ -1908,6 +1950,12 @@ impl TerminalState {
|
||||
self.left_and_right_margins = 0..self.screen().physical_cols;
|
||||
}
|
||||
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::LeftRightMarginMode,
|
||||
)) => {
|
||||
self.decqrm_response(mode, true, self.left_and_right_margin_mode);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SaveCursor)) => {
|
||||
self.dec_save_cursor();
|
||||
}
|
||||
@ -1924,6 +1972,10 @@ impl TerminalState {
|
||||
self.dec_auto_wrap = false;
|
||||
}
|
||||
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::AutoWrap)) => {
|
||||
self.decqrm_response(mode, true, self.dec_auto_wrap);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::OriginMode)) => {
|
||||
self.dec_origin_mode = true;
|
||||
self.set_cursor_pos(&Position::Absolute(0), &Position::Absolute(0));
|
||||
@ -1934,6 +1986,10 @@ impl TerminalState {
|
||||
self.set_cursor_pos(&Position::Absolute(0), &Position::Absolute(0));
|
||||
}
|
||||
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::OriginMode)) => {
|
||||
self.decqrm_response(mode, true, self.dec_origin_mode);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::UsePrivateColorRegistersForEachGraphic,
|
||||
)) => {
|
||||
@ -1944,6 +2000,15 @@ impl TerminalState {
|
||||
)) => {
|
||||
self.use_private_color_registers_for_each_graphic = false;
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::UsePrivateColorRegistersForEachGraphic,
|
||||
)) => {
|
||||
self.decqrm_response(
|
||||
mode,
|
||||
true,
|
||||
self.use_private_color_registers_for_each_graphic,
|
||||
);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::SynchronizedOutput,
|
||||
@ -1955,6 +2020,13 @@ impl TerminalState {
|
||||
)) => {
|
||||
// This is handled in wezterm's mux
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::SynchronizedOutput,
|
||||
)) => {
|
||||
// This is handled in wezterm's mux; if we get here, then it isn't enabled,
|
||||
// so we always report false
|
||||
self.decqrm_response(mode, true, false);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SmoothScroll))
|
||||
| Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SmoothScroll)) => {
|
||||
@ -1988,6 +2060,9 @@ impl TerminalState {
|
||||
Mode::ResetMode(TerminalMode::Code(TerminalModeCode::Insert)) => {
|
||||
self.insert = false;
|
||||
}
|
||||
Mode::QueryMode(TerminalMode::Code(TerminalModeCode::Insert)) => {
|
||||
self.decqrm_response(mode, true, self.insert);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::BracketedPaste)) => {
|
||||
self.bracketed_paste = true;
|
||||
@ -1995,6 +2070,9 @@ impl TerminalState {
|
||||
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::BracketedPaste)) => {
|
||||
self.bracketed_paste = false;
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::BracketedPaste)) => {
|
||||
self.decqrm_response(mode, true, self.bracketed_paste);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::OptEnableAlternateScreen,
|
||||
@ -2036,6 +2114,11 @@ impl TerminalState {
|
||||
)) => {
|
||||
self.application_cursor_keys = false;
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::ApplicationCursorKeys,
|
||||
)) => {
|
||||
self.decqrm_response(mode, true, self.application_cursor_keys);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SixelScrolling)) => {
|
||||
self.sixel_scrolling = true;
|
||||
@ -2043,6 +2126,9 @@ impl TerminalState {
|
||||
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SixelScrolling)) => {
|
||||
self.sixel_scrolling = false;
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SixelScrolling)) => {
|
||||
self.decqrm_response(mode, true, self.sixel_scrolling);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::DecAnsiMode)) => {
|
||||
self.dec_ansi_mode = true;
|
||||
@ -2050,6 +2136,9 @@ impl TerminalState {
|
||||
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::DecAnsiMode)) => {
|
||||
self.dec_ansi_mode = false;
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::DecAnsiMode)) => {
|
||||
self.decqrm_response(mode, true, self.dec_ansi_mode);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::ShowCursor)) => {
|
||||
self.cursor_visible = true;
|
||||
@ -2057,6 +2146,9 @@ impl TerminalState {
|
||||
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::ShowCursor)) => {
|
||||
self.cursor_visible = false;
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::ShowCursor)) => {
|
||||
self.decqrm_response(mode, true, self.cursor_visible);
|
||||
}
|
||||
Mode::SetMode(TerminalMode::Code(TerminalModeCode::ShowCursor)) => {
|
||||
self.cursor_visible = true;
|
||||
}
|
||||
@ -2072,6 +2164,9 @@ impl TerminalState {
|
||||
self.mouse_tracking = false;
|
||||
self.last_mouse_move.take();
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::MouseTracking)) => {
|
||||
self.decqrm_response(mode, true, self.mouse_tracking);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::HighlightMouseTracking,
|
||||
@ -2090,6 +2185,11 @@ impl TerminalState {
|
||||
self.button_event_mouse = false;
|
||||
self.last_mouse_move.take();
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::ButtonEventMouse,
|
||||
)) => {
|
||||
self.decqrm_response(mode, true, self.button_event_mouse);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::AnyEventMouse)) => {
|
||||
self.any_event_mouse = true;
|
||||
@ -2099,6 +2199,9 @@ impl TerminalState {
|
||||
self.any_event_mouse = false;
|
||||
self.last_mouse_move.take();
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::AnyEventMouse)) => {
|
||||
self.decqrm_response(mode, true, self.any_event_mouse);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::FocusTracking)) => {
|
||||
self.focus_tracking = true;
|
||||
@ -2108,6 +2211,9 @@ impl TerminalState {
|
||||
self.focus_tracking = false;
|
||||
self.last_mouse_move.take();
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::FocusTracking)) => {
|
||||
self.decqrm_response(mode, true, self.focus_tracking);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SGRMouse)) => {
|
||||
self.sgr_mouse = true;
|
||||
@ -2117,6 +2223,9 @@ impl TerminalState {
|
||||
self.sgr_mouse = false;
|
||||
self.last_mouse_move.take();
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SGRMouse)) => {
|
||||
self.decqrm_response(mode, true, self.sgr_mouse);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::SixelScrollsRight,
|
||||
@ -2128,6 +2237,11 @@ impl TerminalState {
|
||||
)) => {
|
||||
self.sixel_scrolls_right = false;
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::SixelScrollsRight,
|
||||
)) => {
|
||||
self.decqrm_response(mode, true, self.sixel_scrolls_right);
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::ClearAndEnableAlternateScreen,
|
||||
@ -2153,25 +2267,24 @@ impl TerminalState {
|
||||
log::warn!("save/restore dec mode {:?} unimplemented", n)
|
||||
}
|
||||
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Unspecified(n))
|
||||
| Mode::ResetDecPrivateMode(DecPrivateMode::Unspecified(n))
|
||||
| Mode::SaveDecPrivateMode(DecPrivateMode::Unspecified(n))
|
||||
| Mode::RestoreDecPrivateMode(DecPrivateMode::Unspecified(n)) => {
|
||||
log::warn!("unhandled DecPrivateMode {}", n);
|
||||
Mode::SetDecPrivateMode(DecPrivateMode::Unspecified(_))
|
||||
| Mode::ResetDecPrivateMode(DecPrivateMode::Unspecified(_))
|
||||
| Mode::SaveDecPrivateMode(DecPrivateMode::Unspecified(_))
|
||||
| Mode::RestoreDecPrivateMode(DecPrivateMode::Unspecified(_)) => {
|
||||
log::warn!("unhandled DecPrivateMode {:?}", mode);
|
||||
}
|
||||
|
||||
Mode::SetMode(TerminalMode::Unspecified(n))
|
||||
| Mode::ResetMode(TerminalMode::Unspecified(n)) => {
|
||||
log::warn!("unhandled TerminalMode {}", n);
|
||||
}
|
||||
|
||||
Mode::SetMode(m) | Mode::ResetMode(m) => {
|
||||
log::warn!("unhandled TerminalMode {:?}", m);
|
||||
mode @ Mode::SetMode(_) | mode @ Mode::ResetMode(_) => {
|
||||
log::warn!("unhandled {:?}", mode);
|
||||
}
|
||||
|
||||
Mode::XtermKeyMode { resource, value } => {
|
||||
log::warn!("unhandled XtermKeyMode {:?} {:?}", resource, value);
|
||||
}
|
||||
|
||||
Mode::QueryDecPrivateMode(_) | Mode::QueryMode(_) => {
|
||||
self.decqrm_response(mode, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,6 +247,7 @@ impl XtSmGraphics {
|
||||
}
|
||||
|
||||
pub fn parse(params: &[CsiParam]) -> Result<CSI, ()> {
|
||||
let params = Cracked::parse(¶ms[1..])?;
|
||||
Ok(CSI::Device(Box::new(Device::XtSmGraphics(XtSmGraphics {
|
||||
item: match params.get(0).ok_or(())? {
|
||||
CsiParam::Integer(1) => XtSmGraphicsItem::NumberOfColorRegisters,
|
||||
@ -259,10 +260,10 @@ impl XtSmGraphics {
|
||||
CsiParam::Integer(n) => *n,
|
||||
_ => return Err(()),
|
||||
},
|
||||
value: params[2..]
|
||||
value: params.params[2..]
|
||||
.iter()
|
||||
.filter_map(|p| match p {
|
||||
CsiParam::Integer(n) => Some(*n),
|
||||
Some(CsiParam::Integer(n)) => Some(*n),
|
||||
_ => None,
|
||||
})
|
||||
.collect(),
|
||||
@ -561,8 +562,10 @@ pub enum Mode {
|
||||
ResetDecPrivateMode(DecPrivateMode),
|
||||
SaveDecPrivateMode(DecPrivateMode),
|
||||
RestoreDecPrivateMode(DecPrivateMode),
|
||||
QueryDecPrivateMode(DecPrivateMode),
|
||||
SetMode(TerminalMode),
|
||||
ResetMode(TerminalMode),
|
||||
QueryMode(TerminalMode),
|
||||
XtermKeyMode {
|
||||
resource: XtermKeyModifierResource,
|
||||
value: Option<i64>,
|
||||
@ -594,8 +597,18 @@ impl Display for Mode {
|
||||
Mode::ResetDecPrivateMode(mode) => emit!("l", mode),
|
||||
Mode::SaveDecPrivateMode(mode) => emit!("s", mode),
|
||||
Mode::RestoreDecPrivateMode(mode) => emit!("r", mode),
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Code(mode)) => {
|
||||
write!(f, "?{}$p", mode.to_u16().ok_or_else(|| FmtError)?)
|
||||
}
|
||||
Mode::QueryDecPrivateMode(DecPrivateMode::Unspecified(mode)) => {
|
||||
write!(f, "?{}$p", mode)
|
||||
}
|
||||
Mode::SetMode(mode) => emit_mode!("h", mode),
|
||||
Mode::ResetMode(mode) => emit_mode!("l", mode),
|
||||
Mode::QueryMode(TerminalMode::Code(mode)) => {
|
||||
write!(f, "?{}$p", mode.to_u16().ok_or_else(|| FmtError)?)
|
||||
}
|
||||
Mode::QueryMode(TerminalMode::Unspecified(mode)) => write!(f, "?{}$p", mode),
|
||||
Mode::XtermKeyMode { resource, value } => {
|
||||
write!(
|
||||
f,
|
||||
@ -1378,6 +1391,7 @@ struct CSIParser<'a> {
|
||||
/// default values, especially for SGR, so we need to be careful not
|
||||
/// to update params to an empty slice.
|
||||
params: Option<&'a [CsiParam]>,
|
||||
orig_params: &'a [CsiParam],
|
||||
}
|
||||
|
||||
impl CSI {
|
||||
@ -1396,6 +1410,7 @@ impl CSI {
|
||||
parameters_truncated,
|
||||
control,
|
||||
params: Some(params),
|
||||
orig_params: params,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1502,7 +1517,7 @@ macro_rules! parse {
|
||||
|
||||
impl<'a> CSIParser<'a> {
|
||||
fn parse_next(&mut self, params: &'a [CsiParam]) -> Result<CSI, ()> {
|
||||
match (self.control, params) {
|
||||
match (self.control, self.orig_params) {
|
||||
('q', [.., CsiParam::P(b' ')]) => self.cursor_style(params),
|
||||
('y', [.., CsiParam::P(b'*')]) => self.checksum_area(params),
|
||||
|
||||
@ -1522,76 +1537,82 @@ impl<'a> CSIParser<'a> {
|
||||
.map(|dev| CSI::Device(Box::new(dev))),
|
||||
|
||||
('S', [CsiParam::P(b'?'), ..]) => XtSmGraphics::parse(params),
|
||||
('p', [CsiParam::Integer(_), CsiParam::P(b'$')])
|
||||
| ('p', [CsiParam::P(b'?'), CsiParam::Integer(_), CsiParam::P(b'$')]) => {
|
||||
self.decrqm(params)
|
||||
}
|
||||
('h', [CsiParam::P(b'?'), ..]) => self
|
||||
.dec(params)
|
||||
.dec(self.focus(params, 1, 0))
|
||||
.map(|mode| CSI::Mode(Mode::SetDecPrivateMode(mode))),
|
||||
('l', [CsiParam::P(b'?'), ..]) => self
|
||||
.dec(params)
|
||||
.dec(self.focus(params, 1, 0))
|
||||
.map(|mode| CSI::Mode(Mode::ResetDecPrivateMode(mode))),
|
||||
('r', [CsiParam::P(b'?'), ..]) => self
|
||||
.dec(params)
|
||||
.dec(self.focus(params, 1, 0))
|
||||
.map(|mode| CSI::Mode(Mode::RestoreDecPrivateMode(mode))),
|
||||
('q', [CsiParam::P(b'>'), ..]) => self
|
||||
.req_terminal_name_and_version(params)
|
||||
.map(|dev| CSI::Device(Box::new(dev))),
|
||||
('s', [CsiParam::P(b'?'), ..]) => self
|
||||
.dec(params)
|
||||
.dec(self.focus(params, 1, 0))
|
||||
.map(|mode| CSI::Mode(Mode::SaveDecPrivateMode(mode))),
|
||||
('m', [CsiParam::P(b'>'), ..]) => self.xterm_key_modifier(params),
|
||||
|
||||
('p', [CsiParam::P(b'!')]) => Ok(CSI::Device(Box::new(Device::SoftReset))),
|
||||
|
||||
('c', _) => self
|
||||
.req_primary_device_attributes(params)
|
||||
.map(|dev| CSI::Device(Box::new(dev))),
|
||||
_ => match self.control {
|
||||
'c' => self
|
||||
.req_primary_device_attributes(params)
|
||||
.map(|dev| CSI::Device(Box::new(dev))),
|
||||
|
||||
('@', _) => parse!(Edit, InsertCharacter, params),
|
||||
('`', _) => parse!(Cursor, CharacterPositionAbsolute, params),
|
||||
('A', _) => parse!(Cursor, Up, params),
|
||||
('B', _) => parse!(Cursor, Down, params),
|
||||
('C', _) => parse!(Cursor, Right, params),
|
||||
('D', _) => parse!(Cursor, Left, params),
|
||||
('E', _) => parse!(Cursor, NextLine, params),
|
||||
('F', _) => parse!(Cursor, PrecedingLine, params),
|
||||
('G', _) => parse!(Cursor, CharacterAbsolute, params),
|
||||
('H', _) => parse!(Cursor, Position, line, col, params),
|
||||
('I', _) => parse!(Cursor, ForwardTabulation, params),
|
||||
('J', _) => parse!(Edit, EraseInDisplay, params),
|
||||
('K', _) => parse!(Edit, EraseInLine, params),
|
||||
('L', _) => parse!(Edit, InsertLine, params),
|
||||
('M', _) => parse!(Edit, DeleteLine, params),
|
||||
('P', _) => parse!(Edit, DeleteCharacter, params),
|
||||
('R', _) => parse!(Cursor, ActivePositionReport, line, col, params),
|
||||
('S', _) => parse!(Edit, ScrollUp, params),
|
||||
('T', _) => parse!(Edit, ScrollDown, params),
|
||||
('W', _) => parse!(Cursor, TabulationControl, params),
|
||||
('X', _) => parse!(Edit, EraseCharacter, params),
|
||||
('Y', _) => parse!(Cursor, LineTabulation, params),
|
||||
('Z', _) => parse!(Cursor, BackwardTabulation, params),
|
||||
'@' => parse!(Edit, InsertCharacter, params),
|
||||
'`' => parse!(Cursor, CharacterPositionAbsolute, params),
|
||||
'A' => parse!(Cursor, Up, params),
|
||||
'B' => parse!(Cursor, Down, params),
|
||||
'C' => parse!(Cursor, Right, params),
|
||||
'D' => parse!(Cursor, Left, params),
|
||||
'E' => parse!(Cursor, NextLine, params),
|
||||
'F' => parse!(Cursor, PrecedingLine, params),
|
||||
'G' => parse!(Cursor, CharacterAbsolute, params),
|
||||
'H' => parse!(Cursor, Position, line, col, params),
|
||||
'I' => parse!(Cursor, ForwardTabulation, params),
|
||||
'J' => parse!(Edit, EraseInDisplay, params),
|
||||
'K' => parse!(Edit, EraseInLine, params),
|
||||
'L' => parse!(Edit, InsertLine, params),
|
||||
'M' => parse!(Edit, DeleteLine, params),
|
||||
'P' => parse!(Edit, DeleteCharacter, params),
|
||||
'R' => parse!(Cursor, ActivePositionReport, line, col, params),
|
||||
'S' => parse!(Edit, ScrollUp, params),
|
||||
'T' => parse!(Edit, ScrollDown, params),
|
||||
'W' => parse!(Cursor, TabulationControl, params),
|
||||
'X' => parse!(Edit, EraseCharacter, params),
|
||||
'Y' => parse!(Cursor, LineTabulation, params),
|
||||
'Z' => parse!(Cursor, BackwardTabulation, params),
|
||||
|
||||
('a', _) => parse!(Cursor, CharacterPositionForward, params),
|
||||
('b', _) => parse!(Edit, Repeat, params),
|
||||
('d', _) => parse!(Cursor, LinePositionAbsolute, params),
|
||||
('e', _) => parse!(Cursor, LinePositionForward, params),
|
||||
('f', _) => parse!(Cursor, CharacterAndLinePosition, line, col, params),
|
||||
('g', _) => parse!(Cursor, TabulationClear, params),
|
||||
('h', _) => self
|
||||
.terminal_mode(params)
|
||||
.map(|mode| CSI::Mode(Mode::SetMode(mode))),
|
||||
('j', _) => parse!(Cursor, CharacterPositionBackward, params),
|
||||
('k', _) => parse!(Cursor, LinePositionBackward, params),
|
||||
('l', _) => self
|
||||
.terminal_mode(params)
|
||||
.map(|mode| CSI::Mode(Mode::ResetMode(mode))),
|
||||
'a' => parse!(Cursor, CharacterPositionForward, params),
|
||||
'b' => parse!(Edit, Repeat, params),
|
||||
'd' => parse!(Cursor, LinePositionAbsolute, params),
|
||||
'e' => parse!(Cursor, LinePositionForward, params),
|
||||
'f' => parse!(Cursor, CharacterAndLinePosition, line, col, params),
|
||||
'g' => parse!(Cursor, TabulationClear, params),
|
||||
'h' => self
|
||||
.terminal_mode(params)
|
||||
.map(|mode| CSI::Mode(Mode::SetMode(mode))),
|
||||
'j' => parse!(Cursor, CharacterPositionBackward, params),
|
||||
'k' => parse!(Cursor, LinePositionBackward, params),
|
||||
'l' => self
|
||||
.terminal_mode(params)
|
||||
.map(|mode| CSI::Mode(Mode::ResetMode(mode))),
|
||||
|
||||
('m', _) => self.sgr(params).map(CSI::Sgr),
|
||||
('n', _) => self.dsr(params),
|
||||
('r', _) => self.decstbm(params),
|
||||
('s', _) => self.decslrm(params),
|
||||
('t', _) => self.window(params).map(CSI::Window),
|
||||
('u', _) => noparams!(Cursor, RestoreCursor, params),
|
||||
'm' => self.sgr(params).map(CSI::Sgr),
|
||||
'n' => self.dsr(params),
|
||||
'r' => self.decstbm(params),
|
||||
's' => self.decslrm(params),
|
||||
't' => self.window(params).map(CSI::Window),
|
||||
'u' => noparams!(Cursor, RestoreCursor, params),
|
||||
|
||||
_ => Err(()),
|
||||
_ => Err(()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -1613,6 +1634,15 @@ impl<'a> CSIParser<'a> {
|
||||
result
|
||||
}
|
||||
|
||||
fn focus(&self, params: &'a [CsiParam], from_start: usize, from_end: usize) -> &'a [CsiParam] {
|
||||
if params == self.orig_params {
|
||||
let len = params.len();
|
||||
¶ms[from_start..len - from_end]
|
||||
} else {
|
||||
params
|
||||
}
|
||||
}
|
||||
|
||||
fn cursor_style(&mut self, params: &'a [CsiParam]) -> Result<CSI, ()> {
|
||||
match params {
|
||||
[CsiParam::Integer(p), CsiParam::P(b' ')] => match FromPrimitive::from_i64(*p) {
|
||||
@ -1755,10 +1785,10 @@ impl<'a> CSIParser<'a> {
|
||||
|
||||
fn req_terminal_name_and_version(&mut self, params: &'a [CsiParam]) -> Result<Device, ()> {
|
||||
match params {
|
||||
[] => Ok(Device::RequestTerminalNameAndVersion),
|
||||
[_] => Ok(Device::RequestTerminalNameAndVersion),
|
||||
|
||||
[CsiParam::Integer(0)] => {
|
||||
Ok(self.advance_by(1, params, Device::RequestTerminalNameAndVersion))
|
||||
[_, CsiParam::Integer(0)] => {
|
||||
Ok(self.advance_by(2, params, Device::RequestTerminalNameAndVersion))
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
@ -1887,15 +1917,33 @@ impl<'a> CSIParser<'a> {
|
||||
))
|
||||
}
|
||||
|
||||
fn decrqm(&mut self, params: &'a [CsiParam]) -> Result<CSI, ()> {
|
||||
Ok(CSI::Mode(match params {
|
||||
[CsiParam::Integer(p), CsiParam::P(b'$')] => {
|
||||
Mode::QueryMode(match FromPrimitive::from_i64(*p) {
|
||||
None => TerminalMode::Unspecified(p.to_u16().ok_or(())?),
|
||||
Some(mode) => TerminalMode::Code(mode),
|
||||
})
|
||||
}
|
||||
[CsiParam::P(b'?'), CsiParam::Integer(p), CsiParam::P(b'$')] => {
|
||||
Mode::QueryDecPrivateMode(match FromPrimitive::from_i64(*p) {
|
||||
None => DecPrivateMode::Unspecified(p.to_u16().ok_or(())?),
|
||||
Some(mode) => DecPrivateMode::Code(mode),
|
||||
})
|
||||
}
|
||||
_ => return Err(()),
|
||||
}))
|
||||
}
|
||||
|
||||
fn dec(&mut self, params: &'a [CsiParam]) -> Result<DecPrivateMode, ()> {
|
||||
match params {
|
||||
[CsiParam::P(b'?'), CsiParam::Integer(p0), ..] => match FromPrimitive::from_i64(*p0) {
|
||||
[CsiParam::Integer(p0), ..] => match FromPrimitive::from_i64(*p0) {
|
||||
None => Ok(self.advance_by(
|
||||
2,
|
||||
1,
|
||||
params,
|
||||
DecPrivateMode::Unspecified(p0.to_u16().ok_or(())?),
|
||||
)),
|
||||
Some(mode) => Ok(self.advance_by(2, params, DecPrivateMode::Code(mode))),
|
||||
Some(mode) => Ok(self.advance_by(1, params, DecPrivateMode::Code(mode))),
|
||||
},
|
||||
_ => Err(()),
|
||||
}
|
||||
|
@ -429,7 +429,8 @@ mod test {
|
||||
use crate::cell::{Intensity, Underline};
|
||||
use crate::color::ColorSpec;
|
||||
use crate::escape::csi::{
|
||||
DecPrivateMode, DecPrivateModeCode, Device, Mode, Sgr, Window, XtermKeyModifierResource,
|
||||
DecPrivateMode, DecPrivateModeCode, Device, Mode, Sgr, Window, XtSmGraphics,
|
||||
XtSmGraphicsItem, XtermKeyModifierResource,
|
||||
};
|
||||
use crate::escape::{EscCode, OneBased};
|
||||
use std::io::Write;
|
||||
@ -730,6 +731,14 @@ mod test {
|
||||
actions
|
||||
}
|
||||
|
||||
fn parse_as(s: &str, expected: &str) -> Vec<Action> {
|
||||
let mut p = Parser::new();
|
||||
let actions = p.parse_as_vec(s.as_bytes());
|
||||
println!("actions: {:?}", actions);
|
||||
assert_eq!(expected, encode(&actions));
|
||||
actions
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xterm_key() {
|
||||
assert_eq!(
|
||||
@ -764,6 +773,35 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dec_private_modes() {
|
||||
assert_eq!(
|
||||
parse_as("\x1b[?1;1006h", "\x1b[?1h\x1b[?1006h"),
|
||||
vec![
|
||||
Action::CSI(CSI::Mode(Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::ApplicationCursorKeys
|
||||
),))),
|
||||
Action::CSI(CSI::Mode(Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||
DecPrivateModeCode::SGRMouse
|
||||
),))),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xtsmgraphics() {
|
||||
assert_eq!(
|
||||
round_trip_parse("\x1b[?1;3;256S"),
|
||||
vec![Action::CSI(CSI::Device(Box::new(Device::XtSmGraphics(
|
||||
XtSmGraphics {
|
||||
item: XtSmGraphicsItem::NumberOfColorRegisters,
|
||||
action_or_status: 3,
|
||||
value: vec![256]
|
||||
}
|
||||
))))]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn req_attr() {
|
||||
assert_eq!(
|
||||
|
@ -353,7 +353,7 @@ impl FontConfigInner {
|
||||
}
|
||||
.show();
|
||||
} else {
|
||||
log::warn!(
|
||||
log::debug!(
|
||||
"No fonts contain glyphs for these codepoints: {}",
|
||||
fallback_str.escape_unicode()
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user