1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

tighten up SGR parsing

Track all the rendition bits described in the SGR section here:
https://invisible-island.net/xterm/ctlseqs/ctlseqs.html

Still need to hook up color matching against the color palette
as described for the 256 color mode flavor.
This commit is contained in:
Wez Furlong 2018-01-25 10:05:57 -08:00
parent 3ec0b3f795
commit b56209a181

View File

@ -51,18 +51,52 @@ macro_rules! bitfield {
self.attributes = (self.attributes & clear) | attr_value; self.attributes = (self.attributes & clear) | attr_value;
} }
}; };
($getter:ident, $setter:ident, $enum:ident, $bitmask:expr, $bitshift:expr) => {
#[inline]
#[allow(dead_code)]
pub fn $getter(&self) -> $enum {
unsafe { std::mem::transmute(((self.attributes >> $bitshift) & $bitmask) as u16)}
}
#[inline]
#[allow(dead_code)]
pub fn $setter(&mut self, value: $enum) {
let value = value as u16;
let clear = !($bitmask << $bitshift);
let attr_value = (value & $bitmask) << $bitshift;
self.attributes = (self.attributes & clear) | attr_value;
}
};
} }
#[derive(Debug, Clone, Copy)]
#[repr(u16)]
pub enum Intensity {
Normal = 0,
Bold = 1,
Half = 2,
}
#[derive(Debug, Clone, Copy)]
#[repr(u16)]
pub enum Underline {
None = 0,
Single = 1,
Double = 2,
}
impl CellAttributes { impl CellAttributes {
bitfield!(bold, set_bold, 0); bitfield!(intensity, set_intensity, Intensity, 0b11, 0);
bitfield!(underline, set_underline, 1); bitfield!(underline, set_underline, Underline, 0b1100, 2);
bitfield!(italic, set_italic, 2); bitfield!(italic, set_italic, 4);
bitfield!(blink, set_blink, 3); bitfield!(blink, set_blink, 5);
bitfield!(reverse, set_reverse, 4); bitfield!(reverse, set_reverse, 6);
bitfield!(strikethrough, set_strikethrough, 5); bitfield!(strikethrough, set_strikethrough, 7);
bitfield!(halfbright, set_halfbright, 8);
bitfield!(invisible, set_invisible, 9);
// Allow up to 8 different font values // Allow up to 8 different font values
bitfield!(font, set_font, 0b111000000, 6); //bitfield!(font, set_font, 0b111000000, 6);
} }
impl Default for CellAttributes { impl Default for CellAttributes {
@ -335,6 +369,115 @@ impl Terminal {
} }
} }
enum CSIAction {
SetPen(CellAttributes),
SetForegroundColor(color::ColorAttribute),
SetBackgroundColor(color::ColorAttribute),
SetIntensity(Intensity),
SetUnderline(Underline),
SetItalic(bool),
SetBlink(bool),
SetReverse(bool),
SetStrikethrough(bool),
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.
fn parse_sgr(params: &[i64]) -> Option<(CSIAction, &[i64])> {
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), &params[3..]));
}
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), &params[3..]));
}
}
let p = params[0];
match p {
0 => Some((CSIAction::SetPen(CellAttributes::default()), &params[1..])),
1 => Some((CSIAction::SetIntensity(Intensity::Bold), &params[1..])),
2 => Some((CSIAction::SetIntensity(Intensity::Half), &params[1..])),
3 => Some((CSIAction::SetItalic(true), &params[1..])),
4 => Some((CSIAction::SetUnderline(Underline::Single), &params[1..])),
5 => Some((CSIAction::SetBlink(true), &params[1..])),
7 => Some((CSIAction::SetReverse(true), &params[1..])),
8 => Some((CSIAction::SetInvisible(true), &params[1..])),
9 => Some((CSIAction::SetStrikethrough(true), &params[1..])),
21 => Some((CSIAction::SetUnderline(Underline::Double), &params[1..])),
22 => Some((CSIAction::SetIntensity(Intensity::Normal), &params[1..])),
23 => Some((CSIAction::SetItalic(false), &params[1..])),
24 => Some((CSIAction::SetUnderline(Underline::None), &params[1..])),
25 => Some((CSIAction::SetBlink(false), &params[1..])),
27 => Some((CSIAction::SetReverse(false), &params[1..])),
28 => Some((CSIAction::SetInvisible(false), &params[1..])),
29 => Some((CSIAction::SetStrikethrough(false), &params[1..])),
30...37 => {
Some((
CSIAction::SetForegroundColor(
color::ColorAttribute::PaletteIndex(p as u8 - 30),
),
&params[1..],
))
}
39 => {
Some((
CSIAction::SetForegroundColor(
color::ColorAttribute::Foreground,
),
&params[1..],
))
}
90...97 => {
// Bright foreground colors
Some((
CSIAction::SetForegroundColor(
color::ColorAttribute::PaletteIndex(p as u8 - 90 + 8),
),
&params[1..],
))
}
40...47 => {
Some((
CSIAction::SetBackgroundColor(
color::ColorAttribute::PaletteIndex(p as u8 - 40),
),
&params[1..],
))
}
49 => {
Some((
CSIAction::SetBackgroundColor(
color::ColorAttribute::Background,
),
&params[1..],
))
}
100...107 => {
// Bright background colors
Some((
CSIAction::SetBackgroundColor(
color::ColorAttribute::PaletteIndex(p as u8 - 100 + 8),
),
&params[1..],
))
}
_ => None,
}
}
}
impl vte::Perform for TerminalState { impl vte::Perform for TerminalState {
/// Draw a character to the screen /// Draw a character to the screen
fn print(&mut self, c: char) { fn print(&mut self, c: char) {
@ -373,37 +516,53 @@ impl vte::Perform for TerminalState {
); );
match byte { match byte {
'm' => { 'm' => {
// Set Graphic Rendition let mut params = params;
for p in params { while params.len() > 0 {
match p { match CSIAction::parse_sgr(params) {
&0 => { Some((CSIAction::SetPen(pen), remainder)) => {
self.pen = CellAttributes::default(); self.pen = pen;
params = remainder;
} }
&30...37 => { Some((CSIAction::SetForegroundColor(color), remainder)) => {
self.pen.foreground = self.pen.foreground = color;
color::ColorAttribute::PaletteIndex(*p as u8 - 30); params = remainder;
} }
&39 => { Some((CSIAction::SetBackgroundColor(color), remainder)) => {
self.pen.foreground = color::ColorAttribute::Foreground; self.pen.background = color;
params = remainder;
} }
&90...97 => { Some((CSIAction::SetIntensity(level), remainder)) => {
// Bright foreground colors self.pen.set_intensity(level);
self.pen.foreground = params = remainder;
color::ColorAttribute::PaletteIndex(*p as u8 - 90 + 8);
} }
&40...47 => { Some((CSIAction::SetUnderline(level), remainder)) => {
self.pen.background = self.pen.set_underline(level);
color::ColorAttribute::PaletteIndex(*p as u8 - 40); params = remainder;
} }
&49 => { Some((CSIAction::SetItalic(on), remainder)) => {
self.pen.background = color::ColorAttribute::Foreground; self.pen.set_italic(on);
params = remainder;
} }
&100...107 => { Some((CSIAction::SetBlink(on), remainder)) => {
// Bright background colors self.pen.set_blink(on);
self.pen.background = params = remainder;
color::ColorAttribute::PaletteIndex(*p as u8 - 100 + 8); }
Some((CSIAction::SetReverse(on), remainder)) => {
self.pen.set_reverse(on);
params = remainder;
}
Some((CSIAction::SetStrikethrough(on), remainder)) => {
self.pen.set_strikethrough(on);
params = remainder;
}
Some((CSIAction::SetInvisible(on), remainder)) => {
self.pen.set_invisible(on);
params = remainder;
}
None => {
println!("parse_sgr: unhandled sequence {:?}", params);
break;
} }
_ => {}
} }
} }
} }