diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-06-30 15:55:13 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-06-30 15:55:13 +0300 |
| commit | b7015f17a49501e99642009ebadabcbefc0fbad0 (patch) | |
| tree | d245bcac1ef14e2272e3850d698fcccae1f8c379 /src/pane/terminal.rs | |
| parent | e9bcea9c0da2ebd996b4b570c504582740f3466e (diff) | |
fix: render ansi undercurl styles
refs #895
Diffstat (limited to 'src/pane/terminal.rs')
| -rw-r--r-- | src/pane/terminal.rs | 65 |
1 files changed, 62 insertions, 3 deletions
diff --git a/src/pane/terminal.rs b/src/pane/terminal.rs index b36ae0ee..708a7d28 100644 --- a/src/pane/terminal.rs +++ b/src/pane/terminal.rs @@ -2010,6 +2010,7 @@ fn ghostty_cell_style( if basic.style.strikethrough { modifiers |= Modifier::CROSSED_OUT; } + modifiers = crate::protocol::modifier_with_underline_style(modifiers, basic.style.underline); style.add_modifier(modifiers) } @@ -3783,8 +3784,7 @@ mod tests { let pane = GhosttyPaneTerminal::new(terminal, tx.clone()).unwrap(); let pane_id = PaneId::from_raw(1); - let result = - pane.process_pty_bytes(pane_id, 0, b"\x1bP+q6E6F7065;536D756C78;4D7\x1b\\", &tx); + let result = pane.process_pty_bytes(pane_id, 0, b"\x1bP+q6E6F7065;4D7\x1b\\", &tx); assert!(result.terminal_responses.is_empty()); assert!(rx.try_recv().is_err()); @@ -3797,12 +3797,18 @@ mod tests { let pane = GhosttyPaneTerminal::new(terminal, tx.clone()).unwrap(); let pane_id = PaneId::from_raw(1); - let result = pane.process_pty_bytes(pane_id, 0, b"\x1bP+q5375;536574756C63\x1b\\", &tx); + let result = pane.process_pty_bytes( + pane_id, + 0, + b"\x1bP+q5375;536D756C78;536574756C63\x1b\\", + &tx, + ); assert_eq!( result.terminal_responses, vec![ expected_xtgettcap_response("5375", None), + expected_xtgettcap_response("536D756C78", Some(b"\\E[4:%p1%dm")), expected_xtgettcap_response( "536574756C63", Some(b"\\E[58:2::%p1%{65536}%/%d:%p1%{256}%/%{255}%&%d:%p1%{255}%&%d%;m") @@ -3834,6 +3840,59 @@ mod tests { } #[test] + fn dirty_patch_preserves_curly_underline_style() { + let (tx, _rx) = mpsc::channel(4); + let terminal = crate::ghostty::Terminal::new(20, 5, 0).unwrap(); + let pane = GhosttyPaneTerminal::new(terminal, tx).unwrap(); + let backend = ratatui::backend::TestBackend::new(20, 5); + let mut terminal = ratatui::Terminal::new(backend).unwrap(); + terminal + .draw(|frame| pane.render(frame, Rect::new(0, 0, 20, 5), false)) + .unwrap(); + { + let mut core = pane.core.lock().unwrap(); + core.terminal.write(b"\x1b[4:3mU"); + } + + let patch = match pane.collect_dirty_patch(20, 5) { + TerminalDirtyPatchOutcome::Patch(patch) => patch, + other => panic!("expected dirty patch, got {other:?}"), + }; + + let cell = &patch.rows[0].1[0]; + assert_eq!(cell.symbol, "U"); + assert_eq!( + crate::protocol::underline_style_from_modifier(cell.modifier), + 3 + ); + } + + #[test] + fn full_frame_preserves_curly_underline_style() { + let (tx, _rx) = mpsc::channel(4); + let terminal = crate::ghostty::Terminal::new(20, 5, 0).unwrap(); + let pane = GhosttyPaneTerminal::new(terminal, tx).unwrap(); + { + let mut core = pane.core.lock().unwrap(); + core.terminal.write(b"\x1b[4:3mU"); + } + + let backend = ratatui::backend::TestBackend::new(20, 5); + let mut terminal = ratatui::Terminal::new(backend).unwrap(); + terminal + .draw(|frame| pane.render(frame, Rect::new(0, 0, 20, 5), false)) + .unwrap(); + + let frame = + crate::protocol::FrameData::from_ratatui_buffer(terminal.backend().buffer(), None); + assert_eq!(frame.cells[0].symbol, "U"); + assert_eq!( + crate::protocol::underline_style_from_modifier(frame.cells[0].modifier), + 3 + ); + } + + #[test] fn process_pty_bytes_orders_default_color_reply_before_following_device_attribute_reply() { let (tx, mut rx) = mpsc::channel(4); let terminal = crate::ghostty::Terminal::new(20, 5, 0).unwrap(); |
