summaryrefslogtreecommitdiff
path: root/src/cli/list_keybinds.zig
diff options
context:
space:
mode:
authorMitchell Hashimoto <m@mitchellh.com>2025-10-01 13:10:40 -0700
committerMitchell Hashimoto <m@mitchellh.com>2025-10-03 07:10:43 -0700
commitcb295b84a0ec274a43da59041fa4a199e799798d (patch)
treeac7d5a77a12ecf021983e20d7602226668d8aadb /src/cli/list_keybinds.zig
parent3770f97608409d450a1ab0364974ee7fb1c50f13 (diff)
Zig 0.15: zig build test
Diffstat (limited to 'src/cli/list_keybinds.zig')
-rw-r--r--src/cli/list_keybinds.zig110
1 files changed, 64 insertions, 46 deletions
diff --git a/src/cli/list_keybinds.zig b/src/cli/list_keybinds.zig
index 94f445eea..a8899a4f5 100644
--- a/src/cli/list_keybinds.zig
+++ b/src/cli/list_keybinds.zig
@@ -64,27 +64,38 @@ pub fn run(alloc: Allocator) !u8 {
var config = if (opts.default) try Config.default(alloc) else try Config.load(alloc);
defer config.deinit();
- const stdout = std.io.getStdOut();
+ var buffer: [1024]u8 = undefined;
+ const stdout: std.fs.File = .stdout();
+ var stdout_writer = stdout.writer(&buffer);
+ const writer = &stdout_writer.interface;
- // Despite being under the posix namespace, this also works on Windows as of zig 0.13.0
- if (tui.can_pretty_print and !opts.plain and std.posix.isatty(stdout.handle)) {
+ if (tui.can_pretty_print and !opts.plain and stdout.isTty()) {
var arena = std.heap.ArenaAllocator.init(alloc);
defer arena.deinit();
return prettyPrint(arena.allocator(), config.keybind);
} else {
try config.keybind.formatEntryDocs(
- configpkg.entryFormatter("keybind", stdout.writer()),
+ configpkg.entryFormatter("keybind", writer),
opts.docs,
);
}
+ // Don't forget to flush!
+ try writer.flush();
return 0;
}
-const TriggerList = std.SinglyLinkedList(Binding.Trigger);
+const TriggerNode = struct {
+ data: Binding.Trigger,
+ node: std.SinglyLinkedList.Node = .{},
+
+ pub fn get(node: *std.SinglyLinkedList.Node) *TriggerNode {
+ return @fieldParentPtr("node", node);
+ }
+};
const ChordBinding = struct {
- triggers: TriggerList,
+ triggers: std.SinglyLinkedList,
action: Binding.Action,
// Order keybinds based on various properties
@@ -109,7 +120,8 @@ const ChordBinding = struct {
const lhs_count: usize = blk: {
var count: usize = 0;
var maybe_trigger = lhs.triggers.first;
- while (maybe_trigger) |trigger| : (maybe_trigger = trigger.next) {
+ while (maybe_trigger) |node| : (maybe_trigger = node.next) {
+ const trigger: *TriggerNode = .get(node);
if (trigger.data.mods.super) count += 1;
if (trigger.data.mods.ctrl) count += 1;
if (trigger.data.mods.shift) count += 1;
@@ -120,7 +132,8 @@ const ChordBinding = struct {
const rhs_count: usize = blk: {
var count: usize = 0;
var maybe_trigger = rhs.triggers.first;
- while (maybe_trigger) |trigger| : (maybe_trigger = trigger.next) {
+ while (maybe_trigger) |node| : (maybe_trigger = node.next) {
+ const trigger: *TriggerNode = .get(node);
if (trigger.data.mods.super) count += 1;
if (trigger.data.mods.ctrl) count += 1;
if (trigger.data.mods.shift) count += 1;
@@ -137,8 +150,8 @@ const ChordBinding = struct {
var l_trigger = lhs.triggers.first;
var r_trigger = rhs.triggers.first;
while (l_trigger != null and r_trigger != null) {
- const l_int = l_trigger.?.data.mods.int();
- const r_int = r_trigger.?.data.mods.int();
+ const l_int = TriggerNode.get(l_trigger.?).data.mods.int();
+ const r_int = TriggerNode.get(r_trigger.?).data.mods.int();
if (l_int != r_int) {
return l_int > r_int;
@@ -154,13 +167,13 @@ const ChordBinding = struct {
while (l_trigger != null and r_trigger != null) {
const lhs_key: c_int = blk: {
- switch (l_trigger.?.data.key) {
+ switch (TriggerNode.get(l_trigger.?).data.key) {
.physical => |key| break :blk @intFromEnum(key),
.unicode => |key| break :blk @intCast(key),
}
};
const rhs_key: c_int = blk: {
- switch (r_trigger.?.data.key) {
+ switch (TriggerNode.get(r_trigger.?).data.key) {
.physical => |key| break :blk @intFromEnum(key),
.unicode => |key| break :blk @intCast(key),
}
@@ -186,19 +199,18 @@ const ChordBinding = struct {
fn prettyPrint(alloc: Allocator, keybinds: Config.Keybinds) !u8 {
// Set up vaxis
- var tty = try vaxis.Tty.init();
+ var buf: [1024]u8 = undefined;
+ var tty = try vaxis.Tty.init(&buf);
defer tty.deinit();
var vx = try vaxis.init(alloc, .{});
- defer vx.deinit(alloc, tty.anyWriter());
+ const writer = tty.writer();
+ defer vx.deinit(alloc, writer);
// We know we are ghostty, so let's enable mode 2027. Vaxis normally does this but you need an
// event loop to auto-enable it.
vx.caps.unicode = .unicode;
- try tty.anyWriter().writeAll(vaxis.ctlseqs.unicode_set);
- defer tty.anyWriter().writeAll(vaxis.ctlseqs.unicode_reset) catch {};
-
- var buf_writer = tty.bufferedWriter();
- const writer = buf_writer.writer().any();
+ try writer.writeAll(vaxis.ctlseqs.unicode_set);
+ defer writer.writeAll(vaxis.ctlseqs.unicode_reset) catch {};
const winsize: vaxis.Winsize = switch (builtin.os.tag) {
// We use some default, it doesn't really matter for what
@@ -212,7 +224,7 @@ fn prettyPrint(alloc: Allocator, keybinds: Config.Keybinds) !u8 {
else => try vaxis.Tty.getWinsize(tty.fd),
};
- try vx.resize(alloc, tty.anyWriter(), winsize);
+ try vx.resize(alloc, writer, winsize);
const win = vx.window();
@@ -234,7 +246,9 @@ fn prettyPrint(alloc: Allocator, keybinds: Config.Keybinds) !u8 {
var result: vaxis.Window.PrintResult = .{ .col = 0, .row = 0, .overflow = false };
var maybe_trigger = bind.triggers.first;
- while (maybe_trigger) |trigger| : (maybe_trigger = trigger.next) {
+ while (maybe_trigger) |node| : (maybe_trigger = node.next) {
+ const trigger: *TriggerNode = .get(node);
+
if (trigger.data.mods.super) {
result = win.printSegment(.{ .text = "super", .style = super_style }, .{ .col_offset = result.col });
result = win.printSegment(.{ .text = " + " }, .{ .col_offset = result.col });
@@ -252,18 +266,18 @@ fn prettyPrint(alloc: Allocator, keybinds: Config.Keybinds) !u8 {
result = win.printSegment(.{ .text = " + " }, .{ .col_offset = result.col });
}
const key = switch (trigger.data.key) {
- .physical => |k| try std.fmt.allocPrint(alloc, "{s}", .{@tagName(k)}),
+ .physical => |k| try std.fmt.allocPrint(alloc, "{t}", .{k}),
.unicode => |c| try std.fmt.allocPrint(alloc, "{u}", .{c}),
};
result = win.printSegment(.{ .text = key }, .{ .col_offset = result.col });
// Print a separator between chorded keys
- if (trigger.next != null) {
+ if (trigger.node.next != null) {
result = win.printSegment(.{ .text = " > ", .style = .{ .bold = true, .fg = .{ .index = 6 } } }, .{ .col_offset = result.col });
}
}
- const action = try std.fmt.allocPrint(alloc, "{}", .{bind.action});
+ const action = try std.fmt.allocPrint(alloc, "{f}", .{bind.action});
// If our action has an argument, we print the argument in a different color
if (std.mem.indexOfScalar(u8, action, ':')) |idx| {
_ = win.print(&.{
@@ -276,29 +290,33 @@ fn prettyPrint(alloc: Allocator, keybinds: Config.Keybinds) !u8 {
}
try vx.prettyPrint(writer);
}
- try buf_writer.flush();
+ try writer.flush();
return 0;
}
-fn iterateBindings(alloc: Allocator, iter: anytype, win: *const vaxis.Window) !struct { []ChordBinding, u16 } {
+fn iterateBindings(
+ alloc: Allocator,
+ iter: anytype,
+ win: *const vaxis.Window,
+) !struct { []ChordBinding, u16 } {
var widest_chord: u16 = 0;
- var bindings = std.ArrayList(ChordBinding).init(alloc);
+ var bindings: std.ArrayList(ChordBinding) = .empty;
while (iter.next()) |bind| {
const width = blk: {
- var buf = std.ArrayList(u8).init(alloc);
+ var buf: std.Io.Writer.Allocating = .init(alloc);
const t = bind.key_ptr.*;
- if (t.mods.super) try std.fmt.format(buf.writer(), "super + ", .{});
- if (t.mods.ctrl) try std.fmt.format(buf.writer(), "ctrl + ", .{});
- if (t.mods.alt) try std.fmt.format(buf.writer(), "alt + ", .{});
- if (t.mods.shift) try std.fmt.format(buf.writer(), "shift + ", .{});
+ if (t.mods.super) try buf.writer.print("super + ", .{});
+ if (t.mods.ctrl) try buf.writer.print("ctrl + ", .{});
+ if (t.mods.alt) try buf.writer.print("alt + ", .{});
+ if (t.mods.shift) try buf.writer.print("shift + ", .{});
switch (t.key) {
- .physical => |k| try std.fmt.format(buf.writer(), "{s}", .{@tagName(k)}),
- .unicode => |c| try std.fmt.format(buf.writer(), "{u}", .{c}),
+ .physical => |k| try buf.writer.print("{t}", .{k}),
+ .unicode => |c| try buf.writer.print("{u}", .{c}),
}
- break :blk win.gwidth(buf.items);
+ break :blk win.gwidth(buf.written());
};
switch (bind.value_ptr.*) {
@@ -310,28 +328,28 @@ fn iterateBindings(alloc: Allocator, iter: anytype, win: *const vaxis.Window) !s
// Prepend the current keybind onto the list of sub-binds
for (sub_bindings) |*nb| {
- const prepend_node = try alloc.create(TriggerList.Node);
- prepend_node.* = TriggerList.Node{ .data = bind.key_ptr.* };
- nb.triggers.prepend(prepend_node);
+ const prepend_node = try alloc.create(TriggerNode);
+ prepend_node.* = .{ .data = bind.key_ptr.* };
+ nb.triggers.prepend(&prepend_node.node);
}
// Add the longest sub-bind width to the current bind width along with a padding
// of 5 for the ' > ' spacer
widest_chord = @max(widest_chord, width + max_width + 5);
- try bindings.appendSlice(sub_bindings);
+ try bindings.appendSlice(alloc, sub_bindings);
},
.leaf => |leaf| {
- const node = try alloc.create(TriggerList.Node);
- node.* = TriggerList.Node{ .data = bind.key_ptr.* };
- const triggers = TriggerList{
- .first = node,
- };
+ const node = try alloc.create(TriggerNode);
+ node.* = .{ .data = bind.key_ptr.* };
widest_chord = @max(widest_chord, width);
- try bindings.append(.{ .triggers = triggers, .action = leaf.action });
+ try bindings.append(alloc, .{
+ .triggers = .{ .first = &node.node },
+ .action = leaf.action,
+ });
},
}
}
- return .{ try bindings.toOwnedSlice(), widest_chord };
+ return .{ try bindings.toOwnedSlice(alloc), widest_chord };
}