Merge pull request #2120 from edmz/last_tab

macos: jump to last_tab
This commit is contained in:
Mitchell Hashimoto
2024-08-26 20:22:52 -07:00
committed by GitHub
10 changed files with 59 additions and 66 deletions

View File

@ -143,6 +143,7 @@ typedef enum {
typedef enum {
GHOSTTY_TAB_PREVIOUS = -1,
GHOSTTY_TAB_NEXT = -2,
GHOSTTY_TAB_LAST = -3,
} ghostty_tab_e;
typedef enum {

View File

@ -725,6 +725,8 @@ class TerminalController: NSWindowController, NSWindowDelegate,
} else {
finalIndex = selectedIndex + 1
}
} else if (tabIndex == GHOSTTY_TAB_LAST.rawValue) {
finalIndex = tabbedWindows.count - 1
} else {
return
}

View File

@ -3559,9 +3559,9 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
}
}
if (@hasDecl(apprt.Surface, "gotoPreviousTab")) {
self.rt_surface.gotoPreviousTab();
} else log.warn("runtime doesn't implement gotoPreviousTab", .{});
if (@hasDecl(apprt.Surface, "gotoTab")) {
self.rt_surface.gotoTab(.previous);
} else log.warn("runtime doesn't implement gotoTab", .{});
},
.next_tab => {
@ -3572,14 +3572,27 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
}
}
if (@hasDecl(apprt.Surface, "gotoNextTab")) {
self.rt_surface.gotoNextTab();
} else log.warn("runtime doesn't implement gotoNextTab", .{});
if (@hasDecl(apprt.Surface, "gotoTab")) {
self.rt_surface.gotoTab(.next);
} else log.warn("runtime doesn't implement gotoTab", .{});
},
.last_tab => {
if (@hasDecl(apprt.Surface, "hasTabs")) {
if (!self.rt_surface.hasTabs()) {
log.debug("surface has no tabs, ignoring last_tab binding", .{});
return false;
}
}
if (@hasDecl(apprt.Surface, "gotoTab")) {
self.rt_surface.gotoTab(.last);
} else log.warn("runtime doesn't implement gotoTab", .{});
},
.goto_tab => |n| {
if (@hasDecl(apprt.Surface, "gotoTab")) {
self.rt_surface.gotoTab(n);
self.rt_surface.gotoTab(@enumFromInt(n));
} else log.warn("runtime doesn't implement gotoTab", .{});
},

View File

@ -28,6 +28,7 @@ pub const ClipboardRequestType = structs.ClipboardRequestType;
pub const ColorScheme = structs.ColorScheme;
pub const CursorPos = structs.CursorPos;
pub const DesktopNotification = structs.DesktopNotification;
pub const GotoTab = structs.GotoTab;
pub const IMEPos = structs.IMEPos;
pub const Selection = structs.Selection;
pub const SplitDirection = structs.SplitDirection;

View File

