mirror of
https://github.com/wez/wezterm.git
synced 2024-12-24 22:01:47 +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) => {
|
Ok(size) => {
|
||||||
parser.parse(&buf[0..size], |action| {
|
parser.parse(&buf[0..size], |action| {
|
||||||
|
let mut flush = false;
|
||||||
match &action {
|
match &action {
|
||||||
Action::CSI(CSI::Mode(Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
Action::CSI(CSI::Mode(Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||||
DecPrivateModeCode::SynchronizedOutput,
|
DecPrivateModeCode::SynchronizedOutput,
|
||||||
)))) => {
|
)))) => {
|
||||||
hold = true;
|
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(
|
Action::CSI(CSI::Mode(Mode::ResetDecPrivateMode(
|
||||||
DecPrivateMode::Code(DecPrivateModeCode::SynchronizedOutput),
|
DecPrivateMode::Code(DecPrivateModeCode::SynchronizedOutput),
|
||||||
))) => {
|
))) => {
|
||||||
hold = false;
|
hold = false;
|
||||||
|
flush = true;
|
||||||
}
|
}
|
||||||
Action::CSI(CSI::Device(dev)) if matches!(**dev, Device::SoftReset) => {
|
Action::CSI(CSI::Device(dev)) if matches!(**dev, Device::SoftReset) => {
|
||||||
hold = false;
|
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 {
|
if !actions.is_empty() && !hold {
|
||||||
send_actions_to_mux(pane_id, dead, std::mem::take(&mut actions));
|
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::imageops::FilterType;
|
||||||
use image::ImageFormat;
|
use image::ImageFormat;
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Write;
|
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) {
|
fn perform_csi_mode(&mut self, mode: Mode) {
|
||||||
match mode {
|
match mode {
|
||||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||||
@ -1877,6 +1908,11 @@ impl TerminalState {
|
|||||||
| Mode::ResetDecPrivateMode(DecPrivateMode::Code(
|
| Mode::ResetDecPrivateMode(DecPrivateMode::Code(
|
||||||
DecPrivateModeCode::StartBlinkingCursor,
|
DecPrivateModeCode::StartBlinkingCursor,
|
||||||
)) => {}
|
)) => {}
|
||||||
|
Mode::QueryDecPrivateMode(DecPrivateMode::Code(
|
||||||
|
DecPrivateModeCode::StartBlinkingCursor,
|
||||||
|
)) => {
|
||||||
|
self.decqrm_response(mode, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::AutoRepeat))
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::AutoRepeat))
|
||||||
| Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::AutoRepeat)) => {
|
| Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::AutoRepeat)) => {
|
||||||
@ -1895,6 +1931,12 @@ impl TerminalState {
|
|||||||
self.reverse_wraparound_mode = false;
|
self.reverse_wraparound_mode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Mode::QueryDecPrivateMode(DecPrivateMode::Code(
|
||||||
|
DecPrivateModeCode::ReverseWraparound,
|
||||||
|
)) => {
|
||||||
|
self.decqrm_response(mode, true, self.reverse_wraparound_mode);
|
||||||
|
}
|
||||||
|
|
||||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||||
DecPrivateModeCode::LeftRightMarginMode,
|
DecPrivateModeCode::LeftRightMarginMode,
|
||||||
)) => {
|
)) => {
|
||||||
@ -1908,6 +1950,12 @@ impl TerminalState {
|
|||||||
self.left_and_right_margins = 0..self.screen().physical_cols;
|
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)) => {
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SaveCursor)) => {
|
||||||
self.dec_save_cursor();
|
self.dec_save_cursor();
|
||||||
}
|
}
|
||||||
@ -1924,6 +1972,10 @@ impl TerminalState {
|
|||||||
self.dec_auto_wrap = false;
|
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)) => {
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::OriginMode)) => {
|
||||||
self.dec_origin_mode = true;
|
self.dec_origin_mode = true;
|
||||||
self.set_cursor_pos(&Position::Absolute(0), &Position::Absolute(0));
|
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));
|
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(
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||||
DecPrivateModeCode::UsePrivateColorRegistersForEachGraphic,
|
DecPrivateModeCode::UsePrivateColorRegistersForEachGraphic,
|
||||||
)) => {
|
)) => {
|
||||||
@ -1944,6 +2000,15 @@ impl TerminalState {
|
|||||||
)) => {
|
)) => {
|
||||||
self.use_private_color_registers_for_each_graphic = false;
|
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(
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||||
DecPrivateModeCode::SynchronizedOutput,
|
DecPrivateModeCode::SynchronizedOutput,
|
||||||
@ -1955,6 +2020,13 @@ impl TerminalState {
|
|||||||
)) => {
|
)) => {
|
||||||
// This is handled in wezterm's mux
|
// 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::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SmoothScroll))
|
||||||
| Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SmoothScroll)) => {
|
| Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SmoothScroll)) => {
|
||||||
@ -1988,6 +2060,9 @@ impl TerminalState {
|
|||||||
Mode::ResetMode(TerminalMode::Code(TerminalModeCode::Insert)) => {
|
Mode::ResetMode(TerminalMode::Code(TerminalModeCode::Insert)) => {
|
||||||
self.insert = false;
|
self.insert = false;
|
||||||
}
|
}
|
||||||
|
Mode::QueryMode(TerminalMode::Code(TerminalModeCode::Insert)) => {
|
||||||
|
self.decqrm_response(mode, true, self.insert);
|
||||||
|
}
|
||||||
|
|
||||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::BracketedPaste)) => {
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::BracketedPaste)) => {
|
||||||
self.bracketed_paste = true;
|
self.bracketed_paste = true;
|
||||||
@ -1995,6 +2070,9 @@ impl TerminalState {
|
|||||||
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::BracketedPaste)) => {
|
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::BracketedPaste)) => {
|
||||||
self.bracketed_paste = false;
|
self.bracketed_paste = false;
|
||||||
}
|
}
|
||||||
|
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::BracketedPaste)) => {
|
||||||
|
self.decqrm_response(mode, true, self.bracketed_paste);
|
||||||
|
}
|
||||||
|
|
||||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||||
DecPrivateModeCode::OptEnableAlternateScreen,
|
DecPrivateModeCode::OptEnableAlternateScreen,
|
||||||
@ -2036,6 +2114,11 @@ impl TerminalState {
|
|||||||
)) => {
|
)) => {
|
||||||
self.application_cursor_keys = false;
|
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)) => {
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SixelScrolling)) => {
|
||||||
self.sixel_scrolling = true;
|
self.sixel_scrolling = true;
|
||||||
@ -2043,6 +2126,9 @@ impl TerminalState {
|
|||||||
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SixelScrolling)) => {
|
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SixelScrolling)) => {
|
||||||
self.sixel_scrolling = false;
|
self.sixel_scrolling = false;
|
||||||
}
|
}
|
||||||
|
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SixelScrolling)) => {
|
||||||
|
self.decqrm_response(mode, true, self.sixel_scrolling);
|
||||||
|
}
|
||||||
|
|
||||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::DecAnsiMode)) => {
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::DecAnsiMode)) => {
|
||||||
self.dec_ansi_mode = true;
|
self.dec_ansi_mode = true;
|
||||||
@ -2050,6 +2136,9 @@ impl TerminalState {
|
|||||||
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::DecAnsiMode)) => {
|
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::DecAnsiMode)) => {
|
||||||
self.dec_ansi_mode = false;
|
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)) => {
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::ShowCursor)) => {
|
||||||
self.cursor_visible = true;
|
self.cursor_visible = true;
|
||||||
@ -2057,6 +2146,9 @@ impl TerminalState {
|
|||||||
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::ShowCursor)) => {
|
Mode::ResetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::ShowCursor)) => {
|
||||||
self.cursor_visible = false;
|
self.cursor_visible = false;
|
||||||
}
|
}
|
||||||
|
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::ShowCursor)) => {
|
||||||
|
self.decqrm_response(mode, true, self.cursor_visible);
|
||||||
|
}
|
||||||
Mode::SetMode(TerminalMode::Code(TerminalModeCode::ShowCursor)) => {
|
Mode::SetMode(TerminalMode::Code(TerminalModeCode::ShowCursor)) => {
|
||||||
self.cursor_visible = true;
|
self.cursor_visible = true;
|
||||||
}
|
}
|
||||||
@ -2072,6 +2164,9 @@ impl TerminalState {
|
|||||||
self.mouse_tracking = false;
|
self.mouse_tracking = false;
|
||||||
self.last_mouse_move.take();
|
self.last_mouse_move.take();
|
||||||
}
|
}
|
||||||
|
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::MouseTracking)) => {
|
||||||
|
self.decqrm_response(mode, true, self.mouse_tracking);
|
||||||
|
}
|
||||||
|
|
||||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||||
DecPrivateModeCode::HighlightMouseTracking,
|
DecPrivateModeCode::HighlightMouseTracking,
|
||||||
@ -2090,6 +2185,11 @@ impl TerminalState {
|
|||||||
self.button_event_mouse = false;
|
self.button_event_mouse = false;
|
||||||
self.last_mouse_move.take();
|
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)) => {
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::AnyEventMouse)) => {
|
||||||
self.any_event_mouse = true;
|
self.any_event_mouse = true;
|
||||||
@ -2099,6 +2199,9 @@ impl TerminalState {
|
|||||||
self.any_event_mouse = false;
|
self.any_event_mouse = false;
|
||||||
self.last_mouse_move.take();
|
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)) => {
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::FocusTracking)) => {
|
||||||
self.focus_tracking = true;
|
self.focus_tracking = true;
|
||||||
@ -2108,6 +2211,9 @@ impl TerminalState {
|
|||||||
self.focus_tracking = false;
|
self.focus_tracking = false;
|
||||||
self.last_mouse_move.take();
|
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)) => {
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SGRMouse)) => {
|
||||||
self.sgr_mouse = true;
|
self.sgr_mouse = true;
|
||||||
@ -2117,6 +2223,9 @@ impl TerminalState {
|
|||||||
self.sgr_mouse = false;
|
self.sgr_mouse = false;
|
||||||
self.last_mouse_move.take();
|
self.last_mouse_move.take();
|
||||||
}
|
}
|
||||||
|
Mode::QueryDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SGRMouse)) => {
|
||||||
|
self.decqrm_response(mode, true, self.sgr_mouse);
|
||||||
|
}
|
||||||
|
|
||||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||||
DecPrivateModeCode::SixelScrollsRight,
|
DecPrivateModeCode::SixelScrollsRight,
|
||||||
@ -2128,6 +2237,11 @@ impl TerminalState {
|
|||||||
)) => {
|
)) => {
|
||||||
self.sixel_scrolls_right = false;
|
self.sixel_scrolls_right = false;
|
||||||
}
|
}
|
||||||
|
Mode::QueryDecPrivateMode(DecPrivateMode::Code(
|
||||||
|
DecPrivateModeCode::SixelScrollsRight,
|
||||||
|
)) => {
|
||||||
|
self.decqrm_response(mode, true, self.sixel_scrolls_right);
|
||||||
|
}
|
||||||
|
|
||||||
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
Mode::SetDecPrivateMode(DecPrivateMode::Code(
|
||||||
DecPrivateModeCode::ClearAndEnableAlternateScreen,
|
DecPrivateModeCode::ClearAndEnableAlternateScreen,
|
||||||
@ -2153,25 +2267,24 @@ impl TerminalState {
|
|||||||
log::warn!("save/restore dec mode {:?} unimplemented", n)
|
log::warn!("save/restore dec mode {:?} unimplemented", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
Mode::SetDecPrivateMode(DecPrivateMode::Unspecified(n))
|
Mode::SetDecPrivateMode(DecPrivateMode::Unspecified(_))
|
||||||
| Mode::ResetDecPrivateMode(DecPrivateMode::Unspecified(n))
|
| Mode::ResetDecPrivateMode(DecPrivateMode::Unspecified(_))
|
||||||
| Mode::SaveDecPrivateMode(DecPrivateMode::Unspecified(n))
|
| Mode::SaveDecPrivateMode(DecPrivateMode::Unspecified(_))
|
||||||
| Mode::RestoreDecPrivateMode(DecPrivateMode::Unspecified(n)) => {
|
| Mode::RestoreDecPrivateMode(DecPrivateMode::Unspecified(_)) => {
|
||||||
log::warn!("unhandled DecPrivateMode {}", n);
|
log::warn!("unhandled DecPrivateMode {:?}", mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mode::SetMode(TerminalMode::Unspecified(n))
|
mode @ Mode::SetMode(_) | mode @ Mode::ResetMode(_) => {
|
||||||
| Mode::ResetMode(TerminalMode::Unspecified(n)) => {
|
log::warn!("unhandled {:?}", mode);
|
||||||
log::warn!("unhandled TerminalMode {}", n);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mode::SetMode(m) | Mode::ResetMode(m) => {
|
|
||||||
log::warn!("unhandled TerminalMode {:?}", m);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mode::XtermKeyMode { resource, value } => {
|
Mode::XtermKeyMode { resource, value } => {
|
||||||
log::warn!("unhandled 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, ()> {
|
pub fn parse(params: &[CsiParam]) -> Result<CSI, ()> {
|
||||||
|
let params = Cracked::parse(¶ms[1..])?;
|
||||||
Ok(CSI::Device(Box::new(Device::XtSmGraphics(XtSmGraphics {
|
Ok(CSI::Device(Box::new(Device::XtSmGraphics(XtSmGraphics {
|
||||||
item: match params.get(0).ok_or(())? {
|
item: match params.get(0).ok_or(())? {
|
||||||
CsiParam::Integer(1) => XtSmGraphicsItem::NumberOfColorRegisters,
|
CsiParam::Integer(1) => XtSmGraphicsItem::NumberOfColorRegisters,
|
||||||
@ -259,10 +260,10 @@ impl XtSmGraphics {
|
|||||||
CsiParam::Integer(n) => *n,
|
CsiParam::Integer(n) => *n,
|
||||||
_ => return Err(()),
|
_ => return Err(()),
|
||||||
},
|
},
|
||||||
value: params[2..]
|
value: params.params[2..]
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|p| match p {
|
.filter_map(|p| match p {
|
||||||
CsiParam::Integer(n) => Some(*n),
|
Some(CsiParam::Integer(n)) => Some(*n),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
@ -561,8 +562,10 @@ pub enum Mode {
|
|||||||
ResetDecPrivateMode(DecPrivateMode),
|
ResetDecPrivateMode(DecPrivateMode),
|
||||||
SaveDecPrivateMode(DecPrivateMode),
|
SaveDecPrivateMode(DecPrivateMode),
|
||||||
RestoreDecPrivateMode(DecPrivateMode),
|
RestoreDecPrivateMode(DecPrivateMode),
|
||||||
|
QueryDecPrivateMode(DecPrivateMode),
|
||||||
SetMode(TerminalMode),
|
SetMode(TerminalMode),
|
||||||
ResetMode(TerminalMode),
|
ResetMode(TerminalMode),
|
||||||
|
QueryMode(TerminalMode),
|
||||||
XtermKeyMode {
|
XtermKeyMode {
|
||||||
resource: XtermKeyModifierResource,
|
resource: XtermKeyModifierResource,
|
||||||
value: Option<i64>,
|
value: Option<i64>,
|
||||||
@ -594,8 +597,18 @@ impl Display for Mode {
|
|||||||
Mode::ResetDecPrivateMode(mode) => emit!("l", mode),
|
Mode::ResetDecPrivateMode(mode) => emit!("l", mode),
|
||||||
Mode::SaveDecPrivateMode(mode) => emit!("s", mode),
|
Mode::SaveDecPrivateMode(mode) => emit!("s", mode),
|
||||||
Mode::RestoreDecPrivateMode(mode) => emit!("r", 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::SetMode(mode) => emit_mode!("h", mode),
|
||||||
Mode::ResetMode(mode) => emit_mode!("l", 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 } => {
|
Mode::XtermKeyMode { resource, value } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -1378,6 +1391,7 @@ struct CSIParser<'a> {
|
|||||||
/// default values, especially for SGR, so we need to be careful not
|
/// default values, especially for SGR, so we need to be careful not
|
||||||
/// to update params to an empty slice.
|
/// to update params to an empty slice.
|
||||||
params: Option<&'a [CsiParam]>,
|
params: Option<&'a [CsiParam]>,
|
||||||
|
orig_params: &'a [CsiParam],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSI {
|
impl CSI {
|
||||||
@ -1396,6 +1410,7 @@ impl CSI {
|
|||||||
parameters_truncated,
|
parameters_truncated,
|
||||||
control,
|
control,
|
||||||
params: Some(params),
|
params: Some(params),
|
||||||
|
orig_params: params,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1502,7 +1517,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, params) {
|
match (self.control, self.orig_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),
|
||||||
|
|
||||||
@ -1522,76 +1537,82 @@ impl<'a> CSIParser<'a> {
|
|||||||
.map(|dev| CSI::Device(Box::new(dev))),
|
.map(|dev| CSI::Device(Box::new(dev))),
|
||||||
|
|
||||||
('S', [CsiParam::P(b'?'), ..]) => XtSmGraphics::parse(params),
|
('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
|
('h', [CsiParam::P(b'?'), ..]) => self
|
||||||
.dec(params)
|
.dec(self.focus(params, 1, 0))
|
||||||
.map(|mode| CSI::Mode(Mode::SetDecPrivateMode(mode))),
|
.map(|mode| CSI::Mode(Mode::SetDecPrivateMode(mode))),
|
||||||
('l', [CsiParam::P(b'?'), ..]) => self
|
('l', [CsiParam::P(b'?'), ..]) => self
|
||||||
.dec(params)
|
.dec(self.focus(params, 1, 0))
|
||||||
.map(|mode| CSI::Mode(Mode::ResetDecPrivateMode(mode))),
|
.map(|mode| CSI::Mode(Mode::ResetDecPrivateMode(mode))),
|
||||||
('r', [CsiParam::P(b'?'), ..]) => self
|
('r', [CsiParam::P(b'?'), ..]) => self
|
||||||
.dec(params)
|
.dec(self.focus(params, 1, 0))
|
||||||
.map(|mode| CSI::Mode(Mode::RestoreDecPrivateMode(mode))),
|
.map(|mode| CSI::Mode(Mode::RestoreDecPrivateMode(mode))),
|
||||||
('q', [CsiParam::P(b'>'), ..]) => self
|
('q', [CsiParam::P(b'>'), ..]) => self
|
||||||
.req_terminal_name_and_version(params)
|
.req_terminal_name_and_version(params)
|
||||||
.map(|dev| CSI::Device(Box::new(dev))),
|
.map(|dev| CSI::Device(Box::new(dev))),
|
||||||
('s', [CsiParam::P(b'?'), ..]) => self
|
('s', [CsiParam::P(b'?'), ..]) => self
|
||||||
.dec(params)
|
.dec(self.focus(params, 1, 0))
|
||||||
.map(|mode| CSI::Mode(Mode::SaveDecPrivateMode(mode))),
|
.map(|mode| CSI::Mode(Mode::SaveDecPrivateMode(mode))),
|
||||||
('m', [CsiParam::P(b'>'), ..]) => self.xterm_key_modifier(params),
|
('m', [CsiParam::P(b'>'), ..]) => self.xterm_key_modifier(params),
|
||||||
|
|
||||||
('p', [CsiParam::P(b'!')]) => Ok(CSI::Device(Box::new(Device::SoftReset))),
|
('p', [CsiParam::P(b'!')]) => Ok(CSI::Device(Box::new(Device::SoftReset))),
|
||||||
|
|
||||||
('c', _) => self
|
_ => match self.control {
|
||||||
.req_primary_device_attributes(params)
|
'c' => self
|
||||||
.map(|dev| CSI::Device(Box::new(dev))),
|
.req_primary_device_attributes(params)
|
||||||
|
.map(|dev| CSI::Device(Box::new(dev))),
|
||||||
|
|
||||||
('@', _) => parse!(Edit, InsertCharacter, params),
|
'@' => parse!(Edit, InsertCharacter, params),
|
||||||
('`', _) => parse!(Cursor, CharacterPositionAbsolute, params),
|
'`' => parse!(Cursor, CharacterPositionAbsolute, params),
|
||||||
('A', _) => parse!(Cursor, Up, params),
|
'A' => parse!(Cursor, Up, params),
|
||||||
('B', _) => parse!(Cursor, Down, params),
|
'B' => parse!(Cursor, Down, params),
|
||||||
('C', _) => parse!(Cursor, Right, params),
|
'C' => parse!(Cursor, Right, params),
|
||||||
('D', _) => parse!(Cursor, Left, params),
|
'D' => parse!(Cursor, Left, params),
|
||||||
('E', _) => parse!(Cursor, NextLine, params),
|
'E' => parse!(Cursor, NextLine, params),
|
||||||
('F', _) => parse!(Cursor, PrecedingLine, params),
|
'F' => parse!(Cursor, PrecedingLine, params),
|
||||||
('G', _) => parse!(Cursor, CharacterAbsolute, params),
|
'G' => parse!(Cursor, CharacterAbsolute, params),
|
||||||
('H', _) => parse!(Cursor, Position, line, col, params),
|
'H' => parse!(Cursor, Position, line, col, params),
|
||||||
('I', _) => parse!(Cursor, ForwardTabulation, params),
|
'I' => parse!(Cursor, ForwardTabulation, params),
|
||||||
('J', _) => parse!(Edit, EraseInDisplay, params),
|
'J' => parse!(Edit, EraseInDisplay, params),
|
||||||
('K', _) => parse!(Edit, EraseInLine, params),
|
'K' => parse!(Edit, EraseInLine, params),
|
||||||
('L', _) => parse!(Edit, InsertLine, params),
|
'L' => parse!(Edit, InsertLine, params),
|
||||||
('M', _) => parse!(Edit, DeleteLine, params),
|
'M' => parse!(Edit, DeleteLine, params),
|
||||||
('P', _) => parse!(Edit, DeleteCharacter, params),
|
'P' => parse!(Edit, DeleteCharacter, params),
|
||||||
('R', _) => parse!(Cursor, ActivePositionReport, line, col, params),
|
'R' => parse!(Cursor, ActivePositionReport, line, col, params),
|
||||||
('S', _) => parse!(Edit, ScrollUp, params),
|
'S' => parse!(Edit, ScrollUp, params),
|
||||||
('T', _) => parse!(Edit, ScrollDown, params),
|
'T' => parse!(Edit, ScrollDown, params),
|
||||||
('W', _) => parse!(Cursor, TabulationControl, params),
|
'W' => parse!(Cursor, TabulationControl, params),
|
||||||
('X', _) => parse!(Edit, EraseCharacter, params),
|
'X' => parse!(Edit, EraseCharacter, params),
|
||||||
('Y', _) => parse!(Cursor, LineTabulation, params),
|
'Y' => parse!(Cursor, LineTabulation, params),
|
||||||
('Z', _) => parse!(Cursor, BackwardTabulation, params),
|
'Z' => parse!(Cursor, BackwardTabulation, params),
|
||||||
|
|
||||||
('a', _) => parse!(Cursor, CharacterPositionForward, params),
|
'a' => parse!(Cursor, CharacterPositionForward, params),
|
||||||
('b', _) => parse!(Edit, Repeat, params),
|
'b' => parse!(Edit, Repeat, params),
|
||||||
('d', _) => parse!(Cursor, LinePositionAbsolute, params),
|
'd' => parse!(Cursor, LinePositionAbsolute, params),
|
||||||
('e', _) => parse!(Cursor, LinePositionForward, params),
|
'e' => parse!(Cursor, LinePositionForward, params),
|
||||||
('f', _) => parse!(Cursor, CharacterAndLinePosition, line, col, params),
|
'f' => parse!(Cursor, CharacterAndLinePosition, line, col, params),
|
||||||
('g', _) => parse!(Cursor, TabulationClear, params),
|
'g' => parse!(Cursor, TabulationClear, params),
|
||||||
('h', _) => self
|
'h' => self
|
||||||
.terminal_mode(params)
|
.terminal_mode(params)
|
||||||
.map(|mode| CSI::Mode(Mode::SetMode(mode))),
|
.map(|mode| CSI::Mode(Mode::SetMode(mode))),
|
||||||
('j', _) => parse!(Cursor, CharacterPositionBackward, params),
|
'j' => parse!(Cursor, CharacterPositionBackward, params),
|
||||||
('k', _) => parse!(Cursor, LinePositionBackward, params),
|
'k' => parse!(Cursor, LinePositionBackward, params),
|
||||||
('l', _) => self
|
'l' => self
|
||||||
.terminal_mode(params)
|
.terminal_mode(params)
|
||||||
.map(|mode| CSI::Mode(Mode::ResetMode(mode))),
|
.map(|mode| CSI::Mode(Mode::ResetMode(mode))),
|
||||||
|
|
||||||
('m', _) => self.sgr(params).map(CSI::Sgr),
|
'm' => self.sgr(params).map(CSI::Sgr),
|
||||||
('n', _) => self.dsr(params),
|
'n' => self.dsr(params),
|
||||||
('r', _) => self.decstbm(params),
|
'r' => self.decstbm(params),
|
||||||
('s', _) => self.decslrm(params),
|
's' => self.decslrm(params),
|
||||||
('t', _) => self.window(params).map(CSI::Window),
|
't' => self.window(params).map(CSI::Window),
|
||||||
('u', _) => noparams!(Cursor, RestoreCursor, params),
|
'u' => noparams!(Cursor, RestoreCursor, params),
|
||||||
|
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1613,6 +1634,15 @@ impl<'a> CSIParser<'a> {
|
|||||||
result
|
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, ()> {
|
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) {
|
||||||
@ -1755,10 +1785,10 @@ impl<'a> CSIParser<'a> {
|
|||||||
|
|
||||||
fn req_terminal_name_and_version(&mut self, params: &'a [CsiParam]) -> Result<Device, ()> {
|
fn req_terminal_name_and_version(&mut self, params: &'a [CsiParam]) -> Result<Device, ()> {
|
||||||
match params {
|
match params {
|
||||||
[] => Ok(Device::RequestTerminalNameAndVersion),
|
[_] => Ok(Device::RequestTerminalNameAndVersion),
|
||||||
|
|
||||||
[CsiParam::Integer(0)] => {
|
[_, CsiParam::Integer(0)] => {
|
||||||
Ok(self.advance_by(1, params, Device::RequestTerminalNameAndVersion))
|
Ok(self.advance_by(2, params, Device::RequestTerminalNameAndVersion))
|
||||||
}
|
}
|
||||||
_ => Err(()),
|
_ => 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, ()> {
|
fn dec(&mut self, params: &'a [CsiParam]) -> Result<DecPrivateMode, ()> {
|
||||||
match params {
|
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(
|
None => Ok(self.advance_by(
|
||||||
2,
|
1,
|
||||||
params,
|
params,
|
||||||
DecPrivateMode::Unspecified(p0.to_u16().ok_or(())?),
|
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(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
|
@ -429,7 +429,8 @@ 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, XtermKeyModifierResource,
|
DecPrivateMode, DecPrivateModeCode, Device, Mode, Sgr, Window, XtSmGraphics,
|
||||||
|
XtSmGraphicsItem, XtermKeyModifierResource,
|
||||||
};
|
};
|
||||||
use crate::escape::{EscCode, OneBased};
|
use crate::escape::{EscCode, OneBased};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@ -730,6 +731,14 @@ mod test {
|
|||||||
actions
|
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]
|
#[test]
|
||||||
fn xterm_key() {
|
fn xterm_key() {
|
||||||
assert_eq!(
|
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]
|
#[test]
|
||||||
fn req_attr() {
|
fn req_attr() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -353,7 +353,7 @@ impl FontConfigInner {
|
|||||||
}
|
}
|
||||||
.show();
|
.show();
|
||||||
} else {
|
} else {
|
||||||
log::warn!(
|
log::debug!(
|
||||||
"No fonts contain glyphs for these codepoints: {}",
|
"No fonts contain glyphs for these codepoints: {}",
|
||||||
fallback_str.escape_unicode()
|
fallback_str.escape_unicode()
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user