mirror of
https://github.com/wez/wezterm.git
synced 2024-12-27 07:18:13 +03:00
Adopt slice patterns for parsing CSI
This commit is contained in:
parent
2eefee4412
commit
12a839c4ac
@ -1,3 +1,5 @@
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate failure;
|
||||
#[macro_use]
|
||||
|
292
src/term/csi.rs
292
src/term/csi.rs
@ -1,3 +1,4 @@
|
||||
//! Parsing CSI escape sequences
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -14,125 +15,204 @@ pub enum CSIAction {
|
||||
SetInvisible(bool),
|
||||
}
|
||||
|
||||
impl CSIAction {
|
||||
/// Parses out a "Set Graphics Rendition" action.
|
||||
/// Returns the decoded action plus the unparsed remainder of the
|
||||
/// parameter stream. Returns None if we couldn't decode one of
|
||||
/// the parameter elements.
|
||||
pub fn parse_sgr(params: &[i64]) -> Option<(CSIAction, &[i64])> {
|
||||
if params.len() > 5 {
|
||||
// ISO-8613-6 foreground and background color specification
|
||||
// using full RGB color codes.
|
||||
if params[0] == 38 && params[1] == 2 {
|
||||
return Some((
|
||||
CSIAction::SetForegroundColor(
|
||||
color::ColorAttribute::Rgb(color::RgbColor {
|
||||
red: params[3] as u8,
|
||||
green: params[4] as u8,
|
||||
blue: params[5] as u8,
|
||||
}),
|
||||
),
|
||||
¶ms[6..],
|
||||
));
|
||||
}
|
||||
if params[0] == 48 && params[1] == 2 {
|
||||
return Some((
|
||||
CSIAction::SetBackgroundColor(
|
||||
color::ColorAttribute::Rgb(color::RgbColor {
|
||||
red: params[3] as u8,
|
||||
green: params[4] as u8,
|
||||
blue: params[5] as u8,
|
||||
}),
|
||||
),
|
||||
¶ms[6..],
|
||||
));
|
||||
}
|
||||
}
|
||||
if params.len() > 2 {
|
||||
// Some special look-ahead cases for 88 and 256 color support
|
||||
if params[0] == 38 && params[1] == 5 {
|
||||
// 38;5;IDX -> foreground color
|
||||
let color = color::ColorAttribute::PaletteIndex(params[2] as u8);
|
||||
return Some((CSIAction::SetForegroundColor(color), ¶ms[3..]));
|
||||
}
|
||||
pub struct CSIParser<'a> {
|
||||
intermediates: &'a [u8],
|
||||
ignore: bool,
|
||||
byte: char,
|
||||
params: Option<&'a [i64]>,
|
||||
}
|
||||
|
||||
if params[0] == 48 && params[1] == 5 {
|
||||
// 48;5;IDX -> background color
|
||||
let color = color::ColorAttribute::PaletteIndex(params[2] as u8);
|
||||
return Some((CSIAction::SetBackgroundColor(color), ¶ms[3..]));
|
||||
}
|
||||
impl<'a> CSIParser<'a> {
|
||||
pub fn new<'b>(
|
||||
params: &'b [i64],
|
||||
intermediates: &'b [u8],
|
||||
ignore: bool,
|
||||
byte: char,
|
||||
) -> CSIParser<'b> {
|
||||
CSIParser {
|
||||
intermediates,
|
||||
ignore,
|
||||
byte,
|
||||
params: Some(params),
|
||||
}
|
||||
}
|
||||
|
||||
let p = params[0];
|
||||
match p {
|
||||
0 => Some((CSIAction::SetPen(CellAttributes::default()), ¶ms[1..])),
|
||||
1 => Some((CSIAction::SetIntensity(Intensity::Bold), ¶ms[1..])),
|
||||
2 => Some((CSIAction::SetIntensity(Intensity::Half), ¶ms[1..])),
|
||||
3 => Some((CSIAction::SetItalic(true), ¶ms[1..])),
|
||||
4 => Some((CSIAction::SetUnderline(Underline::Single), ¶ms[1..])),
|
||||
5 => Some((CSIAction::SetBlink(true), ¶ms[1..])),
|
||||
7 => Some((CSIAction::SetReverse(true), ¶ms[1..])),
|
||||
8 => Some((CSIAction::SetInvisible(true), ¶ms[1..])),
|
||||
9 => Some((CSIAction::SetStrikethrough(true), ¶ms[1..])),
|
||||
21 => Some((CSIAction::SetUnderline(Underline::Double), ¶ms[1..])),
|
||||
22 => Some((CSIAction::SetIntensity(Intensity::Normal), ¶ms[1..])),
|
||||
23 => Some((CSIAction::SetItalic(false), ¶ms[1..])),
|
||||
24 => Some((CSIAction::SetUnderline(Underline::None), ¶ms[1..])),
|
||||
25 => Some((CSIAction::SetBlink(false), ¶ms[1..])),
|
||||
27 => Some((CSIAction::SetReverse(false), ¶ms[1..])),
|
||||
28 => Some((CSIAction::SetInvisible(false), ¶ms[1..])),
|
||||
29 => Some((CSIAction::SetStrikethrough(false), ¶ms[1..])),
|
||||
30...37 => {
|
||||
Some((
|
||||
CSIAction::SetForegroundColor(
|
||||
color::ColorAttribute::PaletteIndex(p as u8 - 30),
|
||||
),
|
||||
¶ms[1..],
|
||||
fn advance_by(&mut self, n: usize, params: &'a [i64]) {
|
||||
let (_, next) = params.split_at(n);
|
||||
if next.len() != 0 {
|
||||
self.params = Some(next);
|
||||
}
|
||||
}
|
||||
|
||||
fn next_sgr(&mut self, params: &'a [i64]) -> Option<CSIAction> {
|
||||
match params {
|
||||
&[] => {
|
||||
// With no parameters, reset to default pen.
|
||||
// Note that this empty case is only possible for the initial
|
||||
// iteration.
|
||||
Some(CSIAction::SetPen(CellAttributes::default()))
|
||||
}
|
||||
&[0, _..] => {
|
||||
// Explicitly set to default pen
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetPen(CellAttributes::default()))
|
||||
}
|
||||
&[38, 2, _, red, green, blue, _..] => {
|
||||
// ISO-8613-6 true color foreground
|
||||
self.advance_by(6, params);
|
||||
Some(CSIAction::SetForegroundColor(
|
||||
color::ColorAttribute::Rgb(color::RgbColor {
|
||||
red: red as u8,
|
||||
green: green as u8,
|
||||
blue: blue as u8,
|
||||
}),
|
||||
))
|
||||
}
|
||||
39 => {
|
||||
Some((
|
||||
CSIAction::SetForegroundColor(
|
||||
color::ColorAttribute::Foreground,
|
||||
),
|
||||
¶ms[1..],
|
||||
&[48, 2, _, red, green, blue, _..] => {
|
||||
// ISO-8613-6 true color background
|
||||
self.advance_by(6, params);
|
||||
Some(CSIAction::SetBackgroundColor(
|
||||
color::ColorAttribute::Rgb(color::RgbColor {
|
||||
red: red as u8,
|
||||
green: green as u8,
|
||||
blue: blue as u8,
|
||||
}),
|
||||
))
|
||||
}
|
||||
90...97 => {
|
||||
&[38, 5, idx, _..] => {
|
||||
// 256 color foreground color index
|
||||
self.advance_by(3, params);
|
||||
let color = color::ColorAttribute::PaletteIndex(idx as u8);
|
||||
Some(CSIAction::SetForegroundColor(color))
|
||||
}
|
||||
&[48, 5, idx, _..] => {
|
||||
// 256 color background color index
|
||||
self.advance_by(3, params);
|
||||
let color = color::ColorAttribute::PaletteIndex(idx as u8);
|
||||
Some(CSIAction::SetBackgroundColor(color))
|
||||
}
|
||||
&[1, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetIntensity(Intensity::Bold))
|
||||
}
|
||||
&[2, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetIntensity(Intensity::Half))
|
||||
}
|
||||
&[3, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetItalic(true))
|
||||
}
|
||||
&[4, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetUnderline(Underline::Single))
|
||||
}
|
||||
&[5, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetBlink(true))
|
||||
}
|
||||
&[7, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetReverse(true))
|
||||
}
|
||||
&[8, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetInvisible(true))
|
||||
}
|
||||
&[9, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetStrikethrough(true))
|
||||
}
|
||||
&[21, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetUnderline(Underline::Double))
|
||||
}
|
||||
&[22, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetIntensity(Intensity::Normal))
|
||||
}
|
||||
&[23, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetItalic(false))
|
||||
}
|
||||
&[24, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetUnderline(Underline::None))
|
||||
}
|
||||
&[25, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetBlink(false))
|
||||
}
|
||||
&[27, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetReverse(false))
|
||||
}
|
||||
&[28, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetInvisible(false))
|
||||
}
|
||||
&[29, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetStrikethrough(false))
|
||||
}
|
||||
&[idx @ 30...37, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetForegroundColor(
|
||||
color::ColorAttribute::PaletteIndex(idx as u8 - 30),
|
||||
))
|
||||
}
|
||||
&[39, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetForegroundColor(
|
||||
color::ColorAttribute::Foreground,
|
||||
))
|
||||
}
|
||||
&[idx @ 40...47, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetBackgroundColor(
|
||||
color::ColorAttribute::PaletteIndex(idx as u8 - 40),
|
||||
))
|
||||
}
|
||||
&[49, _..] => {
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetBackgroundColor(
|
||||
color::ColorAttribute::Background,
|
||||
))
|
||||
}
|
||||
&[idx @ 90...97, _..] => {
|
||||
// Bright foreground colors
|
||||
Some((
|
||||
CSIAction::SetForegroundColor(
|
||||
color::ColorAttribute::PaletteIndex(p as u8 - 90 + 8),
|
||||
),
|
||||
¶ms[1..],
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetForegroundColor(
|
||||
color::ColorAttribute::PaletteIndex(idx as u8 - 90 + 8),
|
||||
))
|
||||
}
|
||||
40...47 => {
|
||||
Some((
|
||||
CSIAction::SetBackgroundColor(
|
||||
color::ColorAttribute::PaletteIndex(p as u8 - 40),
|
||||
),
|
||||
¶ms[1..],
|
||||
))
|
||||
}
|
||||
49 => {
|
||||
Some((
|
||||
CSIAction::SetBackgroundColor(
|
||||
color::ColorAttribute::Background,
|
||||
),
|
||||
¶ms[1..],
|
||||
))
|
||||
}
|
||||
100...107 => {
|
||||
&[idx @ 100...107, _..] => {
|
||||
// Bright background colors
|
||||
Some((
|
||||
CSIAction::SetBackgroundColor(
|
||||
color::ColorAttribute::PaletteIndex(p as u8 - 100 + 8),
|
||||
),
|
||||
¶ms[1..],
|
||||
self.advance_by(1, params);
|
||||
Some(CSIAction::SetBackgroundColor(
|
||||
color::ColorAttribute::PaletteIndex(idx as u8 - 100 + 8),
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
_ => {
|
||||
println!("parse_sgr: unhandled csi sequence {:?}", params);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for CSIParser<'a> {
|
||||
type Item = CSIAction;
|
||||
|
||||
fn next(&mut self) -> Option<CSIAction> {
|
||||
let params = self.params.take();
|
||||
match (self.byte, params) {
|
||||
(_, None) => None,
|
||||
('m', Some(params)) => self.next_sgr(params),
|
||||
(b, Some(p)) => {
|
||||
println!("unhandled {} {:?}", b, p);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -514,58 +514,37 @@ impl vte::Perform for TerminalState {
|
||||
fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: char) {
|
||||
match byte {
|
||||
'm' => {
|
||||
let mut params = params;
|
||||
|
||||
if params.len() == 0 {
|
||||
// Empty parameter list means to reset the attributes to default
|
||||
self.pen = CellAttributes::default();
|
||||
}
|
||||
|
||||
while params.len() > 0 {
|
||||
match CSIAction::parse_sgr(params) {
|
||||
Some((CSIAction::SetPen(pen), remainder)) => {
|
||||
for act in CSIParser::new(params, intermediates, ignore, byte) {
|
||||
match act {
|
||||
CSIAction::SetPen(pen) => {
|
||||
self.pen = pen;
|
||||
params = remainder;
|
||||
}
|
||||
Some((CSIAction::SetForegroundColor(color), remainder)) => {
|
||||
CSIAction::SetForegroundColor(color) => {
|
||||
self.pen.foreground = color;
|
||||
params = remainder;
|
||||
}
|
||||
Some((CSIAction::SetBackgroundColor(color), remainder)) => {
|
||||
CSIAction::SetBackgroundColor(color) => {
|
||||
self.pen.background = color;
|
||||
params = remainder;
|
||||
}
|
||||
Some((CSIAction::SetIntensity(level), remainder)) => {
|
||||
CSIAction::SetIntensity(level) => {
|
||||
self.pen.set_intensity(level);
|
||||
params = remainder;
|
||||
}
|
||||
Some((CSIAction::SetUnderline(level), remainder)) => {
|
||||
CSIAction::SetUnderline(level) => {
|
||||
self.pen.set_underline(level);
|
||||
params = remainder;
|
||||
}
|
||||
Some((CSIAction::SetItalic(on), remainder)) => {
|
||||
CSIAction::SetItalic(on) => {
|
||||
self.pen.set_italic(on);
|
||||
params = remainder;
|
||||
}
|
||||
Some((CSIAction::SetBlink(on), remainder)) => {
|
||||
CSIAction::SetBlink(on) => {
|
||||
self.pen.set_blink(on);
|
||||
params = remainder;
|
||||
}
|
||||
Some((CSIAction::SetReverse(on), remainder)) => {
|
||||
CSIAction::SetReverse(on) => {
|
||||
self.pen.set_reverse(on);
|
||||
params = remainder;
|
||||
}
|
||||
Some((CSIAction::SetStrikethrough(on), remainder)) => {
|
||||
CSIAction::SetStrikethrough(on) => {
|
||||
self.pen.set_strikethrough(on);
|
||||
params = remainder;
|
||||
}
|
||||
Some((CSIAction::SetInvisible(on), remainder)) => {
|
||||
CSIAction::SetInvisible(on) => {
|
||||
self.pen.set_invisible(on);
|
||||
params = remainder;
|
||||
}
|
||||
None => {
|
||||
println!("parse_sgr: unhandled sequence {:?}", params);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user