1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-27 12:23:46 +03:00

termwiz: add flag to force use of standard ANSI SGR codes

With a TERM of "screen-256color" or "screen", common attributes such
as bold are rendered with a \x0f AKA ^O AKA \017 code that
makes pagers such as less and streampager grumpy. In particular,
streampager renders as inverted "<0F>" and less as inverted "^O".

Add a new flag force_terminfo_render_to_use_ansi_sgr which makes the
TerminfoRenderer ignore the terminfo entries for common attributes,
instead using the standard ANSI/ECMA-48 sequences.
This commit is contained in:
Muir Manders 2022-09-21 16:23:38 -07:00 committed by Wez Furlong
parent f898c15c9b
commit 1dcec5e5ae
2 changed files with 68 additions and 5 deletions

View File

@ -107,6 +107,13 @@ builder! {
/// Whether mouse support is present and should be used
mouse_reporting: Option<bool>,
/// When true, rather than using the terminfo `sgr` or `sgr0` entries,
/// assume that the terminal is ANSI/ECMA-48 compliant for the
/// common SGR attributes of bold, dim, reverse, underline, blink,
/// invisible and reset, and directly emit those sequences.
/// This can improve rendered text compatibility with pagers.
force_terminfo_render_to_use_ansi_sgr: Option<bool>,
}
}
@ -154,6 +161,7 @@ pub struct Capabilities {
terminfo_db: Option<terminfo::Database>,
bracketed_paste: bool,
mouse_reporting: bool,
force_terminfo_render_to_use_ansi_sgr: bool,
}
impl Capabilities {
@ -282,6 +290,9 @@ impl Capabilities {
let bracketed_paste = hints.bracketed_paste.unwrap_or(true);
let mouse_reporting = hints.mouse_reporting.unwrap_or(true);
let force_terminfo_render_to_use_ansi_sgr =
hints.force_terminfo_render_to_use_ansi_sgr.unwrap_or(false);
Ok(Self {
color_level,
sixel,
@ -291,6 +302,7 @@ impl Capabilities {
terminfo_db,
bracketed_paste,
mouse_reporting,
force_terminfo_render_to_use_ansi_sgr,
})
}
@ -336,6 +348,12 @@ impl Capabilities {
pub fn mouse_reporting(&self) -> bool {
self.mouse_reporting
}
/// Whether to emit standard ANSI/ECMA-48 codes, overriding any
/// SGR terminfo capabilities.
pub fn force_terminfo_render_to_use_ansi_sgr(&self) -> bool {
self.force_terminfo_render_to_use_ansi_sgr
}
}
#[cfg(test)]

View File

@ -50,13 +50,18 @@ impl TerminfoRenderer {
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cognitive_complexity))]
fn flush_pending_attr<W: RenderTty + Write>(&mut self, out: &mut W) -> Result<()> {
macro_rules! attr_on {
($cap:ident, $sgr:expr) => {
if let Some(attr) = self.get_capability::<cap::$cap>() {
($cap:ident, $sgr:expr) => {{
let cap = if self.caps.force_terminfo_render_to_use_ansi_sgr() {
None
} else {
self.get_capability::<cap::$cap>()
};
if let Some(attr) = cap {
attr.expand().to(out.by_ref())?;
} else {
write!(out, "{}", CSI::Sgr($sgr))?;
}
};
}};
($sgr:expr) => {
write!(out, "{}", CSI::Sgr($sgr))?;
};
@ -71,8 +76,13 @@ impl TerminfoRenderer {
current_foreground = ColorAttribute::Default;
current_background = ColorAttribute::Default;
let sgr = if self.caps.force_terminfo_render_to_use_ansi_sgr() {
None
} else {
self.get_capability::<cap::SetAttributes>()
};
// The SetAttributes capability can only handle single underline and slow blink.
if let Some(sgr) = self.get_capability::<cap::SetAttributes>() {
if let Some(sgr) = sgr {
sgr.expand()
.bold(attr.intensity() == Intensity::Bold)
.dim(attr.intensity() == Intensity::Half)
@ -706,10 +716,14 @@ mod test {
/// Return Capabilities loaded from the included xterm terminfo data
fn xterm_terminfo() -> Capabilities {
xterm_terminfo_with_hints(ProbeHints::default())
}
fn xterm_terminfo_with_hints(hints: ProbeHints) -> Capabilities {
// Load our own compiled data so that the tests have an
// environment that doesn't vary machine by machine.
let data = include_bytes!("../../data/xterm-256color");
Capabilities::new_with_hints(ProbeHints::default().terminfo_db(Some(
Capabilities::new_with_hints(hints.terminfo_db(Some(
terminfo::Database::from_buffer(data.as_ref()).unwrap(),
)))
.unwrap()
@ -915,6 +929,37 @@ mod test {
);
}
#[test]
// Sanity that force_terminfo_render_to_use_ansi_sgr does something.
fn bold_text_force_ansi_sgr() {
let mut out = FakeTerm::new(xterm_terminfo_with_hints(
ProbeHints::default().force_terminfo_render_to_use_ansi_sgr(Some(true)),
));
out.render(&[
Change::Text("not ".into()),
AttributeChange::Intensity(Intensity::Bold).into(),
Change::Text("foo".into()),
])
.unwrap();
let result = out.parse();
assert_eq!(
result,
vec![
// Same as bold_text() above, but without the "(B" from srg/sgr0.
Action::Print('n'),
Action::Print('o'),
Action::Print('t'),
Action::Print(' '),
Action::CSI(CSI::Sgr(Sgr::Reset)),
Action::CSI(CSI::Sgr(Sgr::Intensity(Intensity::Bold))),
Action::Print('f'),
Action::Print('o'),
Action::Print('o'),
],
);
}
#[test]
fn clear_screen() {
let mut out = FakeTerm::new_with_size(xterm_terminfo(), 4, 3);