fix: respect synchronized terminal output batches

This commit is contained in:
Ogulcan Celik 2026-04-05 21:03:17 +03:00
parent 2cb03f31ff
commit aea908a7cf
3 changed files with 52 additions and 7 deletions

View File

@ -3284,12 +3284,18 @@ mod tests {
app.state.workspaces = vec![Workspace::test_new("a"), Workspace::test_new("b")];
app.state.active = Some(0);
app.state.selected = 0;
crate::ui::compute_view(&mut app.state, Rect::new(0, 0, 106, 20));
let target_row = app.state.view.workspace_card_areas[1].rect.y;
app.handle_mouse(mouse(MouseEventKind::Down(MouseButton::Left), 2, 2));
app.handle_mouse(mouse(
MouseEventKind::Down(MouseButton::Left),
2,
target_row,
));
assert_eq!(app.state.active, Some(0));
assert!(app.state.workspace_press.is_some());
app.handle_mouse(mouse(MouseEventKind::Up(MouseButton::Left), 2, 2));
app.handle_mouse(mouse(MouseEventKind::Up(MouseButton::Left), 2, target_row));
assert_eq!(app.state.active, Some(1));
assert_eq!(app.state.selected, 1);
assert!(app.state.workspace_press.is_none());
@ -3307,9 +3313,25 @@ mod tests {
let selected_id = app.state.workspaces[2].id.clone();
app.state.active = Some(1);
app.state.selected = 2;
crate::ui::compute_view(&mut app.state, Rect::new(0, 0, 106, 20));
let source_row = app.state.view.workspace_card_areas[1].rect.y;
let target_row = crate::ui::workspace_drop_indicator_row(
&app.state.view.workspace_card_areas,
app.state.workspace_list_rect(),
0,
)
.unwrap();
app.handle_mouse(mouse(MouseEventKind::Down(MouseButton::Left), 2, 2));
app.handle_mouse(mouse(MouseEventKind::Drag(MouseButton::Left), 2, 0));
app.handle_mouse(mouse(
MouseEventKind::Down(MouseButton::Left),
2,
source_row,
));
app.handle_mouse(mouse(
MouseEventKind::Drag(MouseButton::Left),
2,
target_row,
));
assert!(matches!(
app.state.drag.as_ref().map(|drag| &drag.target),
Some(DragTarget::WorkspaceReorder {
@ -3317,7 +3339,7 @@ mod tests {
insert_idx: Some(0),
})
));
app.handle_mouse(mouse(MouseEventKind::Up(MouseButton::Left), 2, 0));
app.handle_mouse(mouse(MouseEventKind::Up(MouseButton::Left), 2, target_row));
let names: Vec<_> = app
.state
@ -3336,6 +3358,7 @@ mod tests {
fn top_drop_slot_is_distinct_from_gap_below_first_workspace() {
let mut app = app_for_mouse_test();
app.state.workspaces = vec![Workspace::test_new("a"), Workspace::test_new("b")];
crate::ui::compute_view(&mut app.state, Rect::new(0, 0, 106, 20));
assert_eq!(app.state.workspace_drop_index_at_row(0), Some(0));
assert_eq!(app.state.workspace_drop_index_at_row(1), Some(1));

View File

@ -121,10 +121,11 @@ pub const MOUSE_BUTTON_WHEEL_RIGHT: ffi::GhosttyMouseButton =
pub const MODE_APPLICATION_CURSOR_KEYS: u16 = 1;
pub const MODE_FOCUS_EVENT: u16 = 1004;
pub const MODE_BRACKETED_PASTE: u16 = 2004;
pub const MODE_MOUSE_UTF8: u16 = 1005;
pub const MODE_MOUSE_SGR: u16 = 1006;
pub const MODE_MOUSE_ALTERNATE_SCROLL: u16 = 1007;
pub const MODE_BRACKETED_PASTE: u16 = 2004;
pub const MODE_SYNCHRONIZED_OUTPUT: u16 = 2026;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ActiveScreen {

View File

@ -449,9 +449,13 @@ impl GhosttyPaneTerminal {
};
core.terminal.write(bytes);
let synchronized_output = core
.terminal
.mode_get(crate::ghostty::MODE_SYNCHRONIZED_OUTPUT)
.unwrap_or(false);
let _ = response_writer;
ProcessBytesResult {
request_render: true,
request_render: !synchronized_output,
}
}
@ -1964,6 +1968,23 @@ mod tests {
);
}
#[test]
fn synchronized_output_suppresses_intermediate_render_requests_until_batch_ends() {
let (tx, _rx) = mpsc::channel(4);
let terminal = crate::ghostty::Terminal::new(80, 24, 0).unwrap();
let pane_terminal = GhosttyPaneTerminal::new(terminal, tx.clone()).unwrap();
let pane_id = PaneId::from_raw(1);
let begin = pane_terminal.process_pty_bytes(pane_id, b"\x1b[?2026h", &tx);
assert!(!begin.request_render);
let body = pane_terminal.process_pty_bytes(pane_id, b"hello", &tx);
assert!(!body.request_render);
let end = pane_terminal.process_pty_bytes(pane_id, b"\x1b[?2026l", &tx);
assert!(end.request_render);
}
#[tokio::test]
async fn focus_events_are_forwarded_when_enabled() {
let (tx, mut rx) = mpsc::channel(4);