@ -108,7 +108,7 @@ pub const App = struct {
toggle_split_zoom: ?*const fn (SurfaceUD) callconv(.C) void = null,
/// Goto tab
goto_tab: ?*const fn (SurfaceUD, GotoTab) callconv(.C) void = null,
goto_tab: ?*const fn (SurfaceUD, apprt.GotoTab) callconv(.C) void = null,
/// Toggle fullscreen for current window.
toggle_fullscreen: ?*const fn (SurfaceUD, configpkg.NonNativeFullscreen) callconv(.C) void = null,
@ -135,13 +135,6 @@ pub const App = struct {
mouse_over_link: ?*const fn (SurfaceUD, ?[*]const u8, usize) void = null,
};
/// Special values for the goto_tab callback.
const GotoTab = enum(i32) {
previous = -1,
next = -2,
_,
};
core_app: *CoreApp,
config: *const Config,
opts: Options,
@ -994,36 +987,13 @@ pub const Surface = struct {
};
}
pub fn gotoTab(self: *Surface, n: usize) void {
pub fn gotoTab(self: *Surface, tab: apprt.GotoTab) void {
const func = self.app.opts.goto_tab orelse {
log.info("runtime embedder does not goto_tab", .{});
return;
};
const idx = std.math.cast(i32, n) orelse {
log.warn("cannot cast tab index to i32 n={}", .{n});
return;
};
func(self.userdata, @enumFromInt(idx));
}
pub fn gotoPreviousTab(self: *Surface) void {
const func = self.app.opts.goto_tab orelse {
log.info("runtime embedder does not goto_tab", .{});
return;
};
func(self.userdata, .previous);
}
pub fn gotoNextTab(self: *Surface) void {
const func = self.app.opts.goto_tab orelse {
log.info("runtime embedder does not goto_tab", .{});
return;
};
func(self.userdata, .next);
func(self.userdata, tab);
}
pub fn toggleFullscreen(self: *Surface, nonNativeFullscreen: configpkg.NonNativeFullscreen) void {

View File

@ -795,31 +795,7 @@ pub fn hasTabs(self: *const Surface) bool {
return window.hasTabs();
}
pub fn gotoPreviousTab(self: *Surface) void {
const window = self.container.window() orelse {
log.info(
"gotoPreviousTab invalid for container={s}",
.{@tagName(self.container)},
);
return;
};
window.gotoPreviousTab(self);
}
pub fn gotoNextTab(self: *Surface) void {
const window = self.container.window() orelse {
log.info(
"gotoNextTab invalid for container={s}",
.{@tagName(self.container)},
);
return;
};
window.gotoNextTab(self);
}
pub fn gotoTab(self: *Surface, n: usize) void {
pub fn gotoTab(self: *Surface, tab: apprt.GotoTab) void {
const window = self.container.window() orelse {
log.info(
"gotoTab invalid for container={s}",
@ -828,7 +804,12 @@ pub fn gotoTab(self: *Surface, n: usize) void {
return;
};
window.gotoTab(n);
switch (tab) {
.previous => window.gotoPreviousTab(self),
.next => window.gotoNextTab(self),
.last => window.gotoLastTab(),
else => window.gotoTab(@intCast(@intFromEnum(tab))),
}
}
pub fn setShouldClose(self: *Surface) void {

View File

@ -288,6 +288,13 @@ pub fn gotoNextTab(self: *Window, surface: *Surface) void {
self.focusCurrentTab();
}
/// Go to the next tab for a surface.
pub fn gotoLastTab(self: *Window) void {
const max = c.gtk_notebook_get_n_pages(self.notebook) -| 1;
c.gtk_notebook_set_current_page(self.notebook, max);
self.focusCurrentTab();
}
/// Go to the specific tab index.
pub fn gotoTab(self: *Window, n: usize) void {
if (n == 0) return;

View File

@ -62,6 +62,16 @@ pub const DesktopNotification = struct {
body: []const u8,
};
/// The tab to jump to. This is non-exhaustive so that integer values represent
/// the index (zero-based) of the tab to jump to. Negative values are special
/// values.
pub const GotoTab = enum(c_int) {
previous = -1,
next = -2,
last = -3,
_,
};
// This is made extern (c_int) to make interop easier with our embedded
// runtime. The small size cost doesn't make a difference in our union.
pub const SplitDirection = enum(c_int) {

View File

@ -1894,6 +1894,11 @@ pub fn default(alloc_gpa: Allocator) Allocator.Error!Config {
.{ .key = .{ .translated = .right_bracket }, .mods = .{ .super = true, .shift = true } },
.{ .next_tab = {} },
);
try result.keybind.set.put(
alloc,
.{ .key = .{ .physical = inputpkg.Key.zero }, .mods = .{ .super = true } },
.{ .last_tab = {} },
);
try result.keybind.set.put(
alloc,
.{ .key = .{ .translated = .d }, .mods = .{ .super = true } },

View File

@ -240,6 +240,9 @@ pub const Action = union(enum) {
/// Go to the next tab.
next_tab: void,
/// Go to the last tab (the one with the highest index)
last_tab: void,
/// Go to the tab with the specific number, 1-indexed.
goto_tab: usize,