mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
HACK: ctrl-tab to swap to last active tab
KVO on tabGroup.selectedWindow works but I can't figure out how to detect when the tabGroup changes, so the observer gets attached to the wrong tabGroup TODO: lastActiveTabIndex needs to be per-tab-group, not global, but I can't figure out how to store per-tab-group or per-associated-window state
This commit is contained in:
@ -142,6 +142,7 @@ typedef enum {
|
||||
typedef enum {
|
||||
GHOSTTY_TAB_PREVIOUS = -1,
|
||||
GHOSTTY_TAB_NEXT = -2,
|
||||
GHOSTTY_TAB_LAST_ACTIVE = -3,
|
||||
} ghostty_tab_e;
|
||||
|
||||
typedef enum {
|
||||
|
@ -36,6 +36,7 @@ class AppDelegate: NSObject,
|
||||
@IBOutlet private var menuPaste: NSMenuItem?
|
||||
@IBOutlet private var menuSelectAll: NSMenuItem?
|
||||
|
||||
@IBOutlet private var menuLastActiveTab: NSMenuItem?
|
||||
@IBOutlet private var menuToggleFullScreen: NSMenuItem?
|
||||
@IBOutlet private var menuZoomSplit: NSMenuItem?
|
||||
@IBOutlet private var menuPreviousSplit: NSMenuItem?
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22505"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22689"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
@ -22,6 +22,7 @@
|
||||
<outlet property="menuDecreaseFontSize" destination="kzb-SZ-dOA" id="Y1B-Vh-6Z2"/>
|
||||
<outlet property="menuEqualizeSplits" destination="3gH-VD-vL9" id="SiZ-ce-FOF"/>
|
||||
<outlet property="menuIncreaseFontSize" destination="CIH-ey-Z6x" id="hkc-9C-80E"/>
|
||||
<outlet property="menuLastActiveTab" destination="ucq-9T-8lf" id="KbP-Y4-YBa"/>
|
||||
<outlet property="menuMoveSplitDividerDown" destination="Zj7-2W-fdF" id="997-LL-nlN"/>
|
||||
<outlet property="menuMoveSplitDividerLeft" destination="wSR-ny-j1a" id="HCZ-CI-2ob"/>
|
||||
<outlet property="menuMoveSplitDividerRight" destination="CcX-ql-QU4" id="rIn-PK-fVM"/>
|
||||
@ -41,8 +42,8 @@
|
||||
<outlet property="menuSelectSplitLeft" destination="cTK-oy-KuV" id="Jpr-5q-dqz"/>
|
||||
<outlet property="menuSelectSplitRight" destination="upj-mc-L7X" id="nLY-o1-lky"/>
|
||||
<outlet property="menuServices" destination="aQe-vS-j8Q" id="uWQ-Wo-T1L"/>
|
||||
<outlet property="menuSplitRight" destination="VUR-Ld-nLx" id="RxO-Zw-ovb"/>
|
||||
<outlet property="menuSplitDown" destination="UDZ-4y-6xL" id="fgZ-Wb-8OR"/>
|
||||
<outlet property="menuSplitRight" destination="VUR-Ld-nLx" id="RxO-Zw-ovb"/>
|
||||
<outlet property="menuTerminalInspector" destination="QwP-M5-fvh" id="wJi-Dh-S9f"/>
|
||||
<outlet property="menuToggleFullScreen" destination="8kY-Pi-KaY" id="yQg-6V-OO6"/>
|
||||
<outlet property="menuZoomSplit" destination="oPd-mn-IEH" id="wTu-jK-egI"/>
|
||||
@ -233,7 +234,17 @@
|
||||
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
|
||||
<menuItem isSeparatorItem="YES" id="Bws-Hg-Q2a"/>
|
||||
<menuItem title="Show Next Tab" id="ucq-9T-8lf">
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
CQ
|
||||
</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" control="YES"/>
|
||||
<connections>
|
||||
<action selector="selectLastActiveTab:" target="-1" id="nJL-fj-u7w"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="CMt-XK-G4G"/>
|
||||
<menuItem title="Toggle Full Screen" keyEquivalent="f" id="8kY-Pi-KaY">
|
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||
<connections>
|
||||
|
@ -550,6 +550,17 @@ class TerminalController: NSWindowController, NSWindowDelegate,
|
||||
splitMoveFocus(direction: .right)
|
||||
}
|
||||
|
||||
@IBAction func selectLastActiveTab(_ sender: Any) {
|
||||
guard let surface = focusedSurface else { return }
|
||||
NotificationCenter.default.post(
|
||||
name: Ghostty.Notification.ghosttyGotoTab,
|
||||
object: surface,
|
||||
userInfo: [
|
||||
Ghostty.Notification.GotoTabKey: GHOSTTY_TAB_LAST_ACTIVE.rawValue,
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction func equalizeSplits(_ sender: Any) {
|
||||
guard let surface = focusedSurface?.surface else { return }
|
||||
ghostty.splitEqualize(surface: surface)
|
||||
@ -710,6 +721,8 @@ class TerminalController: NSWindowController, NSWindowDelegate,
|
||||
} else {
|
||||
finalIndex = selectedIndex + 1
|
||||
}
|
||||
} else if (tabIndex == GHOSTTY_TAB_LAST_ACTIVE.rawValue) {
|
||||
finalIndex = ghostty.lastActiveTabIndex
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
@ -108,6 +108,13 @@ class TerminalWindow: NSWindow {
|
||||
resetZoomTabButton.contentTintColor = .secondaryLabelColor
|
||||
resetZoomToolbarButton.contentTintColor = .tertiaryLabelColor
|
||||
tab.attributedTitle = attributedTitle
|
||||
|
||||
// if resigned key and not selected tab, then we were the last active tab
|
||||
if let tabGroup,
|
||||
tabGroup.selectedWindow != self,
|
||||
let selfIndex = tabGroup.windows.firstIndex(of: self) {
|
||||
(windowController as? TerminalController)?.ghostty.lastActiveTabIndex = selfIndex
|
||||
}
|
||||
}
|
||||
|
||||
override func layoutIfNeeded() {
|
||||
|
@ -24,6 +24,9 @@ extension Ghostty {
|
||||
/// Optional delegate
|
||||
weak var delegate: GhosttyAppDelegate?
|
||||
|
||||
// TODO: this needs to be per-tab-group
|
||||
var lastActiveTabIndex = 0
|
||||
|
||||
/// The readiness value of the state.
|
||||
@Published var readiness: Readiness = .loading
|
||||
|
||||
|
@ -3424,6 +3424,20 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
} else log.warn("runtime doesn't implement gotoPreviousTab", .{});
|
||||
},
|
||||
|
||||
.last_active_tab => {
|
||||
log.warn("last_active_tab is deprecated, use gotoLastActiveTab", .{});
|
||||
if (@hasDecl(apprt.Surface, "hasTabs")) {
|
||||
if (!self.rt_surface.hasTabs()) {
|
||||
log.debug("surface has no tabs, ignoring last_active_tab binding", .{});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (@hasDecl(apprt.Surface, "gotoLastActiveTab")) {
|
||||
self.rt_surface.gotoLastActiveTab();
|
||||
} else log.warn("runtime doesn't implement gotoLastActiveTab", .{});
|
||||
},
|
||||
|
||||
.next_tab => {
|
||||
if (@hasDecl(apprt.Surface, "hasTabs")) {
|
||||
if (!self.rt_surface.hasTabs()) {
|
||||
|
@ -134,6 +134,7 @@ pub const App = struct {
|
||||
const GotoTab = enum(i32) {
|
||||
previous = -1,
|
||||
next = -2,
|
||||
last_active = -3,
|
||||
_,
|
||||
};
|
||||
|
||||
@ -995,6 +996,15 @@ pub const Surface = struct {
|
||||
func(self.userdata, .previous);
|
||||
}
|
||||
|
||||
pub fn gotoLastActiveTab(self: *Surface) void {
|
||||
const func = self.app.opts.goto_tab orelse {
|
||||
log.info("runtime embedder does not goto_tab", .{});
|
||||
return;
|
||||
};
|
||||
|
||||
func(self.userdata, .last_active);
|
||||
}
|
||||
|
||||
pub fn gotoNextTab(self: *Surface) void {
|
||||
const func = self.app.opts.goto_tab orelse {
|
||||
log.info("runtime embedder does not goto_tab", .{});
|
||||
|
@ -1565,6 +1565,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 = .{ .translated = .tab }, .mods = .{ .ctrl = true } },
|
||||
.{ .last_active_tab = {} },
|
||||
);
|
||||
try result.keybind.set.put(
|
||||
alloc,
|
||||
.{ .key = .{ .translated = .d }, .mods = .{ .super = true } },
|
||||
|
@ -215,6 +215,9 @@ pub const Action = union(enum) {
|
||||
/// Go to the next tab.
|
||||
next_tab: void,
|
||||
|
||||
/// Go to the last active tab.
|
||||
last_active_tab: void,
|
||||
|
||||
/// Go to the tab with the specific number, 1-indexed.
|
||||
goto_tab: usize,
|
||||
|
||||
|
Reference in New Issue
Block a user