From c1d033e35ff690725637dc30f30e3f3df903110d Mon Sep 17 00:00:00 2001 From: Taylor Bell Date: Mon, 25 May 2026 00:40:42 -0600 Subject: [PATCH 1/2] ghostty: add ghostty_surface_set_selection_range C API (rebased on upstream/main) Includes resolve of conflict: both selectCursorLine (upstream) and setSelectionRange (Slice 0) are kept as independent cmux additions to the fork. --- include/ghostty.h | 6 ++++++ src/Surface.zig | 24 ++++++++++++++++++++++++ src/apprt/embedded.zig | 21 +++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/include/ghostty.h b/include/ghostty.h index 3697f78d43f..9a1d0e2bf30 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -1180,6 +1180,12 @@ GHOSTTY_API void ghostty_surface_complete_clipboard_request(ghostty_surface_t, GHOSTTY_API bool ghostty_surface_has_selection(ghostty_surface_t); GHOSTTY_API bool ghostty_surface_select_cursor_cell(ghostty_surface_t); GHOSTTY_API bool ghostty_surface_select_cursor_line(ghostty_surface_t); +GHOSTTY_API bool ghostty_surface_set_selection_range(ghostty_surface_t, + uint32_t, + uint32_t, + uint32_t, + uint32_t, + bool); GHOSTTY_API bool ghostty_surface_clear_selection(ghostty_surface_t); GHOSTTY_API bool ghostty_surface_read_selection(ghostty_surface_t, ghostty_text_s*); GHOSTTY_API bool ghostty_surface_read_text(ghostty_surface_t, diff --git a/src/Surface.zig b/src/Surface.zig index a1fd96e7d9b..c373f204403 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -2118,6 +2118,30 @@ pub fn selectCursorLine(self: *Surface) !bool { return true; } +/// Set a selection range from buffer (screen) coordinates (cmux-specific). +pub fn setSelectionRange( + self: *Surface, + row_start: u32, + col_start: u32, + row_end: u32, + col_end: u32, + is_rectangular: bool, +) !bool { + self.renderer_state.mutex.lock(); + defer self.renderer_state.mutex.unlock(); + + const screen: *terminal.Screen = self.io.terminal.screens.active; + const col_start_cell = std.math.cast(terminal.size.CellCountInt, col_start) orelse return false; + const col_end_cell = std.math.cast(terminal.size.CellCountInt, col_end) orelse return false; + const start_pin = screen.pages.pin(.{ .screen = .{ .x = col_start_cell, .y = row_start } }) orelse return false; + const end_pin = screen.pages.pin(.{ .screen = .{ .x = col_end_cell, .y = row_end } }) orelse return false; + + try self.setSelection(terminal.Selection.init(start_pin, end_pin, is_rectangular)); + screen.dirty.selection = true; + try self.queueRender(); + return true; +} + /// Clear the active selection (cmux-specific). pub fn clearSelection(self: *Surface) !bool { self.renderer_state.mutex.lock(); diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index 340fedda58a..0f145487668 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -1684,6 +1684,27 @@ pub const CAPI = struct { }; } + /// Set a selection range from buffer (screen) coordinates (cmux-specific). + export fn ghostty_surface_set_selection_range( + surface: *Surface, + row_start: u32, + col_start: u32, + row_end: u32, + col_end: u32, + is_rectangular: bool, + ) bool { + return surface.core_surface.setSelectionRange( + row_start, + col_start, + row_end, + col_end, + is_rectangular, + ) catch |err| { + log.warn("error setting selection range err={}", .{err}); + return false; + }; + } + /// Same as ghostty_surface_read_text but reads from the user selection, /// if any. export fn ghostty_surface_read_selection( From 0a650e9258af25c2dbbbddd81005d3e79ce074a2 Mon Sep 17 00:00:00 2001 From: Taylor Bell Date: Mon, 25 May 2026 09:08:28 -0600 Subject: [PATCH 2/2] ghostty: name set_selection_range parameters --- include/ghostty.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/ghostty.h b/include/ghostty.h index 9a1d0e2bf30..1d249a3a855 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -1181,11 +1181,11 @@ GHOSTTY_API bool ghostty_surface_has_selection(ghostty_surface_t); GHOSTTY_API bool ghostty_surface_select_cursor_cell(ghostty_surface_t); GHOSTTY_API bool ghostty_surface_select_cursor_line(ghostty_surface_t); GHOSTTY_API bool ghostty_surface_set_selection_range(ghostty_surface_t, - uint32_t, - uint32_t, - uint32_t, - uint32_t, - bool); + uint32_t row_start, + uint32_t col_start, + uint32_t row_end, + uint32_t col_end, + bool is_rectangular); GHOSTTY_API bool ghostty_surface_clear_selection(ghostty_surface_t); GHOSTTY_API bool ghostty_surface_read_selection(ghostty_surface_t, ghostty_text_s*); GHOSTTY_API bool ghostty_surface_read_text(ghostty_surface_t,