Skip to content

Commit f222159

Browse files
committed
Reapply "Fixed documentation generation in list-actions --docs command (ghostty-org#4974)"
This reverts commit f8b547f.
1 parent 66f0eb0 commit f222159

File tree

4 files changed

+114
-69
lines changed

4 files changed

+114
-69
lines changed

src/build/webgen/main_actions.zig

+2-52
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,8 @@
11
const std = @import("std");
22
const help_strings = @import("help_strings");
3-
const KeybindAction = @import("../../input/Binding.zig").Action;
3+
const helpgen_actions = @import("../../input/helpgen_actions.zig");
44

55
pub fn main() !void {
66
const output = std.io.getStdOut().writer();
7-
try genKeybindActions(output);
8-
}
9-
10-
pub fn genKeybindActions(writer: anytype) !void {
11-
// Write the header
12-
try writer.writeAll(
13-
\\---
14-
\\title: Keybinding Action Reference
15-
\\description: Reference of all Ghostty keybinding actions.
16-
\\editOnGithubLink: https://github.com/ghostty-org/ghostty/edit/main/src/input/Binding.zig
17-
\\---
18-
\\
19-
\\This is a reference of all Ghostty keybinding actions.
20-
\\
21-
\\
22-
);
23-
24-
@setEvalBranchQuota(5_000);
25-
26-
var buffer = std.ArrayList(u8).init(std.heap.page_allocator);
27-
defer buffer.deinit();
28-
29-
const fields = @typeInfo(KeybindAction).Union.fields;
30-
inline for (fields) |field| {
31-
if (field.name[0] == '_') continue;
32-
33-
// Write previously stored doc comment below all related actions
34-
if (@hasDecl(help_strings.KeybindAction, field.name)) {
35-
try writer.writeAll(buffer.items);
36-
try writer.writeAll("\n");
37-
38-
buffer.clearRetainingCapacity();
39-
}
40-
41-
// Write the field name.
42-
try writer.writeAll("## `");
43-
try writer.writeAll(field.name);
44-
try writer.writeAll("`\n");
45-
46-
if (@hasDecl(help_strings.KeybindAction, field.name)) {
47-
var iter = std.mem.splitScalar(
48-
u8,
49-
@field(help_strings.KeybindAction, field.name),
50-
'\n',
51-
);
52-
while (iter.next()) |s| {
53-
try buffer.appendSlice(s);
54-
try buffer.appendSlice("\n");
55-
}
56-
}
57-
}
7+
try helpgen_actions.generate(output, .markdown, std.heap.page_allocator);
588
}

src/cli/list_actions.zig

+2-14
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const std = @import("std");
22
const args = @import("args.zig");
33
const Action = @import("action.zig").Action;
44
const Allocator = std.mem.Allocator;
5-
const help_strings = @import("help_strings");
5+
const helpgen_actions = @import("../input/helpgen_actions.zig");
66

77
pub const Options = struct {
88
/// If `true`, print out documentation about the action associated with the
@@ -38,19 +38,7 @@ pub fn run(alloc: Allocator) !u8 {
3838
}
3939

4040
const stdout = std.io.getStdOut().writer();
41-
const info = @typeInfo(help_strings.KeybindAction);
42-
inline for (info.Struct.decls) |field| {
43-
try stdout.print("{s}", .{field.name});
44-
if (opts.docs) {
45-
try stdout.print(":\n", .{});
46-
var iter = std.mem.splitScalar(u8, std.mem.trimRight(u8, @field(help_strings.KeybindAction, field.name), &std.ascii.whitespace), '\n');
47-
while (iter.next()) |line| {
48-
try stdout.print(" {s}\n", .{line});
49-
}
50-
} else {
51-
try stdout.print("\n", .{});
52-
}
53-
}
41+
try helpgen_actions.generate(stdout, .plaintext, std.heap.page_allocator);
5442

5543
return 0;
5644
}

src/input/Binding.zig

