diff options
| author | Mitchell Hashimoto <m@mitchellh.com> | 2025-10-01 13:10:40 -0700 |
|---|---|---|
| committer | Mitchell Hashimoto <m@mitchellh.com> | 2025-10-03 07:10:43 -0700 |
| commit | cb295b84a0ec274a43da59041fa4a199e799798d (patch) | |
| tree | ac7d5a77a12ecf021983e20d7602226668d8aadb /src/cli/list_keybinds.zig | |
| parent | 3770f97608409d450a1ab0364974ee7fb1c50f13 (diff) | |
Zig 0.15: zig build test
Diffstat (limited to 'src/cli/list_keybinds.zig')
| -rw-r--r-- | src/cli/list_keybinds.zig | 110 |
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 }; } |
