diff options
Diffstat (limited to 'src/protocol')
| -rw-r--r-- | src/protocol/render_ansi.rs | 22 | ||||
| -rw-r--r-- | src/protocol/wire.rs | 19 |
2 files changed, 37 insertions, 4 deletions
diff --git a/src/protocol/render_ansi.rs b/src/protocol/render_ansi.rs index 12606bff..3346bb9c 100644 --- a/src/protocol/render_ansi.rs +++ b/src/protocol/render_ansi.rs @@ -31,7 +31,7 @@ use std::io::Write; use unicode_width::UnicodeWidthStr; -use crate::protocol::{CellData, FrameData}; +use crate::protocol::{underline_style_from_modifier, CellData, FrameData}; /// Bytes produced by a [`BlitEncoder`] for one terminal frame. pub(crate) struct EncodedBlit { @@ -294,7 +294,13 @@ fn modifier_to_sgr_parts(val: u16) -> Vec<&'static str> { parts.push("3"); } if val & UNDERLINED != 0 { - parts.push("4"); + parts.push(match underline_style_from_modifier(val) { + 2 => "4:2", + 3 => "4:3", + 4 => "4:4", + 5 => "4:5", + _ => "4", + }); } if val & SLOW_BLINK != 0 { parts.push("5"); @@ -843,6 +849,18 @@ mod tests { } #[test] + fn build_sgr_preserves_curly_underline_style() { + let modifier = crate::protocol::modifier_to_u16( + crate::protocol::modifier_with_underline_style(ratatui::style::Modifier::UNDERLINED, 3), + ); + + assert_eq!( + build_sgr(0x00_00_00_00, 0x00_00_00_00, modifier), + "\x1b[0;4:3;39;49m" + ); + } + + #[test] fn cells_equal_identical() { let a = make_cell("A", 2, 1, 0); let b = make_cell("A", 2, 1, 0); diff --git a/src/protocol/wire.rs b/src/protocol/wire.rs index 5f44691b..8225cb8c 100644 --- a/src/protocol/wire.rs +++ b/src/protocol/wire.rs @@ -426,7 +426,7 @@ pub struct CellData { pub fg: u32, /// Background color as a packed u32. pub bg: u32, - /// Bitmask of style modifiers (bold, italic, etc.). + /// Bitmask of style modifiers (bold, italic, etc.) plus Herdr extension bits. pub modifier: u16, /// Whether this cell should be skipped during diff-based rendering. pub skip: bool, @@ -729,15 +729,30 @@ fn u32_to_color(val: u32) -> ratatui::style::Color { } } +const UNDERLINE_STYLE_SHIFT: u16 = 12; +const UNDERLINE_STYLE_MASK: u16 = 0xF000; + /// Converts a ratatui `Modifier` bitmask to a u16 for wire transport. pub(crate) fn modifier_to_u16(modifier: ratatui::style::Modifier) -> u16 { modifier.bits() } +pub(crate) fn underline_style_from_modifier(modifier: u16) -> u8 { + ((modifier & UNDERLINE_STYLE_MASK) >> UNDERLINE_STYLE_SHIFT) as u8 +} + +pub(crate) fn modifier_with_underline_style( + modifier: ratatui::style::Modifier, + underline_style: u8, +) -> ratatui::style::Modifier { + let bits = modifier.bits() | ((u16::from(underline_style) & 0x0F) << UNDERLINE_STYLE_SHIFT); + ratatui::style::Modifier::from_bits_retain(bits) +} + /// Converts a u16 back to a ratatui `Modifier`. #[cfg(test)] fn u16_to_modifier(val: u16) -> ratatui::style::Modifier { - ratatui::style::Modifier::from_bits_truncate(val) + ratatui::style::Modifier::from_bits_truncate(val & !UNDERLINE_STYLE_MASK) } // --------------------------------------------------------------------------- |