+3-3
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,9 @@ pub const Action = union(enum) {
236236
/// Send an `ESC` sequence.
237237
esc: []const u8,
238238

239-
// Send the given text. Uses Zig string literal syntax. This is currently
240-
// not validated. If the text is invalid (i.e. contains an invalid escape
241-
// sequence), the error will currently only show up in logs.
239+
/// Send the given text. Uses Zig string literal syntax. This is currently
240+
/// not validated. If the text is invalid (i.e. contains an invalid escape
241+
/// sequence), the error will currently only show up in logs.
242242
text: []const u8,
243243

244244
/// Send data to the pty depending on whether cursor key mode is enabled

src/input/helpgen_actions.zig

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//! This module is a help generator for keybind actions documentation.
2+
//! It can generate documentation in different formats (plaintext for CLI,
3+
//! markdown for website) while maintaining consistent content.
4+
5+
const std = @import("std");
6+
const KeybindAction = @import("Binding.zig").Action;
7+
const help_strings = @import("help_strings");
8+
9+
/// Format options for generating keybind actions documentation
10+
pub const Format = enum {
11+
/// Plain text output with indentation
12+
plaintext,
13+
/// Markdown formatted output
14+
markdown,
15+
16+
fn formatFieldName(self: Format, writer: anytype, field_name: []const u8) !void {
17+
switch (self) {
18+
.plaintext => {
19+
try writer.writeAll(field_name);
20+
try writer.writeAll(":\n");
21+
},
22+
.markdown => {
23+
try writer.writeAll("## `");
24+
try writer.writeAll(field_name);
25+
try writer.writeAll("`\n");
26+
},
27+
}
28+
}
29+
30+
fn formatDocLine(self: Format, writer: anytype, line: []const u8) !void {
31+
switch (self) {
32+
.plaintext => {
33+
try writer.appendSlice(" ");
34+
try writer.appendSlice(line);
35+
try writer.appendSlice("\n");
36+
},
37+
.markdown => {
38+
try writer.appendSlice(line);
39+
try writer.appendSlice("\n");
40+
},
41+
}
42+
}
43+
44+
fn header(self: Format) ?[]const u8 {
45+
return switch (self) {
46+
.plaintext => null,
47+
.markdown =>
48+
\\---
49+
\\title: Keybinding Action Reference
50+
\\description: Reference of all Ghostty keybinding actions.
51+
\\editOnGithubLink: https://github.com/ghostty-org/ghostty/edit/main/src/input/Binding.zig
52+
\\---
53+
\\
54+
\\This is a reference of all Ghostty keybinding actions.
55+
\\
56+
\\
57+
,
58+
};
59+
}
60+
};
61+
62+
/// Generate keybind actions documentation with the specified format
63+
pub fn generate(
64+
writer: anytype,
65+
format: Format,
66+
page_allocator: std.mem.Allocator,
67+
) !void {
68+
if (format.header()) |header| {
69+
try writer.writeAll(header);
70+
}
71+
72+
var buffer = std.ArrayList(u8).init(page_allocator);
73+
defer buffer.deinit();
74+
75+
const fields = @typeInfo(KeybindAction).Union.fields;
76+
inline for (fields) |field| {
77+
if (field.name[0] == '_') continue;
78+
79+
// Write previously stored doc comment below all related actions
80+
if (@hasDecl(help_strings.KeybindAction, field.name)) {
81+
try writer.writeAll(buffer.items);
82+
try writer.writeAll("\n");
83+
84+
buffer.clearRetainingCapacity();
85+
}
86+
87+
try format.formatFieldName(writer, field.name);
88+
89+
if (@hasDecl(help_strings.KeybindAction, field.name)) {
90+
var iter = std.mem.splitScalar(
91+
u8,
92+
@field(help_strings.KeybindAction, field.name),
93+
'\n',
94+
);
95+
while (iter.next()) |s| {
96+
// If it is the last line and empty, then skip it.
97+
if (iter.peek() == null and s.len == 0) continue;
98+
try format.formatDocLine(&buffer, s);
99+
}
100+
}
101+
}
102+
103+
// Write any remaining buffered documentation
104+
if (buffer.items.len > 0) {
105+
try writer.writeAll(buffer.items);
106+
}
107+
}

0 commit comments

Comments
 (0)