mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: navigate splits directionally
This commit is contained in:
@ -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:
|
Self.moveFocus(next, previous: node)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Reference in New Issue
Block a user