mirror of
https://github.com/wez/wezterm.git
synced 2024-12-18 19:01:36 +03:00
simplify the terminfo renderer code a little by reducing macro usage
This commit is contained in:
parent
4090417b29
commit
5ac675bb5b
@ -12,7 +12,7 @@ use termwiz::terminal::{Terminal, UnixTerminal};
|
|||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
let caps = Capabilities::new_from_env()?;
|
let caps = Capabilities::new_from_env()?;
|
||||||
let renderer = TerminfoRenderer::new(caps);
|
let mut renderer = TerminfoRenderer::new(caps);
|
||||||
|
|
||||||
let mut terminal = UnixTerminal::new()?;
|
let mut terminal = UnixTerminal::new()?;
|
||||||
terminal.set_raw_mode()?;
|
terminal.set_raw_mode()?;
|
||||||
|
@ -21,7 +21,7 @@ pub trait Renderer {
|
|||||||
/// value in on subsequent calls to maintain the running view of the
|
/// value in on subsequent calls to maintain the running view of the
|
||||||
/// attributes.
|
/// attributes.
|
||||||
fn render_to(
|
fn render_to(
|
||||||
&self,
|
&mut self,
|
||||||
starting_attr: &CellAttributes,
|
starting_attr: &CellAttributes,
|
||||||
changes: &[Change],
|
changes: &[Change],
|
||||||
out: &mut Terminal,
|
out: &mut Terminal,
|
||||||
|
@ -14,16 +14,220 @@ use terminfo::{capability as cap, Capability as TermInfoCapability};
|
|||||||
|
|
||||||
pub struct TerminfoRenderer {
|
pub struct TerminfoRenderer {
|
||||||
caps: Capabilities,
|
caps: Capabilities,
|
||||||
|
current_attr: CellAttributes,
|
||||||
|
pending_attr: Option<CellAttributes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminfoRenderer {
|
impl TerminfoRenderer {
|
||||||
pub fn new(caps: Capabilities) -> Self {
|
pub fn new(caps: Capabilities) -> Self {
|
||||||
Self { caps }
|
Self {
|
||||||
|
caps,
|
||||||
|
current_attr: CellAttributes::default(),
|
||||||
|
pending_attr: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_capability<'a, T: TermInfoCapability<'a>>(&'a self) -> Option<T> {
|
fn get_capability<'a, T: TermInfoCapability<'a>>(&'a self) -> Option<T> {
|
||||||
self.caps.terminfo_db().and_then(|db| db.get::<T>())
|
self.caps.terminfo_db().and_then(|db| db.get::<T>())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn attr_apply<F: FnOnce(&mut CellAttributes)>(&mut self, func: F) {
|
||||||
|
self.pending_attr = Some(match self.pending_attr.take() {
|
||||||
|
Some(mut attr) => {
|
||||||
|
func(&mut attr);
|
||||||
|
attr
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let mut attr = self.current_attr.clone();
|
||||||
|
func(&mut attr);
|
||||||
|
attr
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_pending_attr(&mut self, out: &mut Terminal) -> Result<(), failure::Error> {
|
||||||
|
macro_rules! attr_on_off {
|
||||||
|
($cap_on:ident, $cap_off:ident, $attr:expr, $accesor:ident, $sgr:ident) => {
|
||||||
|
let value = $attr.$accesor();
|
||||||
|
if value != self.current_attr.$accesor() {
|
||||||
|
let mut out = WriteWrapper::new(out);
|
||||||
|
let on: bool = value.into();
|
||||||
|
if on {
|
||||||
|
if let Some(attr) = self.get_capability::<cap::$cap_on>() {
|
||||||
|
attr.expand().to(out)?;
|
||||||
|
} else {
|
||||||
|
CSI::Sgr(Sgr::$sgr(value)).encode_escape(&mut out)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(attr) = self.get_capability::<cap::$cap_off>() {
|
||||||
|
attr.expand().to(out)?;
|
||||||
|
} else {
|
||||||
|
CSI::Sgr(Sgr::$sgr(value)).encode_escape(&mut out)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(attr) = self.pending_attr.take() {
|
||||||
|
if !attr.attribute_bits_equal(&self.current_attr) {
|
||||||
|
if let Some(sgr) = self.get_capability::<cap::SetAttributes>() {
|
||||||
|
sgr.expand()
|
||||||
|
.bold(attr.intensity() == Intensity::Bold)
|
||||||
|
.dim(attr.intensity() == Intensity::Half)
|
||||||
|
.underline(attr.underline() != Underline::None)
|
||||||
|
.blink(attr.blink() != Blink::None)
|
||||||
|
.reverse(attr.reverse())
|
||||||
|
.invisible(attr.invisible())
|
||||||
|
.to(WriteWrapper::new(out))?;
|
||||||
|
} else {
|
||||||
|
if let Some(exit) = self.get_capability::<cap::ExitAttributeMode>() {
|
||||||
|
exit.expand().to(WriteWrapper::new(out))?;
|
||||||
|
} else {
|
||||||
|
CSI::Sgr(Sgr::Reset).encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if attr.intensity() != self.current_attr.intensity() {
|
||||||
|
match attr.intensity() {
|
||||||
|
Intensity::Bold => {
|
||||||
|
if let Some(bold) = self.get_capability::<cap::EnterBoldMode>() {
|
||||||
|
bold.expand().to(WriteWrapper::new(out))?;
|
||||||
|
} else {
|
||||||
|
CSI::Sgr(Sgr::Intensity(attr.intensity()))
|
||||||
|
.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Intensity::Half => {
|
||||||
|
if let Some(dim) = self.get_capability::<cap::EnterDimMode>() {
|
||||||
|
dim.expand().to(WriteWrapper::new(out))?;
|
||||||
|
} else {
|
||||||
|
CSI::Sgr(Sgr::Intensity(attr.intensity()))
|
||||||
|
.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attr_on_off!(
|
||||||
|
EnterUnderlineMode,
|
||||||
|
ExitUnderlineMode,
|
||||||
|
attr,
|
||||||
|
underline,
|
||||||
|
Underline
|
||||||
|
);
|
||||||
|
|
||||||
|
attr_on_off!(
|
||||||
|
EnterUnderlineMode,
|
||||||
|
ExitUnderlineMode,
|
||||||
|
attr,
|
||||||
|
underline,
|
||||||
|
Underline
|
||||||
|
);
|
||||||
|
|
||||||
|
if attr.blink() != self.current_attr.blink() {
|
||||||
|
if let Some(attr) = self.get_capability::<cap::EnterBlinkMode>() {
|
||||||
|
attr.expand().to(WriteWrapper::new(out))?;
|
||||||
|
} else {
|
||||||
|
CSI::Sgr(Sgr::Blink(attr.blink()))
|
||||||
|
.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if attr.reverse() != self.current_attr.reverse() {
|
||||||
|
if let Some(attr) = self.get_capability::<cap::EnterReverseMode>() {
|
||||||
|
attr.expand().to(WriteWrapper::new(out))?;
|
||||||
|
} else {
|
||||||
|
CSI::Sgr(Sgr::Inverse(attr.reverse()))
|
||||||
|
.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if attr.invisible() != self.current_attr.invisible() {
|
||||||
|
CSI::Sgr(Sgr::Invisible(attr.invisible()))
|
||||||
|
.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attr_on_off!(EnterItalicsMode, ExitItalicsMode, attr, italic, Italic);
|
||||||
|
|
||||||
|
// TODO: add strikethrough to Capabilities
|
||||||
|
if attr.strikethrough() != self.current_attr.strikethrough() {
|
||||||
|
CSI::Sgr(Sgr::StrikeThrough(attr.strikethrough()))
|
||||||
|
.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let has_true_color = self.caps.color_level() == ColorLevel::TrueColor;
|
||||||
|
|
||||||
|
if attr.foreground != self.current_attr.foreground {
|
||||||
|
match (has_true_color, attr.foreground) {
|
||||||
|
(true, ColorAttribute::TrueColorWithPaletteFallback(tc, _))
|
||||||
|
| (true, ColorAttribute::TrueColorWithDefaultFallback(tc)) => {
|
||||||
|
CSI::Sgr(Sgr::Foreground(ColorSpec::TrueColor(tc)))
|
||||||
|
.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
(false, ColorAttribute::TrueColorWithDefaultFallback(_))
|
||||||
|
| (_, ColorAttribute::Default) => {
|
||||||
|
// Terminfo doesn't define a reset color to default, so
|
||||||
|
// we use the ANSI code.
|
||||||
|
CSI::Sgr(Sgr::Foreground(ColorSpec::Default))
|
||||||
|
.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
(false, ColorAttribute::TrueColorWithPaletteFallback(_, idx))
|
||||||
|
| (_, ColorAttribute::PaletteIndex(idx)) => {
|
||||||
|
if let Some(set) = self.get_capability::<cap::SetAForeground>() {
|
||||||
|
set.expand().color(idx).to(WriteWrapper::new(out))?;
|
||||||
|
} else {
|
||||||
|
CSI::Sgr(Sgr::Foreground(ColorSpec::PaletteIndex(idx)))
|
||||||
|
.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if attr.background != self.current_attr.background {
|
||||||
|
match (has_true_color, attr.background) {
|
||||||
|
(true, ColorAttribute::TrueColorWithPaletteFallback(tc, _))
|
||||||
|
| (true, ColorAttribute::TrueColorWithDefaultFallback(tc)) => {
|
||||||
|
CSI::Sgr(Sgr::Background(ColorSpec::TrueColor(tc)))
|
||||||
|
.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
(false, ColorAttribute::TrueColorWithDefaultFallback(_))
|
||||||
|
| (_, ColorAttribute::Default) => {
|
||||||
|
// Terminfo doesn't define a reset color to default, so
|
||||||
|
// we use the ANSI code.
|
||||||
|
CSI::Sgr(Sgr::Background(ColorSpec::Default))
|
||||||
|
.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
(false, ColorAttribute::TrueColorWithPaletteFallback(_, idx))
|
||||||
|
| (_, ColorAttribute::PaletteIndex(idx)) => {
|
||||||
|
if let Some(set) = self.get_capability::<cap::SetABackground>() {
|
||||||
|
set.expand().color(idx).to(WriteWrapper::new(out))?;
|
||||||
|
} else {
|
||||||
|
CSI::Sgr(Sgr::Background(ColorSpec::PaletteIndex(idx)))
|
||||||
|
.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.caps.hyperlinks() {
|
||||||
|
if let Some(link) = attr.hyperlink.as_ref() {
|
||||||
|
let osc = OperatingSystemCommand::SetHyperlink(Some((**link).clone()));
|
||||||
|
osc.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
} else if self.current_attr.hyperlink.is_some() {
|
||||||
|
// Close out the old hyperlink
|
||||||
|
let osc = OperatingSystemCommand::SetHyperlink(None);
|
||||||
|
osc.encode_escape(&mut WriteWrapper::new(out))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current_attr = attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The terminfo crate wants us to move the Write instance in on
|
// The terminfo crate wants us to move the Write instance in on
|
||||||
@ -51,229 +255,22 @@ impl<'a> Write for WriteWrapper<'a> {
|
|||||||
|
|
||||||
impl Renderer for TerminfoRenderer {
|
impl Renderer for TerminfoRenderer {
|
||||||
fn render_to(
|
fn render_to(
|
||||||
&self,
|
&mut self,
|
||||||
start_attr: &CellAttributes,
|
start_attr: &CellAttributes,
|
||||||
changes: &[Change],
|
changes: &[Change],
|
||||||
out: &mut Terminal,
|
out: &mut Terminal,
|
||||||
) -> Result<CellAttributes, failure::Error> {
|
) -> Result<CellAttributes, failure::Error> {
|
||||||
let mut current_attr = start_attr.clone();
|
self.current_attr = start_attr.clone();
|
||||||
let mut pending_attr: Option<CellAttributes> = None;
|
self.pending_attr = None;
|
||||||
|
|
||||||
macro_rules! attr_apply {
|
|
||||||
($apply:expr) => {
|
|
||||||
pending_attr = Some(match pending_attr {
|
|
||||||
Some(mut attr) => {
|
|
||||||
$apply(&mut attr);
|
|
||||||
attr
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let mut attr = current_attr.clone();
|
|
||||||
$apply(&mut attr);
|
|
||||||
attr
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
macro_rules! record {
|
macro_rules! record {
|
||||||
($accesor:ident, $value:expr) => {
|
($accesor:ident, $value:expr) => {
|
||||||
attr_apply!(|attr: &mut CellAttributes| {
|
self.attr_apply(|attr| {
|
||||||
attr.$accesor(*$value);
|
attr.$accesor(*$value);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! attr_on_off {
|
|
||||||
($cap_on:ident, $cap_off:ident, $attr:expr, $accesor:ident, $sgr:ident) => {
|
|
||||||
let value = $attr.$accesor();
|
|
||||||
if value != current_attr.$accesor() {
|
|
||||||
let mut out = WriteWrapper::new(out);
|
|
||||||
let on: bool = value.into();
|
|
||||||
if on {
|
|
||||||
if let Some(attr) = self.get_capability::<cap::$cap_on>() {
|
|
||||||
attr.expand().to(out)?;
|
|
||||||
} else {
|
|
||||||
CSI::Sgr(Sgr::$sgr(value)).encode_escape(&mut out)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if let Some(attr) = self.get_capability::<cap::$cap_off>() {
|
|
||||||
attr.expand().to(out)?;
|
|
||||||
} else {
|
|
||||||
CSI::Sgr(Sgr::$sgr(value)).encode_escape(&mut out)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! flush_pending_attr {
|
|
||||||
() => {
|
|
||||||
if let Some(attr) = pending_attr.take() {
|
|
||||||
if !attr.attribute_bits_equal(¤t_attr) {
|
|
||||||
if let Some(sgr) = self.get_capability::<cap::SetAttributes>() {
|
|
||||||
sgr.expand()
|
|
||||||
.bold(attr.intensity() == Intensity::Bold)
|
|
||||||
.dim(attr.intensity() == Intensity::Half)
|
|
||||||
.underline(attr.underline() != Underline::None)
|
|
||||||
.blink(attr.blink() != Blink::None)
|
|
||||||
.reverse(attr.reverse())
|
|
||||||
.invisible(attr.invisible())
|
|
||||||
.to(WriteWrapper::new(out))?;
|
|
||||||
} else {
|
|
||||||
if let Some(exit) = self.get_capability::<cap::ExitAttributeMode>()
|
|
||||||
{
|
|
||||||
exit.expand().to(WriteWrapper::new(out))?;
|
|
||||||
} else {
|
|
||||||
CSI::Sgr(Sgr::Reset)
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if attr.intensity() != current_attr.intensity() {
|
|
||||||
match attr.intensity() {
|
|
||||||
Intensity::Bold => if let Some(bold) =
|
|
||||||
self.get_capability::<cap::EnterBoldMode>()
|
|
||||||
{
|
|
||||||
bold.expand().to(WriteWrapper::new(out))?;
|
|
||||||
} else {
|
|
||||||
CSI::Sgr(Sgr::Intensity(attr.intensity()))
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
},
|
|
||||||
Intensity::Half => if let Some(dim) =
|
|
||||||
self.get_capability::<cap::EnterDimMode>()
|
|
||||||
{
|
|
||||||
dim.expand().to(WriteWrapper::new(out))?;
|
|
||||||
} else {
|
|
||||||
CSI::Sgr(Sgr::Intensity(attr.intensity()))
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attr_on_off!(
|
|
||||||
EnterUnderlineMode,
|
|
||||||
ExitUnderlineMode,
|
|
||||||
attr,
|
|
||||||
underline,
|
|
||||||
Underline
|
|
||||||
);
|
|
||||||
|
|
||||||
attr_on_off!(
|
|
||||||
EnterUnderlineMode,
|
|
||||||
ExitUnderlineMode,
|
|
||||||
attr,
|
|
||||||
underline,
|
|
||||||
Underline
|
|
||||||
);
|
|
||||||
|
|
||||||
if attr.blink() != current_attr.blink() {
|
|
||||||
if let Some(attr) = self.get_capability::<cap::EnterBlinkMode>()
|
|
||||||
{
|
|
||||||
attr.expand().to(WriteWrapper::new(out))?;
|
|
||||||
} else {
|
|
||||||
CSI::Sgr(Sgr::Blink(attr.blink()))
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if attr.reverse() != current_attr.reverse() {
|
|
||||||
if let Some(attr) =
|
|
||||||
self.get_capability::<cap::EnterReverseMode>()
|
|
||||||
{
|
|
||||||
attr.expand().to(WriteWrapper::new(out))?;
|
|
||||||
} else {
|
|
||||||
CSI::Sgr(Sgr::Inverse(attr.reverse()))
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if attr.invisible() != current_attr.invisible() {
|
|
||||||
CSI::Sgr(Sgr::Invisible(attr.invisible()))
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attr_on_off!(EnterItalicsMode, ExitItalicsMode, attr, italic, Italic);
|
|
||||||
|
|
||||||
// TODO: add strikethrough to Capabilities
|
|
||||||
if attr.strikethrough() != current_attr.strikethrough() {
|
|
||||||
CSI::Sgr(Sgr::StrikeThrough(attr.strikethrough()))
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let has_true_color = self.caps.color_level() == ColorLevel::TrueColor;
|
|
||||||
|
|
||||||
if attr.foreground != current_attr.foreground {
|
|
||||||
match (has_true_color, attr.foreground) {
|
|
||||||
(true, ColorAttribute::TrueColorWithPaletteFallback(tc, _))
|
|
||||||
| (true, ColorAttribute::TrueColorWithDefaultFallback(tc)) => {
|
|
||||||
CSI::Sgr(Sgr::Foreground(ColorSpec::TrueColor(tc)))
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
}
|
|
||||||
(false, ColorAttribute::TrueColorWithDefaultFallback(_))
|
|
||||||
| (_, ColorAttribute::Default) => {
|
|
||||||
// Terminfo doesn't define a reset color to default, so
|
|
||||||
// we use the ANSI code.
|
|
||||||
CSI::Sgr(Sgr::Foreground(ColorSpec::Default))
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
}
|
|
||||||
(false, ColorAttribute::TrueColorWithPaletteFallback(_, idx))
|
|
||||||
| (_, ColorAttribute::PaletteIndex(idx)) => {
|
|
||||||
if let Some(set) = self.get_capability::<cap::SetAForeground>()
|
|
||||||
{
|
|
||||||
set.expand().color(idx).to(WriteWrapper::new(out))?;
|
|
||||||
} else {
|
|
||||||
CSI::Sgr(Sgr::Foreground(ColorSpec::PaletteIndex(idx)))
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if attr.background != current_attr.background {
|
|
||||||
match (has_true_color, attr.background) {
|
|
||||||
(true, ColorAttribute::TrueColorWithPaletteFallback(tc, _))
|
|
||||||
| (true, ColorAttribute::TrueColorWithDefaultFallback(tc)) => {
|
|
||||||
CSI::Sgr(Sgr::Background(ColorSpec::TrueColor(tc)))
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
}
|
|
||||||
(false, ColorAttribute::TrueColorWithDefaultFallback(_))
|
|
||||||
| (_, ColorAttribute::Default) => {
|
|
||||||
// Terminfo doesn't define a reset color to default, so
|
|
||||||
// we use the ANSI code.
|
|
||||||
CSI::Sgr(Sgr::Background(ColorSpec::Default))
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
}
|
|
||||||
(false, ColorAttribute::TrueColorWithPaletteFallback(_, idx))
|
|
||||||
| (_, ColorAttribute::PaletteIndex(idx)) => {
|
|
||||||
if let Some(set) = self.get_capability::<cap::SetABackground>()
|
|
||||||
{
|
|
||||||
set.expand().color(idx).to(WriteWrapper::new(out))?;
|
|
||||||
} else {
|
|
||||||
CSI::Sgr(Sgr::Background(ColorSpec::PaletteIndex(idx)))
|
|
||||||
.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.caps.hyperlinks() {
|
|
||||||
if let Some(link) = attr.hyperlink.as_ref() {
|
|
||||||
let osc =
|
|
||||||
OperatingSystemCommand::SetHyperlink(Some((**link).clone()));
|
|
||||||
osc.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
} else if current_attr.hyperlink.is_some() {
|
|
||||||
// Close out the old hyperlink
|
|
||||||
let osc = OperatingSystemCommand::SetHyperlink(None);
|
|
||||||
osc.encode_escape(&mut WriteWrapper::new(out))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current_attr = attr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for change in changes {
|
for change in changes {
|
||||||
match change {
|
match change {
|
||||||
Change::ClearScreen(color) => {
|
Change::ClearScreen(color) => {
|
||||||
@ -281,13 +278,13 @@ impl Renderer for TerminfoRenderer {
|
|||||||
let defaults = CellAttributes::default()
|
let defaults = CellAttributes::default()
|
||||||
.set_background(color.clone())
|
.set_background(color.clone())
|
||||||
.clone();
|
.clone();
|
||||||
if current_attr != defaults {
|
if self.current_attr != defaults {
|
||||||
pending_attr = Some(defaults);
|
self.pending_attr = Some(defaults);
|
||||||
flush_pending_attr!();
|
self.flush_pending_attr(out)?;
|
||||||
}
|
}
|
||||||
pending_attr = None;
|
self.pending_attr = None;
|
||||||
|
|
||||||
if current_attr.background == ColorAttribute::Default || self.caps.bce() {
|
if self.current_attr.background == ColorAttribute::Default || self.caps.bce() {
|
||||||
// The erase operation respects "background color erase",
|
// The erase operation respects "background color erase",
|
||||||
// or we're clearing to the default background color, so we can
|
// or we're clearing to the default background color, so we can
|
||||||
// simply emit a clear screen op.
|
// simply emit a clear screen op.
|
||||||
@ -344,19 +341,19 @@ impl Renderer for TerminfoRenderer {
|
|||||||
record!(set_underline, value);
|
record!(set_underline, value);
|
||||||
}
|
}
|
||||||
Change::Attribute(AttributeChange::Foreground(col)) => {
|
Change::Attribute(AttributeChange::Foreground(col)) => {
|
||||||
attr_apply!(|attr: &mut CellAttributes| attr.foreground = *col);
|
self.attr_apply(|attr| attr.foreground = *col);
|
||||||
}
|
}
|
||||||
Change::Attribute(AttributeChange::Background(col)) => {
|
Change::Attribute(AttributeChange::Background(col)) => {
|
||||||
attr_apply!(|attr: &mut CellAttributes| attr.background = *col);
|
self.attr_apply(|attr| attr.background = *col);
|
||||||
}
|
}
|
||||||
Change::Attribute(AttributeChange::Hyperlink(link)) => {
|
Change::Attribute(AttributeChange::Hyperlink(link)) => {
|
||||||
attr_apply!(|attr: &mut CellAttributes| attr.hyperlink = link.clone());
|
self.attr_apply(|attr| attr.hyperlink = link.clone());
|
||||||
}
|
}
|
||||||
Change::AllAttributes(all) => {
|
Change::AllAttributes(all) => {
|
||||||
pending_attr = Some(all.clone());
|
self.pending_attr = Some(all.clone());
|
||||||
}
|
}
|
||||||
Change::Text(text) => {
|
Change::Text(text) => {
|
||||||
flush_pending_attr!();
|
self.flush_pending_attr(out)?;
|
||||||
WriteWrapper::new(out).write_all(text.as_bytes())?;
|
WriteWrapper::new(out).write_all(text.as_bytes())?;
|
||||||
}
|
}
|
||||||
Change::CursorPosition {
|
Change::CursorPosition {
|
||||||
@ -444,8 +441,8 @@ impl Renderer for TerminfoRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flush_pending_attr!();
|
self.flush_pending_attr(out)?;
|
||||||
Ok(current_attr)
|
Ok(self.current_attr.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,7 +543,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn empty_render() {
|
fn empty_render() {
|
||||||
let mut out = FakeTerm::new();
|
let mut out = FakeTerm::new();
|
||||||
let renderer = TerminfoRenderer::new(xterm_terminfo());
|
let mut renderer = TerminfoRenderer::new(xterm_terminfo());
|
||||||
let end_attr = renderer
|
let end_attr = renderer
|
||||||
.render_to(&CellAttributes::default(), &[], &mut out)
|
.render_to(&CellAttributes::default(), &[], &mut out)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -557,7 +554,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn basic_text() {
|
fn basic_text() {
|
||||||
let mut out = FakeTerm::new();
|
let mut out = FakeTerm::new();
|
||||||
let renderer = TerminfoRenderer::new(xterm_terminfo());
|
let mut renderer = TerminfoRenderer::new(xterm_terminfo());
|
||||||
let end_attr = renderer
|
let end_attr = renderer
|
||||||
.render_to(
|
.render_to(
|
||||||
&CellAttributes::default(),
|
&CellAttributes::default(),
|
||||||
@ -572,7 +569,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn bold_text() {
|
fn bold_text() {
|
||||||
let mut out = FakeTerm::new();
|
let mut out = FakeTerm::new();
|
||||||
let renderer = TerminfoRenderer::new(xterm_terminfo());
|
let mut renderer = TerminfoRenderer::new(xterm_terminfo());
|
||||||
let end_attr = renderer
|
let end_attr = renderer
|
||||||
.render_to(
|
.render_to(
|
||||||
&CellAttributes::default(),
|
&CellAttributes::default(),
|
||||||
@ -613,7 +610,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn clear_screen() {
|
fn clear_screen() {
|
||||||
let mut out = FakeTerm::new_with_size(4, 3);
|
let mut out = FakeTerm::new_with_size(4, 3);
|
||||||
let renderer = TerminfoRenderer::new(xterm_terminfo());
|
let mut renderer = TerminfoRenderer::new(xterm_terminfo());
|
||||||
let end_attr = renderer
|
let end_attr = renderer
|
||||||
.render_to(
|
.render_to(
|
||||||
&CellAttributes::default(),
|
&CellAttributes::default(),
|
||||||
@ -639,7 +636,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn clear_screen_bce() {
|
fn clear_screen_bce() {
|
||||||
let mut out = FakeTerm::new_with_size(4, 3);
|
let mut out = FakeTerm::new_with_size(4, 3);
|
||||||
let renderer = TerminfoRenderer::new(xterm_terminfo());
|
let mut renderer = TerminfoRenderer::new(xterm_terminfo());
|
||||||
let end_attr = renderer
|
let end_attr = renderer
|
||||||
.render_to(
|
.render_to(
|
||||||
&CellAttributes::default(),
|
&CellAttributes::default(),
|
||||||
@ -671,7 +668,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn clear_screen_no_terminfo() {
|
fn clear_screen_no_terminfo() {
|
||||||
let mut out = FakeTerm::new_with_size(4, 3);
|
let mut out = FakeTerm::new_with_size(4, 3);
|
||||||
let renderer = TerminfoRenderer::new(no_terminfo_all_enabled());
|
let mut renderer = TerminfoRenderer::new(no_terminfo_all_enabled());
|
||||||
let end_attr = renderer
|
let end_attr = renderer
|
||||||
.render_to(
|
.render_to(
|
||||||
&CellAttributes::default(),
|
&CellAttributes::default(),
|
||||||
@ -697,7 +694,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn clear_screen_bce_no_terminfo() {
|
fn clear_screen_bce_no_terminfo() {
|
||||||
let mut out = FakeTerm::new_with_size(4, 3);
|
let mut out = FakeTerm::new_with_size(4, 3);
|
||||||
let renderer = TerminfoRenderer::new(no_terminfo_all_enabled());
|
let mut renderer = TerminfoRenderer::new(no_terminfo_all_enabled());
|
||||||
let end_attr = renderer
|
let end_attr = renderer
|
||||||
.render_to(
|
.render_to(
|
||||||
&CellAttributes::default(),
|
&CellAttributes::default(),
|
||||||
@ -740,7 +737,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn bold_text_no_terminfo() {
|
fn bold_text_no_terminfo() {
|
||||||
let mut out = FakeTerm::new();
|
let mut out = FakeTerm::new();
|
||||||
let renderer = TerminfoRenderer::new(no_terminfo_all_enabled());
|
let mut renderer = TerminfoRenderer::new(no_terminfo_all_enabled());
|
||||||
let end_attr = renderer
|
let end_attr = renderer
|
||||||
.render_to(
|
.render_to(
|
||||||
&CellAttributes::default(),
|
&CellAttributes::default(),
|
||||||
@ -780,7 +777,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn red_bold_text() {
|
fn red_bold_text() {
|
||||||
let mut out = FakeTerm::new();
|
let mut out = FakeTerm::new();
|
||||||
let renderer = TerminfoRenderer::new(xterm_terminfo());
|
let mut renderer = TerminfoRenderer::new(xterm_terminfo());
|
||||||
let end_attr = renderer
|
let end_attr = renderer
|
||||||
.render_to(
|
.render_to(
|
||||||
&CellAttributes::default(),
|
&CellAttributes::default(),
|
||||||
@ -822,7 +819,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn red_bold_text_no_terminfo() {
|
fn red_bold_text_no_terminfo() {
|
||||||
let mut out = FakeTerm::new();
|
let mut out = FakeTerm::new();
|
||||||
let renderer = TerminfoRenderer::new(no_terminfo_all_enabled());
|
let mut renderer = TerminfoRenderer::new(no_terminfo_all_enabled());
|
||||||
let end_attr = renderer
|
let end_attr = renderer
|
||||||
.render_to(
|
.render_to(
|
||||||
&CellAttributes::default(),
|
&CellAttributes::default(),
|
||||||
@ -863,7 +860,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn truecolor() {
|
fn truecolor() {
|
||||||
let mut out = FakeTerm::new();
|
let mut out = FakeTerm::new();
|
||||||
let renderer = TerminfoRenderer::new(xterm_terminfo());
|
let mut renderer = TerminfoRenderer::new(xterm_terminfo());
|
||||||
renderer
|
renderer
|
||||||
.render_to(
|
.render_to(
|
||||||
&CellAttributes::default(),
|
&CellAttributes::default(),
|
||||||
@ -892,7 +889,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn truecolor_no_terminfo() {
|
fn truecolor_no_terminfo() {
|
||||||
let mut out = FakeTerm::new();
|
let mut out = FakeTerm::new();
|
||||||
let renderer = TerminfoRenderer::new(no_terminfo_all_enabled());
|
let mut renderer = TerminfoRenderer::new(no_terminfo_all_enabled());
|
||||||
renderer
|
renderer
|
||||||
.render_to(
|
.render_to(
|
||||||
&CellAttributes::default(),
|
&CellAttributes::default(),
|
||||||
|
Loading…
Reference in New Issue
Block a user