From 3976da8149544362a8210e5fdff5563c0dd39c72 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 11 Mar 2023 17:55:31 -0800 Subject: [PATCH] macos: navigate splits directionally --- macos/Sources/Ghostty/Ghostty.SplitView.swift | 26 +++++++++++------- macos/Sources/Ghostty/Package.swift | 26 +++++++++++++++++- macos/Sources/GhosttyApp.swift | 27 ++++++++++++------- src/config.zig | 20 ++++++++++++++ 4 files changed, 79 insertions(+), 20 deletions(-) diff --git a/macos/Sources/Ghostty/Ghostty.SplitView.swift b/macos/Sources/Ghostty/Ghostty.SplitView.swift index b6020e18b..4cff3217c 100644 --- a/macos/Sources/Ghostty/Ghostty.SplitView.swift +++ b/macos/Sources/Ghostty/Ghostty.SplitView.swift @@ -92,6 +92,21 @@ extension Ghostty { /// No neighbors, used by the root node. static let empty: Self = .init() + /// Get the node for a given direction. + func get(direction: SplitFocusDirection) -> SplitNode? { + let map: [SplitFocusDirection : KeyPath] = [ + .previous: \.previous, + .next: \.next, + .top: \.top, + .bottom: \.bottom, + .left: \.left, + .right: \.right, + ] + + guard let path = map[direction] else { return nil } + return self[keyPath: path] + } + /// Update multiple keys and return a new copy. func update(_ attrs: [WritableKeyPath: SplitNode?]) -> Self { var clone = self @@ -216,15 +231,8 @@ extension Ghostty { // Determine our desired direction guard let directionAny = notification.userInfo?[Notification.SplitDirectionKey] else { return } guard let direction = directionAny as? SplitFocusDirection else { return } - switch (direction) { - case .previous: - guard let next = neighbors.previous else { return } - Self.moveFocus(next, previous: node) - - case .next: - guard let next = neighbors.next else { return } - Self.moveFocus(next, previous: node) - } + guard let next = neighbors.get(direction: direction) else { return } + Self.moveFocus(next, previous: node) } /// There is a bug I can't figure out where when changing the split state, the terminal view diff --git a/macos/Sources/Ghostty/Package.swift b/macos/Sources/Ghostty/Package.swift index 92f28b36a..ea0b7fd50 100644 --- a/macos/Sources/Ghostty/Package.swift +++ b/macos/Sources/Ghostty/Package.swift @@ -11,7 +11,7 @@ struct Ghostty { extension Ghostty { /// An enum that is used for the directions that a split focus event can change. enum SplitFocusDirection { - case previous, next + case previous, next, top, bottom, left, right /// Initialize from a Ghostty API enum. static func from(direction: ghostty_split_focus_direction_e) -> Self? { @@ -22,6 +22,18 @@ extension Ghostty { case GHOSTTY_SPLIT_FOCUS_NEXT: return .next + case GHOSTTY_SPLIT_FOCUS_TOP: + return .top + + case GHOSTTY_SPLIT_FOCUS_BOTTOM: + return .bottom + + case GHOSTTY_SPLIT_FOCUS_LEFT: + return .left + + case GHOSTTY_SPLIT_FOCUS_RIGHT: + return .right + default: return nil } @@ -34,6 +46,18 @@ extension Ghostty { case .next: return GHOSTTY_SPLIT_FOCUS_NEXT + + case .top: + return GHOSTTY_SPLIT_FOCUS_TOP + + case .bottom: + return GHOSTTY_SPLIT_FOCUS_BOTTOM + + case .left: + return GHOSTTY_SPLIT_FOCUS_LEFT + + case .right: + return GHOSTTY_SPLIT_FOCUS_RIGHT } } } diff --git a/macos/Sources/GhosttyApp.swift b/macos/Sources/GhosttyApp.swift index 8fb421e99..7c12e8f4e 100644 --- a/macos/Sources/GhosttyApp.swift +++ b/macos/Sources/GhosttyApp.swift @@ -40,8 +40,21 @@ struct GhosttyApp: App { CommandGroup(before: .windowArrangement) { Divider() - Button("Select Previous Split", action: splitMoveFocusPrevious).keyboardShortcut("[", modifiers: .command) - Button("Select Next Split", action: splitMoveFocusNext).keyboardShortcut("]", modifiers: .command) + Button("Select Previous Split") { splitMoveFocus(direction: .previous) } + .keyboardShortcut("[", modifiers: .command) + Button("Select Next Split") { splitMoveFocus(direction: .next) } + .keyboardShortcut("]", modifiers: .command) + Menu("Select Split") { + Button("Select Split Above") { splitMoveFocus(direction: .top) } + .keyboardShortcut(.upArrow, modifiers: [.command, .option]) + Button("Select Split Below") { splitMoveFocus(direction: .bottom) } + .keyboardShortcut(.downArrow, modifiers: [.command, .option]) + Button("Select Split Left") { splitMoveFocus(direction: .left) } + .keyboardShortcut(.leftArrow, modifiers: [.command, .option]) + Button("Select Split Right") { splitMoveFocus(direction: .right)} + .keyboardShortcut(.rightArrow, modifiers: [.command, .option]) + } + Divider() } } @@ -84,16 +97,10 @@ struct GhosttyApp: App { ghostty.split(surface: surface, direction: GHOSTTY_SPLIT_DOWN) } - func splitMoveFocusPrevious() { + func splitMoveFocus(direction: Ghostty.SplitFocusDirection) { guard let surfaceView = focusedSurface else { return } guard let surface = surfaceView.surface else { return } - ghostty.splitMoveFocus(surface: surface, direction: .previous) - } - - func splitMoveFocusNext() { - guard let surfaceView = focusedSurface else { return } - guard let surface = surfaceView.surface else { return } - ghostty.splitMoveFocus(surface: surface, direction: .next) + ghostty.splitMoveFocus(surface: surface, direction: direction) } } diff --git a/src/config.zig b/src/config.zig index 3df202cd4..a3c88c1e0 100644 --- a/src/config.zig +++ b/src/config.zig @@ -321,6 +321,26 @@ pub const Config = struct { .{ .key = .right_bracket, .mods = .{ .super = true } }, .{ .goto_split = .next }, ); + try result.keybind.set.put( + alloc, + .{ .key = .up, .mods = .{ .super = true, .alt = true } }, + .{ .goto_split = .top }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .down, .mods = .{ .super = true, .alt = true } }, + .{ .goto_split = .bottom }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .left, .mods = .{ .super = true, .alt = true } }, + .{ .goto_split = .left }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .right, .mods = .{ .super = true, .alt = true } }, + .{ .goto_split = .right }, + ); { // Cmd+N for goto tab N const start = @enumToInt(inputpkg.Key.one);