From 59daecc30402f9bf0940d909d2c99a00a9c8e2b0 Mon Sep 17 00:00:00 2001 From: Raiden1411 <67233402+Raiden1411@users.noreply.github.com> Date: Thu, 2 Nov 2023 21:34:14 +0000 Subject: [PATCH 1/4] feat(actions): add new list-keybinds action --- src/cli/action.zig | 5 ++ src/cli/list_keybinds.zig | 105 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 src/cli/list_keybinds.zig diff --git a/src/cli/action.zig b/src/cli/action.zig index 4151d7aa2..38cc1fbd7 100644 --- a/src/cli/action.zig +++ b/src/cli/action.zig @@ -3,6 +3,7 @@ const Allocator = std.mem.Allocator; const list_fonts = @import("list_fonts.zig"); const version = @import("version.zig"); +const list_keybinds = @import("list_keybinds.zig"); /// Special commands that can be invoked via CLI flags. These are all /// invoked by using `+` as a CLI flag. The only exception is @@ -14,6 +15,9 @@ pub const Action = enum { /// List available fonts @"list-fonts", + /// List available keybinds + @"list-keybinds", + pub const Error = error{ /// Multiple actions were detected. You can specify at most one /// action on the CLI otherwise the behavior desired is ambiguous. @@ -52,6 +56,7 @@ pub const Action = enum { return switch (self) { .version => try version.run(), .@"list-fonts" => try list_fonts.run(alloc), + .@"list-keybinds" => try list_keybinds.run(alloc), }; } }; diff --git a/src/cli/list_keybinds.zig b/src/cli/list_keybinds.zig new file mode 100644 index 000000000..2788de83d --- /dev/null +++ b/src/cli/list_keybinds.zig @@ -0,0 +1,105 @@ +const std = @import("std"); +const inputpkg = @import("../input.zig"); +const args = @import("args.zig"); +const Arena = std.heap.ArenaAllocator; +const Allocator = std.mem.Allocator; +const Config = @import("../config/Config.zig"); + +pub const Options = struct { + _arena: ?Arena = null, + default: bool = false, + + pub fn deinit(self: *Options) void { + if (self._arena) |arena| arena.deinit(); + self.* = undefined; + } +}; + +/// The "list-keybinds" command is used to list all the available keybinds for Ghostty. +/// +/// When executed without any arguments this will list the current keybinds loaded by the config file. +/// If no config file is found or there aren't any changes to the keybinds it will print out the default ones configured for Ghostty +/// +/// The "--default" argument will print out all the default keybinds configured for Ghostty +pub fn run(alloc: Allocator) !u8 { + var opts: Options = .{}; + defer opts.deinit(); + + var iter = try std.process.argsWithAllocator(alloc); + defer iter.deinit(); + try args.parse(Options, alloc, &opts, &iter); + + if (opts.default) { + return try listDefaultKeybinds(alloc); + } + + return try listKeybinds(alloc); +} + +fn listKeybinds(alloc: Allocator) !u8 { + var loaded_config = try Config.load(alloc); + defer loaded_config.deinit(); + + const stdout = std.io.getStdOut().writer(); + var iter = loaded_config.keybind.set.bindings.iterator(); + + return try iterConfig(&stdout, &iter); +} + +fn listDefaultKeybinds(alloc: Allocator) !u8 { + var default = try Config.default(alloc); + defer default.deinit(); + + const stdout = std.io.getStdOut().writer(); + var iter = default.keybind.set.bindings.iterator(); + + return try iterConfig(&stdout, &iter); +} + +fn iterConfig(stdout: anytype, iter: anytype) !u8 { + const start = @intFromEnum(inputpkg.Key.one); + var amount: u8 = 0; + + while (iter.next()) |next| { + const keys = next.key_ptr.*; + const value = next.value_ptr.*; + try stdout.print("{s}", .{@tagName(value)}); + switch (value) { + .goto_tab => |val| try stdout.print(" {d}:", .{val}), + .jump_to_prompt => |val| try stdout.print(" {d}:", .{val}), + .increase_font_size, .decrease_font_size => |val| try stdout.print(" {d}:", .{val}), + .goto_split => |val| try stdout.print(" {s}:", .{@tagName(val)}), + .inspector => |val| try stdout.print(" {s}:", .{@tagName(val)}), + inline else => try stdout.print(":", .{}), + } + + switch (keys.key) { + .one, .two, .three, .four, .five, .six, .seven, .eight, .nine => try stdout.print(" {d} +", .{(@intFromEnum(keys.key) - start) + 1}), + inline else => try stdout.print(" {s} +", .{@tagName(keys.key)}), + } + const fields = @typeInfo(@TypeOf(keys.mods)).Struct.fields; + inline for (fields) |field| { + switch (field.type) { + bool => { + if (@field(keys.mods, field.name)) { + if (amount >= 1) { + try stdout.print(" +", .{}); + } + try stdout.print(" {s}", .{field.name}); + amount += 1; + } + }, + u6 => continue, + + inline else => { + try stdout.print("\n", .{}); + continue; + }, + } + } + + amount = 0; + } + + return 0; +} From cb4bb8aaf6f4a3a43724ac09dbd5080edc390131 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 3 Nov 2023 15:57:14 -0700 Subject: [PATCH 2/4] input: add Binding.Action.format to convert action to string --- src/cli/list_keybinds.zig | 10 +--------- src/input/Binding.zig | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/cli/list_keybinds.zig b/src/cli/list_keybinds.zig index 2788de83d..625b6a8ec 100644 --- a/src/cli/list_keybinds.zig +++ b/src/cli/list_keybinds.zig @@ -63,15 +63,7 @@ fn iterConfig(stdout: anytype, iter: anytype) !u8 { while (iter.next()) |next| { const keys = next.key_ptr.*; const value = next.value_ptr.*; - try stdout.print("{s}", .{@tagName(value)}); - switch (value) { - .goto_tab => |val| try stdout.print(" {d}:", .{val}), - .jump_to_prompt => |val| try stdout.print(" {d}:", .{val}), - .increase_font_size, .decrease_font_size => |val| try stdout.print(" {d}:", .{val}), - .goto_split => |val| try stdout.print(" {s}:", .{@tagName(val)}), - .inspector => |val| try stdout.print(" {s}:", .{@tagName(val)}), - inline else => try stdout.print(":", .{}), - } + try stdout.print("{}", .{value}); switch (keys.key) { .one, .two, .three, .four, .five, .six, .seven, .eight, .nine => try stdout.print(" {d} +", .{(@intFromEnum(keys.key) - start) + 1}), diff --git a/src/input/Binding.zig b/src/input/Binding.zig index 9198e2f53..d0af763a9 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -303,6 +303,41 @@ pub const Action = union(enum) { return Error.InvalidAction; } + /// Implements the formatter for the fmt package. This encodes the + /// action back into the format used by parse. + pub fn format( + self: Action, + comptime layout: []const u8, + opts: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = layout; + _ = opts; + + switch (self) { + inline else => |value| { + const Value = @TypeOf(value); + const value_info = @typeInfo(Value); + + // All actions start with the tag. + try writer.print("{s}", .{@tagName(self)}); + + // Write the value depending on the type + switch (Value) { + void => {}, + []const u8 => try writer.print(":{s}", .{value}), + else => switch (value_info) { + .Enum => try writer.print(":{s}", .{@tagName(value)}), + .Float => try writer.print(":{d}", .{value}), + .Int => try writer.print(":{d}", .{value}), + .Struct => try writer.print("{} (not configurable)", .{value}), + else => @compileError("unhandled type: " ++ @typeName(Value)), + }, + } + }, + } + } + /// Returns a hash code that can be used to uniquely identify this /// action. pub fn hash(self: Action) u64 { From debeba99db71bd5ff42607bfddfcf5e14c3f3a37 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 3 Nov 2023 17:48:19 -0700 Subject: [PATCH 3/4] input: Binding.Trigger format --- src/cli/list_keybinds.zig | 32 +------------------------------- src/input/Binding.zig | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 31 deletions(-) diff --git a/src/cli/list_keybinds.zig b/src/cli/list_keybinds.zig index 625b6a8ec..1ce0d317c 100644 --- a/src/cli/list_keybinds.zig +++ b/src/cli/list_keybinds.zig @@ -57,40 +57,10 @@ fn listDefaultKeybinds(alloc: Allocator) !u8 { } fn iterConfig(stdout: anytype, iter: anytype) !u8 { - const start = @intFromEnum(inputpkg.Key.one); - var amount: u8 = 0; - while (iter.next()) |next| { const keys = next.key_ptr.*; const value = next.value_ptr.*; - try stdout.print("{}", .{value}); - - switch (keys.key) { - .one, .two, .three, .four, .five, .six, .seven, .eight, .nine => try stdout.print(" {d} +", .{(@intFromEnum(keys.key) - start) + 1}), - inline else => try stdout.print(" {s} +", .{@tagName(keys.key)}), - } - const fields = @typeInfo(@TypeOf(keys.mods)).Struct.fields; - inline for (fields) |field| { - switch (field.type) { - bool => { - if (@field(keys.mods, field.name)) { - if (amount >= 1) { - try stdout.print(" +", .{}); - } - try stdout.print(" {s}", .{field.name}); - amount += 1; - } - }, - u6 => continue, - - inline else => { - try stdout.print("\n", .{}); - continue; - }, - } - } - - amount = 0; + try stdout.print("{}={}\n", .{ keys, value }); } return 0; diff --git a/src/input/Binding.zig b/src/input/Binding.zig index d0af763a9..0531d6b12 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -416,6 +416,27 @@ pub const Trigger = extern struct { std.hash.autoHash(&hasher, self.physical); return hasher.final(); } + + /// Format implementation for fmt package. + pub fn format( + self: Trigger, + comptime layout: []const u8, + opts: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = layout; + _ = opts; + + // Modifiers first + if (self.mods.super) try writer.writeAll("super+"); + if (self.mods.ctrl) try writer.writeAll("ctrl+"); + if (self.mods.alt) try writer.writeAll("alt+"); + if (self.mods.shift) try writer.writeAll("shift+"); + + // Key + if (self.physical) try writer.writeAll("physical:"); + try writer.print("{s}", .{@tagName(self.key)}); + } }; /// A structure that contains a set of bindings and focuses on fast lookup. From e73d3db497d66b17155c5fedfb62e0aa281bc7e2 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 3 Nov 2023 17:51:34 -0700 Subject: [PATCH 4/4] cli/list-keybindings: stylistic changes --- src/cli/list_keybinds.zig | 55 ++++++++++++++------------------------- 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/src/cli/list_keybinds.zig b/src/cli/list_keybinds.zig index 1ce0d317c..8d9585be9 100644 --- a/src/cli/list_keybinds.zig +++ b/src/cli/list_keybinds.zig @@ -6,57 +6,40 @@ const Allocator = std.mem.Allocator; const Config = @import("../config/Config.zig"); pub const Options = struct { - _arena: ?Arena = null, + /// If true, print out the default keybinds instead of the ones + /// configured in the config file. default: bool = false, - pub fn deinit(self: *Options) void { - if (self._arena) |arena| arena.deinit(); - self.* = undefined; + pub fn deinit(self: Options) void { + _ = self; } }; -/// The "list-keybinds" command is used to list all the available keybinds for Ghostty. +/// The "list-keybinds" command is used to list all the available keybinds +/// for Ghostty. /// -/// When executed without any arguments this will list the current keybinds loaded by the config file. -/// If no config file is found or there aren't any changes to the keybinds it will print out the default ones configured for Ghostty +/// When executed without any arguments this will list the current keybinds +/// loaded by the config file. If no config file is found or there aren't any +/// changes to the keybinds it will print out the default ones configured for +/// Ghostty /// -/// The "--default" argument will print out all the default keybinds configured for Ghostty +/// The "--default" argument will print out all the default keybinds +/// configured for Ghostty pub fn run(alloc: Allocator) !u8 { var opts: Options = .{}; defer opts.deinit(); - var iter = try std.process.argsWithAllocator(alloc); - defer iter.deinit(); - try args.parse(Options, alloc, &opts, &iter); - - if (opts.default) { - return try listDefaultKeybinds(alloc); + { + var iter = try std.process.argsWithAllocator(alloc); + defer iter.deinit(); + try args.parse(Options, alloc, &opts, &iter); } - return try listKeybinds(alloc); -} - -fn listKeybinds(alloc: Allocator) !u8 { - var loaded_config = try Config.load(alloc); - defer loaded_config.deinit(); + var config = if (opts.default) try Config.default(alloc) else try Config.load(alloc); + defer config.deinit(); const stdout = std.io.getStdOut().writer(); - var iter = loaded_config.keybind.set.bindings.iterator(); - - return try iterConfig(&stdout, &iter); -} - -fn listDefaultKeybinds(alloc: Allocator) !u8 { - var default = try Config.default(alloc); - defer default.deinit(); - - const stdout = std.io.getStdOut().writer(); - var iter = default.keybind.set.bindings.iterator(); - - return try iterConfig(&stdout, &iter); -} - -fn iterConfig(stdout: anytype, iter: anytype) !u8 { + var iter = config.keybind.set.bindings.iterator(); while (iter.next()) |next| { const keys = next.key_ptr.*; const value = next.value_ptr.*;