aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/cli/explain_config.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-04 19:22:04 +0300
committerCan Celik <ogulcancelik@gmail.com>2026-04-05 01:23:06 +0300
commit41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch)
tree3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/cli/explain_config.zig
parent55c138263e190a1e79d4b997bfb9397306c0ec1f (diff)
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/cli/explain_config.zig')
-rw-r--r--vendor/libghostty-vt/src/cli/explain_config.zig151
1 files changed, 151 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/cli/explain_config.zig b/vendor/libghostty-vt/src/cli/explain_config.zig
new file mode 100644
index 00000000..4f034afe
--- /dev/null
+++ b/vendor/libghostty-vt/src/cli/explain_config.zig
@@ -0,0 +1,151 @@
+const std = @import("std");
+const args = @import("args.zig");
+const Allocator = std.mem.Allocator;
+const Action = @import("ghostty.zig").Action;
+const help_strings = @import("help_strings");
+const Config = @import("../config/Config.zig");
+const ConfigKey = @import("../config/key.zig").Key;
+const KeybindAction = @import("../input/Binding.zig").Action;
+const Pager = @import("Pager.zig");
+
+pub const Options = struct {
+ /// The config option to explain. For example:
+ ///
+ /// ghostty +explain-config --option=font-size
+ option: ?[]const u8 = null,
+
+ /// The keybind action to explain. For example:
+ ///
+ /// ghostty +explain-config --keybind=copy_to_clipboard
+ keybind: ?[]const u8 = null,
+
+ pub fn deinit(self: Options) void {
+ _ = self;
+ }
+
+ /// Enables `-h` and `--help` to work.
+ pub fn help(self: Options) !void {
+ _ = self;
+ return Action.help_error;
+ }
+};
+
+/// The `explain-config` command prints the documentation for a single
+/// Ghostty configuration option or keybind action.
+///
+/// Examples:
+///
+/// ghostty +explain-config font-size
+/// ghostty +explain-config copy_to_clipboard
+/// ghostty +explain-config --option=font-size
+/// ghostty +explain-config --keybind=copy_to_clipboard
+///
+/// Flags:
+///
+/// * `--option`: The name of the configuration option to explain.
+/// * `--keybind`: The name of the keybind action to explain.
+/// * `--no-pager`: Disable automatic paging of output.
+pub fn run(alloc: Allocator) !u8 {
+ var option_name: ?[]const u8 = null;
+ var keybind_name: ?[]const u8 = null;
+ var positional: ?[]const u8 = null;
+ var no_pager: bool = false;
+
+ var iter = try args.argsIterator(alloc);
+ defer iter.deinit();
+ defer if (option_name) |s| alloc.free(s);
+ defer if (keybind_name) |s| alloc.free(s);
+ defer if (positional) |s| alloc.free(s);
+
+ while (iter.next()) |arg| {
+ if (std.mem.startsWith(u8, arg, "--option=")) {
+ option_name = try alloc.dupe(u8, arg["--option=".len..]);
+ } else if (std.mem.startsWith(u8, arg, "--keybind=")) {
+ keybind_name = try alloc.dupe(u8, arg["--keybind=".len..]);
+ } else if (std.mem.eql(u8, arg, "--no-pager")) {
+ no_pager = true;
+ } else if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
+ return Action.help_error;
+ } else if (!std.mem.startsWith(u8, arg, "-")) {
+ positional = try alloc.dupe(u8, arg);
+ }
+ }
+
+ // Resolve what to look up. Explicit flags go directly to their
+ // respective lookup. A bare positional argument tries config
+ // options first, then keybind actions as a fallback.
+ const name = keybind_name orelse option_name orelse positional orelse {
+ var stderr: std.fs.File = .stderr();
+ var buffer: [4096]u8 = undefined;
+ var stderr_writer = stderr.writer(&buffer);
+ try stderr_writer.interface.writeAll("Usage: ghostty +explain-config <option>\n");
+ try stderr_writer.interface.writeAll(" ghostty +explain-config --option=<option>\n");
+ try stderr_writer.interface.writeAll(" ghostty +explain-config --keybind=<action>\n");
+ try stderr_writer.end();
+ return 1;
+ };
+
+ const text = if (keybind_name != null)
+ explainKeybind(name)
+ else if (option_name != null)
+ explainOption(name)
+ else
+ explainOption(name) orelse explainKeybind(name);
+
+ var pager: Pager = if (!no_pager) .init(alloc) else .{};
+ defer pager.deinit();
+ var buffer: [4096]u8 = undefined;
+ const writer = pager.writer(&buffer);
+
+ if (text) |t| {
+ try writer.writeAll(t);
+ try writer.writeAll("\n");
+ } else {
+ try writer.writeAll("Unknown: '");
+ try writer.writeAll(name);
+ try writer.writeAll("'.\n");
+ try writer.flush();
+ return 1;
+ }
+
+ try writer.flush();
+ return 0;
+}
+
+fn explainOption(name: []const u8) ?[]const u8 {
+ const key = std.meta.stringToEnum(ConfigKey, name) orelse return null;
+ return switch (key) {
+ inline else => |tag| {
+ const field_name = @tagName(tag);
+ return if (@hasDecl(help_strings.Config, field_name))
+ @field(help_strings.Config, field_name)
+ else
+ null;
+ },
+ };
+}
+
+fn explainKeybind(name: []const u8) ?[]const u8 {
+ const tag = std.meta.stringToEnum(std.meta.Tag(KeybindAction), name) orelse return null;
+ return switch (tag) {
+ inline else => |t| {
+ const field_name = @tagName(t);
+ return if (@hasDecl(help_strings.KeybindAction, field_name))
+ @field(help_strings.KeybindAction, field_name)
+ else
+ null;
+ },
+ };
+}
+
+test "explain" {
+ // Config options
+ try std.testing.expect(explainOption("font-size") != null);
+ try std.testing.expect(explainOption("copy_to_clipboard") == null);
+ try std.testing.expect(explainOption("unknown-option") == null);
+
+ // Keybind actions
+ try std.testing.expect(explainKeybind("copy_to_clipboard") != null);
+ try std.testing.expect(explainKeybind("font-size") == null);
+ try std.testing.expect(explainKeybind("unknown_keybind") == null);
+}