aboutsummaryrefslogtreecommitdiff
path: root/src/server/render_stream.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/render_stream.rs')
-rw-r--r--src/server/render_stream.rs87
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)
+}