diff options
Diffstat (limited to 'src/server/render_stream.rs')
| -rw-r--r-- | src/server/render_stream.rs | 87 |
1 files changed, 81 insertions, 6 deletions
diff --git a/src/server/render_stream.rs b/src/server/render_stream.rs index e158a6d4..6699298d 100644 --- a/src/server/render_stream.rs +++ b/src/server/render_stream.rs @@ -260,11 +260,15 @@ pub(crate) fn render_virtual_with_runtime_registry( resize_panes: bool, cell_size: crate::kitty_graphics::HostCellSize, ) -> (ratatui::buffer::Buffer, Option<CursorState>) { + let pre_compute_suppresses_focused_terminal_cursor = + focused_terminal_suppresses_host_cursor(app_state, terminal_runtimes); if resize_panes { crate::ui::compute_view_with_cell_size(app_state, terminal_runtimes, area, cell_size); } else { crate::ui::compute_view_without_resizing_panes(app_state, terminal_runtimes, area); } + let suppress_focused_terminal_cursor = pre_compute_suppresses_focused_terminal_cursor + || focused_terminal_suppresses_host_cursor(app_state, terminal_runtimes); let backend = CursorTrackingBackend::new(area.width, area.height); let mut terminal = ratatui::Terminal::new(backend).expect("TestBackend::new should never fail"); @@ -276,8 +280,15 @@ pub(crate) fn render_virtual_with_runtime_registry( .expect("render to TestBackend should never fail"); let buffer = terminal.backend().buffer().clone(); - let cursor = focused_terminal_cursor(app_state, terminal_runtimes) - .or_else(|| terminal.backend().rendered_cursor()); + let cursor = if suppress_focused_terminal_cursor { + None + } else { + focused_terminal_cursor(app_state, terminal_runtimes).or_else(|| { + (!focused_terminal_owns_host_cursor(app_state, terminal_runtimes)) + .then(|| terminal.backend().rendered_cursor()) + .flatten() + }) + }; (buffer, cursor) } @@ -287,6 +298,7 @@ pub(crate) fn render_terminal_virtual( runtime: &crate::terminal::TerminalRuntime, area: Rect, ) -> (ratatui::buffer::Buffer, Option<CursorState>) { + let suppress_cursor = runtime.synchronized_output_active(); let backend = CursorTrackingBackend::new(area.width, area.height); let mut terminal = ratatui::Terminal::new(backend).expect("TestBackend::new should never fail"); @@ -297,15 +309,20 @@ pub(crate) fn render_terminal_virtual( .expect("render to TestBackend should never fail"); let buffer = terminal.backend().buffer().clone(); - let cursor = runtime - .cursor_state(area, true) + let cursor = (!suppress_cursor) + .then(|| runtime.cursor_state(area, true)) + .flatten() .map(|cursor| CursorState { x: cursor.x, y: cursor.y, visible: cursor.visible && !crate::ui::pane_is_scrolled_back(runtime), shape: cursor.shape, }) - .or_else(|| terminal.backend().rendered_cursor()); + .or_else(|| { + (!suppress_cursor) + .then(|| terminal.backend().rendered_cursor()) + .flatten() + }); (buffer, cursor) } @@ -355,8 +372,10 @@ pub(crate) fn focused_terminal_cursor( return None; } let rt = app_state.runtime_for_pane_in_workspace(terminal_runtimes, ws_idx, info.id)?; + if rt.synchronized_output_active() { + return None; + } let scrolled_back = crate::ui::pane_is_scrolled_back(rt); - // Determine whether the IME-anchor reveal applies to this focused pane. // The master switch must be on, and either no agent filter is configured // (apply to any pane) or the focused pane's detected agent matches the @@ -406,3 +425,59 @@ pub(crate) fn focused_terminal_cursor( None } } + +fn focused_terminal_owns_host_cursor( + app_state: &AppState, + terminal_runtimes: &TerminalRuntimeRegistry, +) -> bool { + if app_state.mode != Mode::Terminal { + return false; + } + + let Some(ws_idx) = app_state.active else { + return false; + }; + let Some(info) = app_state + .view + .pane_infos + .iter() + .find(|info| info.is_focused) + else { + return false; + }; + if !app_state.pane_exposes_host_cursor(ws_idx, info.id) { + return false; + } + + app_state + .runtime_for_pane_in_workspace(terminal_runtimes, ws_idx, info.id) + .is_some() +} + +fn focused_terminal_suppresses_host_cursor( + app_state: &AppState, + terminal_runtimes: &TerminalRuntimeRegistry, +) -> bool { + if app_state.mode != Mode::Terminal { + return false; + } + + let Some(ws_idx) = app_state.active else { + return false; + }; + let Some(info) = app_state + .view + .pane_infos + .iter() + .find(|info| info.is_focused) + else { + return false; + }; + if !app_state.pane_exposes_host_cursor(ws_idx, info.id) { + return false; + } + + app_state + .runtime_for_pane_in_workspace(terminal_runtimes, ws_idx, info.id) + .is_some_and(crate::terminal::TerminalRuntime::synchronized_output_active) +} |
