Skip to content

Commit

Permalink
Merge pull request #2255 from pluiedev/feat/situs-inversus
Browse files Browse the repository at this point in the history
DRAFT: implement splitting leftwards and upwards
  • Loading branch information
mitchellh authored Oct 8, 2024
2 parents 1b5a443 + 3928753 commit 78d6cfb
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 12 deletions.
2 changes: 2 additions & 0 deletions include/ghostty.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ typedef struct {
typedef enum {
GHOSTTY_SPLIT_DIRECTION_RIGHT,
GHOSTTY_SPLIT_DIRECTION_DOWN,
GHOSTTY_SPLIT_DIRECTION_LEFT,
GHOSTTY_SPLIT_DIRECTION_UP,
} ghostty_action_split_direction_e;

// apprt.action.GotoSplit
Expand Down
9 changes: 9 additions & 0 deletions macos/Sources/Ghostty/Ghostty.SplitNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,15 @@ extension Ghostty {
bottomRight.parent = self
}

// Move the top left node to the bottom right and vice versa,
// preserving the size.
func swap() {
let topLeft: SplitNode = self.topLeft
self.topLeft = bottomRight
self.bottomRight = topLeft
self.split = 1 - self.split
}

/// Resize the split by moving the split divider in the given
/// direction by the given amount. If this container is not split
/// in the given direction, navigate up the tree until we find a
Expand Down
18 changes: 16 additions & 2 deletions macos/Sources/Ghostty/Ghostty.TerminalSplit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,21 @@ extension Ghostty {
// Determine our desired direction
guard let directionAny = notification.userInfo?["direction"] else { return }
guard let direction = directionAny as? ghostty_action_split_direction_e else { return }
var splitDirection: SplitViewDirection
let splitDirection: SplitViewDirection
let swap: Bool
switch (direction) {
case GHOSTTY_SPLIT_DIRECTION_RIGHT:
splitDirection = .horizontal

swap = false
case GHOSTTY_SPLIT_DIRECTION_LEFT:
splitDirection = .horizontal
swap = true
case GHOSTTY_SPLIT_DIRECTION_DOWN:
splitDirection = .vertical
swap = false
case GHOSTTY_SPLIT_DIRECTION_UP:
splitDirection = .vertical
swap = true

default:
return
Expand All @@ -240,6 +248,12 @@ extension Ghostty {

// See moveFocus comment, we have to run this whenever split changes.
Ghostty.moveFocus(to: container.bottomRight.preferredFocus(), from: node!.preferredFocus())

// If we are swapping, swap now. We do this after our focus event
// so that focus is in the right place.
if swap {
container.swap()
}
}

/// This handles the event to move the split focus (i.e. previous/next) from a keyboard event.
Expand Down
2 changes: 2 additions & 0 deletions src/Surface.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3835,7 +3835,9 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
.new_split,
switch (direction) {
.right => .right,
.left => .left,
.down => .down,
.up => .up,
.auto => if (self.screen_size.width > self.screen_size.height)
.right
else
Expand Down
2 changes: 2 additions & 0 deletions src/apprt/action.zig
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ pub const Action = union(Key) {
pub const SplitDirection = enum(c_int) {
right,
down,
left,
up,
};

// This is made extern (c_int) to make interop easier with our embedded
Expand Down
2 changes: 2 additions & 0 deletions src/apprt/gtk/App.zig
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,8 @@ fn syncActionAccelerators(self: *App) !void {
try self.syncActionAccelerator("win.new_tab", .{ .new_tab = {} });
try self.syncActionAccelerator("win.split_right", .{ .new_split = .right });
try self.syncActionAccelerator("win.split_down", .{ .new_split = .down });
try self.syncActionAccelerator("win.split_left", .{ .new_split = .left });
try self.syncActionAccelerator("win.split_up", .{ .new_split = .up });
try self.syncActionAccelerator("win.copy", .{ .copy_to_clipboard = {} });
try self.syncActionAccelerator("win.paste", .{ .paste_from_clipboard = {} });
try self.syncActionAccelerator("win.reset", .{ .reset = {} });
Expand Down
27 changes: 19 additions & 8 deletions src/apprt/gtk/Split.zig
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ pub const Orientation = enum {

pub fn fromDirection(direction: apprt.action.SplitDirection) Orientation {
return switch (direction) {
.right => .horizontal,
.down => .vertical,
.right, .left => .horizontal,
.down, .up => .vertical,
};
}

Expand Down Expand Up @@ -80,8 +80,8 @@ pub fn init(

// Create the actual GTKPaned, attach the proper children.
const orientation: c_uint = switch (direction) {
.right => c.GTK_ORIENTATION_HORIZONTAL,
.down => c.GTK_ORIENTATION_VERTICAL,
.right, .left => c.GTK_ORIENTATION_HORIZONTAL,
.down, .up => c.GTK_ORIENTATION_VERTICAL,
};
const paned = c.gtk_paned_new(orientation);
errdefer c.g_object_unref(paned);
Expand All @@ -94,14 +94,25 @@ pub fn init(
// we're inheriting its parent. The sibling points to its location
// in the split, and the surface points to the other location.
const container = sibling.container;
sibling.container = .{ .split_tl = &self.top_left };
surface.container = .{ .split_br = &self.bottom_right };
const tl: *Surface, const br: *Surface = switch (direction) {
.right, .down => right_down: {
sibling.container = .{ .split_tl = &self.top_left };
surface.container = .{ .split_br = &self.bottom_right };
break :right_down .{ sibling, surface };
},

.left, .up => left_up: {
sibling.container = .{ .split_br = &self.bottom_right };
surface.container = .{ .split_tl = &self.top_left };
break :left_up .{ surface, sibling };
},
};

self.* = .{
.paned = @ptrCast(paned),
.container = container,
.top_left = .{ .surface = sibling },
.bottom_right = .{ .surface = surface },
.top_left = .{ .surface = tl },
.bottom_right = .{ .surface = br },
.orientation = Orientation.fromDirection(direction),
};

Expand Down
28 changes: 28 additions & 0 deletions src/apprt/gtk/Window.zig
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@ fn initActions(self: *Window) void {
.{ "new_tab", &gtkActionNewTab },
.{ "split_right", &gtkActionSplitRight },
.{ "split_down", &gtkActionSplitDown },
.{ "split_left", &gtkActionSplitLeft },
.{ "split_up", &gtkActionSplitUp },
.{ "toggle_inspector", &gtkActionToggleInspector },
.{ "copy", &gtkActionCopy },
.{ "paste", &gtkActionPaste },
Expand Down Expand Up @@ -812,6 +814,32 @@ fn gtkActionSplitDown(
};
}

fn gtkActionSplitLeft(
_: *c.GSimpleAction,
_: *c.GVariant,
ud: ?*anyopaque,
) callconv(.C) void {
const self: *Window = @ptrCast(@alignCast(ud orelse return));
const surface = self.actionSurface() orelse return;
_ = surface.performBindingAction(.{ .new_split = .left }) catch |err| {
log.warn("error performing binding action error={}", .{err});
return;
};
}

fn gtkActionSplitUp(
_: *c.GSimpleAction,
_: *c.GVariant,
ud: ?*anyopaque,
) callconv(.C) void {
const self: *Window = @ptrCast(@alignCast(ud orelse return));
const surface = self.actionSurface() orelse return;
_ = surface.performBindingAction(.{ .new_split = .up }) catch |err| {
log.warn("error performing binding action error={}", .{err});
return;
};
}

fn gtkActionToggleInspector(
_: *c.GSimpleAction,
_: *c.GVariant,
Expand Down
4 changes: 2 additions & 2 deletions src/input/Binding.zig
Original file line number Diff line number Diff line change
Expand Up @@ -440,9 +440,9 @@ pub const Action = union(enum) {
pub const SplitDirection = enum {
right,
down,
left,
up,
auto, // splits along the larger direction

// Note: we don't support top or left yet
};

pub const SplitFocusDirection = enum {
Expand Down

0 comments on commit 78d6cfb

Please sign in to comment.