summaryrefslogtreecommitdiff
path: root/src/input/helpgen_actions.zig
blob: 1382bbe9541e99dc6a604b4f083a196ccb5acf65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! 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,
    show_docs: bool,
    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 (show_docs and @hasDecl(help_strings.KeybindAction, field.name)) {
            try writer.writeAll(buffer.items);
            try writer.writeAll("\n");

            buffer.clearRetainingCapacity();
        }

        if (show_docs) {
            try format.formatFieldName(writer, field.name);
        } else {
            try writer.writeAll(field.name);
            try writer.writeAll("\n");
        }

        if (show_docs and @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);
    }
}