mirror of
https://github.com/herdrdev/herdr.git
synced 2026-09-22 08:01:06 +00:00
+83
-1
@@ -1441,7 +1441,8 @@ impl GhosttyPaneTerminal {
|
||||
.terminal
|
||||
.mode_get(crate::ghostty::MODE_SYNCHRONIZED_OUTPUT)
|
||||
.unwrap_or(false);
|
||||
if CURSOR_POSITION_SETTLE_ENABLED {
|
||||
// Intermediate synchronized-frame positions must not become settled cursors.
|
||||
if CURSOR_POSITION_SETTLE_ENABLED && !synchronized_output {
|
||||
let cursor_started = crate::render_prof::timer();
|
||||
let cursor_after_write = current_cursor_state(&mut core);
|
||||
crate::render_prof::duration_since("pty.cursor_state_update", cursor_started);
|
||||
@@ -4363,6 +4364,87 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(windows)]
|
||||
fn cursor_settle_ignores_intermediate_synchronized_frame_positions() {
|
||||
let (tx, _rx) = mpsc::channel(4);
|
||||
let terminal = crate::ghostty::Terminal::new(80, 24, 0).unwrap();
|
||||
let pane = GhosttyPaneTerminal::new(terminal, tx.clone()).unwrap();
|
||||
let pane_id = PaneId::from_raw(1);
|
||||
pane.process_pty_bytes(pane_id, 0, b"\x1b[15;4H", &tx);
|
||||
|
||||
let previous = TerminalCursorState {
|
||||
x: 3,
|
||||
y: 14,
|
||||
visible: true,
|
||||
shape: 0,
|
||||
};
|
||||
{
|
||||
let mut core = pane.core.lock().unwrap();
|
||||
let now = Instant::now();
|
||||
core.cursor_settle_state = CursorPositionSettleState::default();
|
||||
core.cursor_settle_state.observe(
|
||||
Some(TerminalCursorState { x: 2, ..previous }),
|
||||
now - Duration::from_millis(300),
|
||||
);
|
||||
// Seed a pending hold whose deadline has passed, without wall-clock sleeps.
|
||||
core.cursor_settle_state
|
||||
.observe(Some(previous), now - Duration::from_millis(200));
|
||||
}
|
||||
|
||||
for bytes in [
|
||||
b"\x1b[?2026h\x1b[15;4Hx\x1b[13;1H".as_slice(),
|
||||
b"\x1b[0 q\x1b[13;1H \x1b[15;5H",
|
||||
b"\x1b[?25h",
|
||||
] {
|
||||
let result = pane.process_pty_bytes(pane_id, 0, bytes, &tx);
|
||||
assert!(!result.request_render);
|
||||
assert_eq!(result.render_delay, None);
|
||||
assert_eq!(pane.cursor_state(), Some(previous));
|
||||
assert!(pane.core.lock().unwrap().cursor_settle_state.pending());
|
||||
}
|
||||
|
||||
let result = pane.process_pty_bytes(pane_id, 0, b"\x1b[?2026l", &tx);
|
||||
assert!(result.request_render);
|
||||
assert!(!pane.core.lock().unwrap().cursor_settle_state.pending());
|
||||
assert_eq!(
|
||||
pane.cursor_state(),
|
||||
Some(TerminalCursorState { x: 4, ..previous })
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(windows)]
|
||||
fn cursor_settle_preserves_final_visibility_and_shape_across_split_sync_sequences() {
|
||||
let (tx, _rx) = mpsc::channel(4);
|
||||
let terminal = crate::ghostty::Terminal::new(80, 24, 0).unwrap();
|
||||
let pane = GhosttyPaneTerminal::new(terminal, tx.clone()).unwrap();
|
||||
let pane_id = PaneId::from_raw(1);
|
||||
pane.process_pty_bytes(pane_id, 0, b"\x1b[15;4H", &tx);
|
||||
|
||||
for bytes in [
|
||||
b"\x1b[?202".as_slice(),
|
||||
b"6h\x1b[13;1H",
|
||||
b"\x1b[6 q\x1b[15;5H\x1b[?25l\x1b[?20",
|
||||
] {
|
||||
pane.process_pty_bytes(pane_id, 0, bytes, &tx);
|
||||
assert!(!pane.core.lock().unwrap().cursor_settle_state.pending());
|
||||
}
|
||||
|
||||
let result = pane.process_pty_bytes(pane_id, 0, b"26l", &tx);
|
||||
assert!(result.request_render);
|
||||
assert_eq!(result.render_delay, None);
|
||||
assert_eq!(
|
||||
pane.cursor_state(),
|
||||
Some(TerminalCursorState {
|
||||
x: 4,
|
||||
y: 14,
|
||||
visible: false,
|
||||
shape: 6,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(windows))]
|
||||
fn cursor_state_uses_live_position_when_settle_policy_disabled() {
|
||||
|
||||
Reference in New Issue
Block a user