aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/headless.rs72
1 files changed, 71 insertions, 1 deletions
diff --git a/src/server/headless.rs b/src/server/headless.rs
index b4f433f7..859e02af 100644
--- a/src/server/headless.rs
+++ b/src/server/headless.rs
@@ -4910,7 +4910,8 @@ mod tests {
use super::*;
use crate::app::AppState;
- use crate::protocol::CursorState;
+ use crate::protocol::{CellData, CursorState};
+ use unicode_width::UnicodeWidthStr;
#[path = "pane_graphics.rs"]
mod pane_graphics_tests;
@@ -5350,6 +5351,16 @@ mod tests {
for (idx, (actual_cell, expected_cell)) in
actual.cells.iter().zip(expected.cells.iter()).enumerate()
{
+ if cells_equivalent_for_frame_compare(
+ &actual.cells,
+ &expected.cells,
+ usize::from(actual.width),
+ idx,
+ actual_cell,
+ expected_cell,
+ ) {
+ continue;
+ }
assert_eq!(
actual_cell,
expected_cell,
@@ -5360,6 +5371,65 @@ mod tests {
}
}
+ fn cells_equivalent_for_frame_compare(
+ actual_cells: &[CellData],
+ expected_cells: &[CellData],
+ width: usize,
+ idx: usize,
+ actual: &CellData,
+ expected: &CellData,
+ ) -> bool {
+ if actual == expected {
+ return true;
+ }
+ if !cell_style_without_symbol_eq(actual, expected) {
+ return false;
+ }
+ if !matches!(
+ (actual.symbol.as_str(), expected.symbol.as_str()),
+ ("", " ") | (" ", "")
+ ) {
+ return false;
+ }
+ covered_by_previous_wide_cell(actual_cells, width, idx)
+ || covered_by_previous_wide_cell(expected_cells, width, idx)
+ }
+
+ fn cell_style_without_symbol_eq(a: &CellData, b: &CellData) -> bool {
+ a.fg == b.fg
+ && a.bg == b.bg
+ && a.modifier == b.modifier
+ && a.skip == b.skip
+ && a.hyperlink == b.hyperlink
+ }
+
+ fn covered_by_previous_wide_cell(cells: &[CellData], width: usize, idx: usize) -> bool {
+ if idx == 0 || idx.is_multiple_of(width) {
+ return false;
+ }
+ frame_cell_display_width(&cells[idx - 1]) > 1
+ }
+
+ fn frame_cell_display_width(cell: &CellData) -> usize {
+ if is_halfwidth_katakana_voiced_grapheme(&cell.symbol) {
+ return 2;
+ }
+ cell.symbol.width()
+ }
+
+ fn is_halfwidth_katakana_voiced_grapheme(symbol: &str) -> bool {
+ let mut chars = symbol.chars();
+ let Some(base) = chars.next() else {
+ return false;
+ };
+ let Some(mark) = chars.next() else {
+ return false;
+ };
+ chars.next().is_none()
+ && ('\u{ff66}'..='\u{ff9d}').contains(&base)
+ && matches!(mark, '\u{ff9e}' | '\u{ff9f}')
+ }
+
#[test]
fn foreground_client_applies_client_keybindings() {
let mut server = test_headless_server();