diff --git a/src/build/webgen/main_actions.zig b/src/build/webgen/main_actions.zig index e802aac4af..65420d7e24 100644 --- a/src/build/webgen/main_actions.zig +++ b/src/build/webgen/main_actions.zig @@ -1,65 +1,8 @@ const std = @import("std"); const help_strings = @import("help_strings"); -const KeybindAction = @import("../../input/Binding.zig").Action; +const helpgen_actions = @import("../../helpgen_actions.zig"); pub fn main() !void { const output = std.io.getStdOut().writer(); - try genKeybindActions(output); -} - -pub fn genKeybindActions(writer: anytype) !void { - // Write the header - try writer.writeAll( - \\--- - \\title: Keybinding Action Reference - \\description: Reference of all Ghostty keybinding actions. - \\editOnGithubLink: https://github.com/ghostty-org/ghostty/edit/main/src/input/Binding.zig - \\--- - \\ - \\This is a reference of all Ghostty keybinding actions. - \\ - \\ - ); - - @setEvalBranchQuota(5_000); - - var buffer = std.ArrayList(u8).init(std.heap.page_allocator); - defer buffer.deinit(); - - const fields = @typeInfo(KeybindAction).Union.fields; - inline for (fields) |field| { - if (field.name[0] == '_') continue; - - // Write previously stored doc comment below all related actions - if (@hasDecl(help_strings.KeybindAction, field.name)) { - try writer.writeAll(buffer.items); - try writer.writeAll("\n"); - - buffer.clearRetainingCapacity(); - } - - // Write the field name. - try writer.writeAll("## `"); - try writer.writeAll(field.name); - try writer.writeAll("`\n"); - - if (@hasDecl(help_strings.KeybindAction, field.name)) { - var iter = std.mem.splitScalar( - u8, - @field(help_strings.KeybindAction, field.name), - '\n', - ); - while (iter.next()) |s| { - // If it is the last line and empty, then skip it. - if (iter.peek() == null and s.len == 0) continue; - try buffer.appendSlice(s); - try buffer.appendSlice("\n"); - } - } - } - - // Write any remaining buffered documentation - if (buffer.items.len > 0) { - try writer.writeAll(buffer.items); - } + try helpgen_actions.generate(output, .markdown, std.heap.page_allocator); } diff --git a/src/cli/list_actions.zig b/src/cli/list_actions.zig index e4b22023d2..e6c34adb2b 100644 --- a/src/cli/list_actions.zig +++ b/src/cli/list_actions.zig @@ -2,8 +2,7 @@ const std = @import("std"); const args = @import("args.zig"); const Action = @import("action.zig").Action; const Allocator = std.mem.Allocator; -const help_strings = @import("help_strings"); -const KeybindAction = @import("../input/Binding.zig").Action; +const helpgen_actions = @import("../helpgen_actions.zig"); pub const Options = struct { /// If `true`, print out documentation about the action associated with the @@ -37,46 +36,7 @@ pub fn run(alloc: Allocator) !u8 { } const stdout = std.io.getStdOut().writer(); - - var buffer = std.ArrayList(u8).init(std.heap.page_allocator); - defer buffer.deinit(); - - const fields = @typeInfo(KeybindAction).Union.fields; - inline for (fields) |field| { - if (field.name[0] == '_') continue; - - // Write previously stored doc comment below all related actions - if (@hasDecl(help_strings.KeybindAction, field.name)) { - try stdout.writeAll(buffer.items); - try stdout.writeAll("\n"); - - buffer.clearRetainingCapacity(); - } - - // Write the field name. - try stdout.writeAll(field.name); - try stdout.writeAll(":\n"); - - if (@hasDecl(help_strings.KeybindAction, field.name)) { - var iter = std.mem.splitScalar( - u8, - @field(help_strings.KeybindAction, field.name), - '\n', - ); - while (iter.next()) |s| { - // If it is the last line and empty, then skip it. - if (iter.peek() == null and s.len == 0) continue; - try buffer.appendSlice(" "); - try buffer.appendSlice(s); - try buffer.appendSlice("\n"); - } - } - } - - // Write any remaining buffered documentation - if (buffer.items.len > 0) { - try stdout.writeAll(buffer.items); - } + try helpgen_actions.generate(stdout, .plaintext, std.heap.page_allocator); return 0; } diff --git a/src/input/helpgen_actions.zig b/src/input/helpgen_actions.zig new file mode 100644 index 0000000000..9a7612b579 --- /dev/null +++ b/src/input/helpgen_actions.zig @@ -0,0 +1,107 @@ +//! This module is a help generator for keybind actions documentation. +//! It can generate documentation in different formats (plaintext for CLI, +//! markdown for website) while maintaining consistent content. + +const std = @import("std"); +const KeybindAction = @import("Binding.zig").Action; +const help_strings = @import("help_strings"); + +/// Format options for generating keybind actions documentation +pub const Format = enum { + /// Plain text output with indentation + plaintext, + /// Markdown formatted output + markdown, + + fn formatFieldName(self: Format, writer: anytype, field_name: []const u8) !void { + switch (self) { + .plaintext => { + try writer.writeAll(field_name); + try writer.writeAll(":\n"); + }, + .markdown => { + try writer.writeAll("## `"); + try writer.writeAll(field_name); + try writer.writeAll("`\n"); + }, + } + } + + fn formatDocLine(self: Format, writer: anytype, line: []const u8) !void { + switch (self) { + .plaintext => { + try writer.appendSlice(" "); + try writer.appendSlice(line); + try writer.appendSlice("\n"); + }, + .markdown => { + try writer.appendSlice(line); + try writer.appendSlice("\n"); + }, + } + } + + fn header(self: Format) ?[]const u8 { + return switch (self) { + .plaintext => null, + .markdown => + \\--- + \\title: Keybinding Action Reference + \\description: Reference of all Ghostty keybinding actions. + \\editOnGithubLink: https://github.com/ghostty-org/ghostty/edit/main/src/input/Binding.zig + \\--- + \\ + \\This is a reference of all Ghostty keybinding actions. + \\ + \\ + , + }; + } +}; + +/// Generate keybind actions documentation with the specified format +pub fn generate( + writer: anytype, + format: Format, + page_allocator: std.mem.Allocator, +) !void { + if (format.header()) |header| { + try writer.writeAll(header); + } + + var buffer = std.ArrayList(u8).init(page_allocator); + defer buffer.deinit(); + + const fields = @typeInfo(KeybindAction).Union.fields; + inline for (fields) |field| { + if (field.name[0] == '_') continue; + + // Write previously stored doc comment below all related actions + if (@hasDecl(help_strings.KeybindAction, field.name)) { + try writer.writeAll(buffer.items); + try writer.writeAll("\n"); + + buffer.clearRetainingCapacity(); + } + + try format.formatFieldName(writer, field.name); + + if (@hasDecl(help_strings.KeybindAction, field.name)) { + var iter = std.mem.splitScalar( + u8, + @field(help_strings.KeybindAction, field.name), + '\n', + ); + while (iter.next()) |s| { + // If it is the last line and empty, then skip it. + if (iter.peek() == null and s.len == 0) continue; + try format.formatDocLine(&buffer, s); + } + } + } + + // Write any remaining buffered documentation + if (buffer.items.len > 0) { + try writer.writeAll(buffer.items); + } +}