macos: navigate splits directionally

This commit is contained in:
Mitchell Hashimoto
2023-03-11 17:55:31 -08:00
parent 04c38ef3b0
commit 3976da8149
4 changed files with 79 additions and 20 deletions

View File

@ -92,6 +92,21 @@ extension Ghostty {
/// No neighbors, used by the root node. /// No neighbors, used by the root node.
static let empty: Self = .init() static let empty: Self = .init()
/// Get the node for a given direction.
func get(direction: SplitFocusDirection) -> SplitNode? {
let map: [SplitFocusDirection : KeyPath<Self, SplitNode?>] = [
.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. /// Update multiple keys and return a new copy.
func update(_ attrs: [WritableKeyPath<Self, SplitNode?>: SplitNode?]) -> Self { func update(_ attrs: [WritableKeyPath<Self, SplitNode?>: SplitNode?]) -> Self {
var clone = self var clone = self
@ -216,15 +231,8 @@ extension Ghostty {
// Determine our desired direction // Determine our desired direction
guard let directionAny = notification.userInfo?[Notification.SplitDirectionKey] else { return } guard let directionAny = notification.userInfo?[Notification.SplitDirectionKey] else { return }
guard let direction = directionAny as? SplitFocusDirection else { return } guard let direction = directionAny as? SplitFocusDirection else { return }
switch (direction) { guard let next = neighbors.get(direction: direction) else { return }
case .previous:
guard let next = neighbors.previous else { return }
Self.moveFocus(next, previous: node) Self.moveFocus(next, previous: node)
case .next:
guard let next = neighbors.next 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 /// There is a bug I can't figure out where when changing the split state, the terminal view

View File

@ -11,7 +11,7 @@ struct Ghostty {
extension Ghostty { extension Ghostty {
/// An enum that is used for the directions that a split focus event can change. /// An enum that is used for the directions that a split focus event can change.
enum SplitFocusDirection { enum SplitFocusDirection {
case previous, next case previous, next, top, bottom, left, right
/// Initialize from a Ghostty API enum. /// Initialize from a Ghostty API enum.
static func from(direction: ghostty_split_focus_direction_e) -> Self? { static func from(direction: ghostty_split_focus_direction_e) -> Self? {
@ -22,6 +22,18 @@ extension Ghostty {
case GHOSTTY_SPLIT_FOCUS_NEXT: case GHOSTTY_SPLIT_FOCUS_NEXT:
return .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: default:
return nil return nil
} }
@ -34,6 +46,18 @@ extension Ghostty {
case .next: case .next:
return GHOSTTY_SPLIT_FOCUS_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
} }
} }
} }

View File

@ -40,8 +40,21 @@ struct GhosttyApp: App {
CommandGroup(before: .windowArrangement) { CommandGroup(before: .windowArrangement) {
Divider() Divider()
Button("Select Previous Split", action: splitMoveFocusPrevious).keyboardShortcut("[", modifiers: .command) Button("Select Previous Split") { splitMoveFocus(direction: .previous) }
Button("Select Next Split", action: splitMoveFocusNext).keyboardShortcut("]", modifiers: .command) .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() Divider()
} }
} }
@ -84,16 +97,10 @@ struct GhosttyApp: App {
ghostty.split(surface: surface, direction: GHOSTTY_SPLIT_DOWN) ghostty.split(surface: surface, direction: GHOSTTY_SPLIT_DOWN)
} }
func splitMoveFocusPrevious() { func splitMoveFocus(direction: Ghostty.SplitFocusDirection) {
guard let surfaceView = focusedSurface else { return } guard let surfaceView = focusedSurface else { return }
guard let surface = surfaceView.surface else { return } guard let surface = surfaceView.surface else { return }
ghostty.splitMoveFocus(surface: surface, direction: .previous) ghostty.splitMoveFocus(surface: surface, direction: direction)
}
func splitMoveFocusNext() {
guard let surfaceView = focusedSurface else { return }
guard let surface = surfaceView.surface else { return }
ghostty.splitMoveFocus(surface: surface, direction: .next)
} }
} }

View File

@ -321,6 +321,26 @@ pub const Config = struct {
.{ .key = .right_bracket, .mods = .{ .super = true } }, .{ .key = .right_bracket, .mods = .{ .super = true } },
.{ .goto_split = .next }, .{ .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 // Cmd+N for goto tab N
const start = @enumToInt(inputpkg.Key.one); const start = @enumToInt(inputpkg.Key.one);