1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-22 22:42:48 +03:00

termwiz: allow setting alpha for SGR fg, bg attributes

This commit extends the sgr color parser to support a wezterm
extension that I just made up:

```
printf "\e[48:4:255:0:0:60mhello\e0m"
```

The `4` is wezterm specific and denotes 4 channel color, in this case
RGBA. red is 255, green is 0, blue is 0 and alpha is 60; the values are
interpreted as u8 values.

CSI 38 (fg), 48 (bg) and 58 (underline) support this.

refs: https://github.com/wez/wezterm/issues/2313
This commit is contained in:
Wez Furlong 2022-07-26 21:01:44 -07:00
parent bc083ee470
commit 6e9a22e199
2 changed files with 99 additions and 30 deletions

View File

@ -1,6 +1,6 @@
use super::OneBased;
use crate::cell::{Blink, Intensity, Underline};
use crate::color::{AnsiColor, ColorSpec, RgbColor};
use crate::color::{AnsiColor, ColorSpec, RgbColor, SrgbaTuple};
use crate::input::{Modifiers, MouseButtons};
use num_derive::*;
use num_traits::{FromPrimitive, ToPrimitive};
@ -1435,15 +1435,27 @@ impl Display for Sgr {
(White, ForegroundBrightWhite)
),
Sgr::Foreground(ColorSpec::TrueColor(c)) => {
let (red, green, blue, _alpha) = c.to_srgb_u8();
write!(
f,
"{}:2::{}:{}:{}m",
SgrCode::ForegroundColor as i64,
red,
green,
blue
)?
let (red, green, blue, alpha) = c.to_srgb_u8();
if alpha == 255 {
write!(
f,
"{}:2::{}:{}:{}m",
SgrCode::ForegroundColor as i64,
red,
green,
blue
)?
} else {
write!(
f,
"{}:4::{}:{}:{}:{}m",
SgrCode::ForegroundColor as i64,
red,
green,
blue,
alpha
)?
}
}
Sgr::Background(ColorSpec::PaletteIndex(idx)) => ansi_color!(
*idx,
@ -1469,27 +1481,51 @@ impl Display for Sgr {
(White, BackgroundBrightWhite)
),
Sgr::Background(ColorSpec::TrueColor(c)) => {
let (red, green, blue, _alpha) = c.to_srgb_u8();
write!(
f,
"{}:2::{}:{}:{}m",
SgrCode::BackgroundColor as i64,
red,
green,
blue
)?
let (red, green, blue, alpha) = c.to_srgb_u8();
if alpha == 255 {
write!(
f,
"{}:2::{}:{}:{}m",
SgrCode::BackgroundColor as i64,
red,
green,
blue
)?
} else {
write!(
f,
"{}:4::{}:{}:{}:{}m",
SgrCode::BackgroundColor as i64,
red,
green,
blue,
alpha
)?
}
}
Sgr::UnderlineColor(ColorSpec::Default) => code!(ResetUnderlineColor),
Sgr::UnderlineColor(ColorSpec::TrueColor(c)) => {
let (red, green, blue, _alpha) = c.to_srgb_u8();
write!(
f,
"{}:2::{}:{}:{}m",
SgrCode::UnderlineColor as i64,
red,
green,
blue
)?
let (red, green, blue, alpha) = c.to_srgb_u8();
if alpha == 255 {
write!(
f,
"{}:2::{}:{}:{}m",
SgrCode::UnderlineColor as i64,
red,
green,
blue
)?
} else {
write!(
f,
"{}:4::{}:{}:{}:{}m",
SgrCode::UnderlineColor as i64,
red,
green,
blue,
alpha
)?
}
}
Sgr::UnderlineColor(ColorSpec::PaletteIndex(idx)) => {
write!(f, "{}:5:{}m", SgrCode::UnderlineColor as i64, *idx)?
@ -2203,9 +2239,31 @@ impl<'a> CSIParser<'a> {
fn parse_sgr_color(&mut self, params: &'a [CsiParam]) -> Result<ColorSpec, ()> {
match params {
// wezterm extension to support an optional alpha channel in the `:` form only
[_, CsiParam::P(b':'), CsiParam::Integer(4), CsiParam::P(b':'),
CsiParam::Integer(_colorspace), CsiParam::P(b':'),
red, CsiParam::P(b':'), green, CsiParam::P(b':'), blue, CsiParam::P(b':'), alpha, ..] => {
let res: SrgbaTuple = (to_u8(red)?, to_u8(green)?, to_u8(blue)?, to_u8(alpha)?).into();
Ok(self.advance_by(13, params, res.into()))
}
[_, CsiParam::P(b':'), CsiParam::Integer(4), CsiParam::P(b':'),
/* empty colorspace */ CsiParam::P(b':'),
red, CsiParam::P(b':'), green, CsiParam::P(b':'), blue, CsiParam::P(b':'), alpha, ..] => {
let res: SrgbaTuple = (to_u8(red)?, to_u8(green)?, to_u8(blue)?, to_u8(alpha)?).into();
Ok(self.advance_by(12, params, res.into()))
}
[_, CsiParam::P(b':'), CsiParam::Integer(4), CsiParam::P(b':'), red, CsiParam::P(b':'), green,
CsiParam::P(b':'), blue, CsiParam::P(b':'), alpha, ..] =>
{
let res: SrgbaTuple = (to_u8(red)?, to_u8(green)?, to_u8(blue)?, to_u8(alpha)?).into();
Ok(self.advance_by(11, params, res.into()))
}
// standard sgr colors
[_, CsiParam::P(b':'), CsiParam::Integer(2), CsiParam::P(b':'),
CsiParam::Integer(_colorspace), CsiParam::P(b':'),
red, CsiParam::P(b':'), green, CsiParam::P(b':'), blue, ..] => {
CsiParam::Integer(_colorspace), CsiParam::P(b':'),
red, CsiParam::P(b':'), green, CsiParam::P(b':'), blue, ..] => {
let res = RgbColor::new_8bpc(to_u8(red)?, to_u8(green)?, to_u8(blue)?).into();
Ok(self.advance_by(11, params, res))
}

View File

@ -452,6 +452,17 @@ mod test {
],
actions
);
let actions = p.parse_as_vec(b"\x1b[38:4:0:255:0:127mw");
assert_eq!(
vec![
Action::CSI(CSI::Sgr(Sgr::Foreground(ColorSpec::TrueColor(
(0, 255, 0, 127).into()
)))),
Action::Print('w'),
],
actions
);
}
#[test]