Skip to content

Commit

Permalink
Performable tab and split navigation (#5644)
Browse files Browse the repository at this point in the history
Partial fixes #5552 (for GTK).

This PR adds the core infrastructure for keybind actions that are
implemented as runtime app actions to be performable. This is done by
having `rt_app.performAction` return a boolean. By default all runtime
app actions return `true` (the action was performed) unless they are
modified to return `true`/`false` as appropriate.

The GTK apprt is modified so that `goto_split`, `previous_tab`,
`next_tab`, `last_tab`, and `goto_tab` are performable. macOS support
will need to be added in a subsequent commit.

This doesn't completely solve the issue for the OP because if the
`goto_split` isn't performable there is no fallback to`previous_tab` or
`next_tab`.

I don't think that the approach taken in #5579 is the right one as it
conflates split and tab navigation unconditionally which I don't think
is what everyone would want. Either a separate action that explicitly
combines the actions or a solution to #3175 will be the ultimate
solution I believe.
  • Loading branch information
mitchellh authored Feb 12, 2025
2 parents 66442cd + f26c96d commit 338a07e
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 113 deletions.
2 changes: 1 addition & 1 deletion include/ghostty.h
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ typedef void (*ghostty_runtime_write_clipboard_cb)(void*,
ghostty_clipboard_e,
bool);
typedef void (*ghostty_runtime_close_surface_cb)(void*, bool);
typedef void (*ghostty_runtime_action_cb)(ghostty_app_t,
typedef bool (*ghostty_runtime_action_cb)(ghostty_app_t,
ghostty_target_s,
ghostty_action_s);

Expand Down
11 changes: 8 additions & 3 deletions macos/Sources/Ghostty/Ghostty.App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -423,15 +423,15 @@ extension Ghostty {

// MARK: Actions (macOS)

static func action(_ app: ghostty_app_t, target: ghostty_target_s, action: ghostty_action_s) {
static func action(_ app: ghostty_app_t, target: ghostty_target_s, action: ghostty_action_s) -> Bool {
// Make sure it a target we understand so all our action handlers can assert
switch (target.tag) {
case GHOSTTY_TARGET_APP, GHOSTTY_TARGET_SURFACE:
break

default:
Ghostty.logger.warning("unknown action target=\(target.tag.rawValue)")
return
return false
}

// Action dispatch
Expand Down Expand Up @@ -541,10 +541,15 @@ extension Ghostty {
fallthrough
case GHOSTTY_ACTION_QUIT_TIMER:
Ghostty.logger.info("known but unimplemented action action=\(action.tag.rawValue)")

return false
default:
Ghostty.logger.warning("unknown action action=\(action.tag.rawValue)")
return false
}

// If we reached here then we assume performed since all unknown actions
// are captured in the switch and return false.
return true
}

private static func quit(_ app: ghostty_app_t) {
Expand Down
24 changes: 12 additions & 12 deletions src/App.zig
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ pub fn updateConfig(self: *App, rt_app: *apprt.App, config: *const Config) !void
const applied: *const configpkg.Config = if (applied_) |*c| c else config;

// Notify the apprt that the app has changed configuration.
try rt_app.performAction(
_ = try rt_app.performAction(
.app,
.config_change,
.{ .config = applied },
Expand All @@ -180,7 +180,7 @@ pub fn addSurface(
// Since we have non-zero surfaces, we can cancel the quit timer.
// It is up to the apprt if there is a quit timer at all and if it
// should be canceled.
rt_surface.app.performAction(
_ = rt_surface.app.performAction(
.app,
.quit_timer,
.stop,
Expand Down Expand Up @@ -214,7 +214,7 @@ pub fn deleteSurface(self: *App, rt_surface: *apprt.Surface) void {

// If we have no surfaces, we can start the quit timer. It is up to the
// apprt to determine if this is necessary.
if (self.surfaces.items.len == 0) rt_surface.app.performAction(
if (self.surfaces.items.len == 0) _ = rt_surface.app.performAction(
.app,
.quit_timer,
.start,
Expand Down Expand Up @@ -294,7 +294,7 @@ pub fn newWindow(self: *App, rt_app: *apprt.App, msg: Message.NewWindow) !void {
break :target .app;
};

try rt_app.performAction(
_ = try rt_app.performAction(
target,
.new_window,
{},
Expand Down Expand Up @@ -419,7 +419,7 @@ pub fn colorSchemeEvent(

// Request our configuration be reloaded because the new scheme may
// impact the colors of the app.
try rt_app.performAction(
_ = try rt_app.performAction(
.app,
.reload_config,
.{ .soft = true },
Expand All @@ -437,13 +437,13 @@ pub fn performAction(
switch (action) {
.unbind => unreachable,
.ignore => {},
.quit => try rt_app.performAction(.app, .quit, {}),
.new_window => try self.newWindow(rt_app, .{ .parent = null }),
.open_config => try rt_app.performAction(.app, .open_config, {}),
.reload_config => try rt_app.performAction(.app, .reload_config, .{}),
.close_all_windows => try rt_app.performAction(.app, .close_all_windows, {}),
.toggle_quick_terminal => try rt_app.performAction(.app, .toggle_quick_terminal, {}),
.toggle_visibility => try rt_app.performAction(.app, .toggle_visibility, {}),
.quit => _ = try rt_app.performAction(.app, .quit, {}),
.new_window => _ = try self.newWindow(rt_app, .{ .parent = null }),
.open_config => _ = try rt_app.performAction(.app, .open_config, {}),
.reload_config => _ = try rt_app.performAction(.app, .reload_config, .{}),
.close_all_windows => _ = try rt_app.performAction(.app, .close_all_windows, {}),
.toggle_quick_terminal => _ = try rt_app.performAction(.app, .toggle_quick_terminal, {}),
.toggle_visibility => _ = try rt_app.performAction(.app, .toggle_visibility, {}),
}
}

Expand Down
Loading

0 comments on commit 338a07e

Please sign in to comment.