Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed documentation generation in list-actions --docs command #4974

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 2 additions & 52 deletions src/build/webgen/main_actions.zig
Original file line number Diff line number Diff line change
@@ -1,58 +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| {
try buffer.appendSlice(s);
try buffer.appendSlice("\n");
}
}
}
try helpgen_actions.generate(output, .markdown, std.heap.page_allocator);
}
16 changes: 2 additions & 14 deletions src/cli/list_actions.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +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 helpgen_actions = @import("../helpgen_actions.zig");

pub const Options = struct {
/// If `true`, print out documentation about the action associated with the
Expand Down Expand Up @@ -36,19 +36,7 @@ pub fn run(alloc: Allocator) !u8 {
}

const stdout = std.io.getStdOut().writer();
const info = @typeInfo(help_strings.KeybindAction);
inline for (info.Struct.decls) |field| {
try stdout.print("{s}", .{field.name});
if (opts.docs) {
try stdout.print(":\n", .{});
var iter = std.mem.splitScalar(u8, std.mem.trimRight(u8, @field(help_strings.KeybindAction, field.name), &std.ascii.whitespace), '\n');
while (iter.next()) |line| {
try stdout.print(" {s}\n", .{line});
}
} else {
try stdout.print("\n", .{});
}
}
try helpgen_actions.generate(stdout, .plaintext, std.heap.page_allocator);

return 0;
}
6 changes: 3 additions & 3 deletions src/input/Binding.zig
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,9 @@ pub const Action = union(enum) {
/// Send an `ESC` sequence.
esc: []const u8,

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

/// Send data to the pty depending on whether cursor key mode is enabled
Expand Down
107 changes: 107 additions & 0 deletions src/input/helpgen_actions.zig
Original file line number Diff line number Diff line change
@@ -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);
}
}