From 73dba97521f5a0e3104518ef48b775a178998f52 Mon Sep 17 00:00:00 2001 From: Ogulcan Celik Date: Fri, 15 May 2026 20:53:34 +0300 Subject: fix: forward pane cursor shape fixes #116 --- src/pane/terminal.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'src/pane') diff --git a/src/pane/terminal.rs b/src/pane/terminal.rs index 33cd8ed5..f0535c7a 100644 --- a/src/pane/terminal.rs +++ b/src/pane/terminal.rs @@ -39,6 +39,21 @@ pub struct TerminalCursorState { pub x: u16, pub y: u16, pub visible: bool, + /// DECSCUSR parameter (0–6). 0 means terminal default. + pub shape: u8, +} + +fn decscusr_cursor_shape(style: crate::ghostty::CursorVisualStyle, blinking: bool) -> u8 { + match (style, blinking) { + (crate::ghostty::CursorVisualStyle::Block, true) + | (crate::ghostty::CursorVisualStyle::BlockHollow, true) => 1, + (crate::ghostty::CursorVisualStyle::Block, false) + | (crate::ghostty::CursorVisualStyle::BlockHollow, false) => 2, + (crate::ghostty::CursorVisualStyle::Underline, true) => 3, + (crate::ghostty::CursorVisualStyle::Underline, false) => 4, + (crate::ghostty::CursorVisualStyle::Bar, true) => 5, + (crate::ghostty::CursorVisualStyle::Bar, false) => 6, + } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -530,10 +545,17 @@ impl GhosttyPaneTerminal { } = &mut *core; render_state.update(terminal).ok()?; let cursor = render_state.cursor_viewport().ok()??; + let shape = render_state + .cursor_visual_style() + .ok() + .zip(render_state.cursor_blinking().ok()) + .map(|(style, blinking)| decscusr_cursor_shape(style, blinking)) + .unwrap_or(0); Some(TerminalCursorState { x: cursor.x, y: cursor.y, visible: render_state.cursor_visible().ok()?, + shape, }) } @@ -1202,6 +1224,38 @@ mod tests { terminal.write(b"END"); } + #[test] + fn decscusr_cursor_shape_preserves_blinking_variants() { + assert_eq!( + decscusr_cursor_shape(crate::ghostty::CursorVisualStyle::Block, true), + 1 + ); + assert_eq!( + decscusr_cursor_shape(crate::ghostty::CursorVisualStyle::Block, false), + 2 + ); + assert_eq!( + decscusr_cursor_shape(crate::ghostty::CursorVisualStyle::Underline, true), + 3 + ); + assert_eq!( + decscusr_cursor_shape(crate::ghostty::CursorVisualStyle::Underline, false), + 4 + ); + assert_eq!( + decscusr_cursor_shape(crate::ghostty::CursorVisualStyle::Bar, true), + 5 + ); + assert_eq!( + decscusr_cursor_shape(crate::ghostty::CursorVisualStyle::Bar, false), + 6 + ); + assert_eq!( + decscusr_cursor_shape(crate::ghostty::CursorVisualStyle::BlockHollow, false), + 2 + ); + } + #[test] fn host_terminal_theme_restore_probe_skips_when_no_transient_override() { let (tx, _rx) = mpsc::channel(4); -- cgit v1.2.3