diff --git a/include/ghostty.h b/include/ghostty.h index 9b7a918ec..8c4455564 100644 --- a/include/ghostty.h +++ b/include/ghostty.h @@ -747,6 +747,11 @@ typedef struct { uint64_t duration; } ghostty_action_command_finished_s; +// apprt.action.StartSearch.C +typedef struct { + const char* needle; +} ghostty_action_start_search_s; + // terminal.Scrollbar typedef struct { uint64_t total; @@ -811,6 +816,7 @@ typedef enum { GHOSTTY_ACTION_PROGRESS_REPORT, GHOSTTY_ACTION_SHOW_ON_SCREEN_KEYBOARD, GHOSTTY_ACTION_COMMAND_FINISHED, + GHOSTTY_ACTION_START_SEARCH, } ghostty_action_tag_e; typedef union { @@ -844,6 +850,7 @@ typedef union { ghostty_surface_message_childexited_s child_exited; ghostty_action_progress_report_s progress_report; ghostty_action_command_finished_s command_finished; + ghostty_action_start_search_s start_search; } ghostty_action_u; typedef struct { diff --git a/src/Surface.zig b/src/Surface.zig index 4323291be..1e1363229 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -4877,6 +4877,17 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool self.renderer_state.terminal.fullReset(); }, + .start_search => if (self.search == null) { + // To save resources, we don't actually start a search here, + // we just notify teh apprt. The real thread will start when + // the first needles are set. + _ = try self.rt_app.performAction( + .{ .surface = self }, + .start_search, + .{ .needle = "" }, + ); + } else return false, + .search => |text| search: { const s: *Search = if (self.search) |*s| s else init: { // If we're stopping the search and we had no prior search, diff --git a/src/apprt/action.zig b/src/apprt/action.zig index 11186f059..45fa8aca0 100644 --- a/src/apprt/action.zig +++ b/src/apprt/action.zig @@ -301,6 +301,9 @@ pub const Action = union(Key) { /// A command has finished, command_finished: CommandFinished, + /// Start the search overlay with an optional initial needle. + start_search: StartSearch, + /// Sync with: ghostty_action_tag_e pub const Key = enum(c_int) { quit, @@ -358,6 +361,7 @@ pub const Action = union(Key) { progress_report, show_on_screen_keyboard, command_finished, + start_search, }; /// Sync with: ghostty_action_u @@ -770,3 +774,18 @@ pub const CommandFinished = struct { }; } }; + +pub const StartSearch = struct { + needle: [:0]const u8, + + // Sync with: ghostty_action_start_search_s + pub const C = extern struct { + needle: [*:0]const u8, + }; + + pub fn cval(self: StartSearch) C { + return .{ + .needle = self.needle.ptr, + }; + } +}; diff --git a/src/input/Binding.zig b/src/input/Binding.zig index ce60ea0e0..636f343e3 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -340,6 +340,10 @@ pub const Action = union(enum) { /// is not performed. navigate_search: NavigateSearch, + /// Start a search if it isn't started already. This doesn't set any + /// search terms, but opens the UI for searching. + start_search, + /// Clear the screen and all scrollback. clear_screen, @@ -1167,6 +1171,7 @@ pub const Action = union(enum) { .cursor_key, .search, .navigate_search, + .start_search, .reset, .copy_to_clipboard, .copy_url_to_clipboard, diff --git a/src/input/command.zig b/src/input/command.zig index a3df0e858..37dc08fb4 100644 --- a/src/input/command.zig +++ b/src/input/command.zig @@ -163,6 +163,12 @@ fn actionCommands(action: Action.Key) []const Command { .description = "Paste the contents of the selection clipboard.", }}, + .start_search => comptime &.{.{ + .action = .start_search, + .title = "Start Search", + .description = "Start a search if one isn't already active.", + }}, + .navigate_search => comptime &.{ .{ .action = .{ .navigate_search = .next }, .title = "Next Search Result",