add undo/redo keybindings, default them on macOS

This commit is contained in:
Mitchell Hashimoto
2025-06-06 11:34:33 -07:00
parent e1847da139
commit b044f4864a
10 changed files with 132 additions and 10 deletions

View File

@@ -4337,6 +4337,18 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
{},
),
.undo => return try self.rt_app.performAction(
.{ .surface = self },
.undo,
{},
),
.redo => return try self.rt_app.performAction(
.{ .surface = self },
.redo,
{},
),
.select_all => {
const sel = self.io.terminal.screen.selectAll();
if (sel) |s| {

View File

@@ -258,6 +258,13 @@ pub const Action = union(Key) {
/// it needs to ring the bell. This is usually a sound or visual effect.
ring_bell,
/// Undo the last action. See the "undo" keybinding for more
/// details on what can and cannot be undone.
undo,
/// Redo the last undone action.
redo,
check_for_updates,
/// Sync with: ghostty_action_tag_e
@@ -307,6 +314,8 @@ pub const Action = union(Key) {
config_change,
close_window,
ring_bell,
undo,
redo,
check_for_updates,
};

View File

@@ -26,7 +26,7 @@ pub fn genConfig(writer: anytype, cli: bool) !void {
\\
);
@setEvalBranchQuota(3000);
@setEvalBranchQuota(5000);
inline for (@typeInfo(Config).@"struct".fields) |field| {
if (field.name[0] == '_') continue;
@@ -94,6 +94,7 @@ pub fn genKeybindActions(writer: anytype) !void {
const info = @typeInfo(KeybindAction);
std.debug.assert(info == .@"union");
@setEvalBranchQuota(5000);
inline for (info.@"union".fields) |field| {
if (field.name[0] == '_') continue;

View File

@@ -4898,6 +4898,18 @@ pub const Keybinds = struct {
.{ .key = .{ .unicode = 'q' }, .mods = .{ .super = true } },
.{ .quit = {} },
);
try self.set.putFlags(
alloc,
.{ .key = .{ .unicode = 'z' }, .mods = .{ .super = true } },
.{ .undo = {} },
.{ .performable = true },
);
try self.set.putFlags(
alloc,
.{ .key = .{ .unicode = 'z' }, .mods = .{ .super = true, .shift = true } },
.{ .redo = {} },
.{ .performable = true },
);
try self.set.putFlags(
alloc,
.{ .key = .{ .unicode = 'k' }, .mods = .{ .super = true } },

View File

@@ -655,6 +655,35 @@ pub const Action = union(enum) {
/// Only implemented on macOS.
check_for_updates,
/// Undo the last undoable action for the focused surface or terminal,
/// if possible. This can undo actions such as closing tabs or
/// windows.
///
/// Not every action in Ghostty can be undone or redone. The list
/// of actions support undo/redo is currently limited to:
///
/// - New window, close window
/// - New tab, close tab
/// - New split, close split
///
/// All actions are only undoable/redoable for a limited time.
/// For example, restoring a closed split can only be done for
/// some number of seconds since the split was closed. The exact
/// amount is configured with `TODO`.
///
/// The undo/redo actions being limited ensures that there is
/// bounded memory usage over time, closed surfaces don't continue running
/// in the background indefinitely, and the keybinds become available
/// for terminal applications to use.
///
/// Only implemented on macOS.
undo,
/// Redo the last undoable action for the focused surface or terminal,
/// if possible. See "undo" for more details on what can and cannot
/// be undone or redone.
redo,
/// Quit Ghostty.
quit,
@@ -991,6 +1020,8 @@ pub const Action = union(enum) {
.toggle_secure_input,
.toggle_command_palette,
.reset_window_size,
.undo,
.redo,
.crash,
=> .surface,

View File

@@ -409,6 +409,18 @@ fn actionCommands(action: Action.Key) []const Command {
.description = "Check for updates to the application.",
}},
.undo => comptime &.{.{
.action = .undo,
.title = "Undo",
.description = "Undo the last action.",
}},
.redo => comptime &.{.{
.action = .redo,
.title = "Redo",
.description = "Redo the last undone action.",
}},
.quit => comptime &.{.{
.action = .quit,
.title = "Quit",