diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-04-04 19:22:04 +0300 |
|---|---|---|
| committer | Can Celik <ogulcancelik@gmail.com> | 2026-04-05 01:23:06 +0300 |
| commit | 41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch) | |
| tree | 3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/cli/explain_config.zig | |
| parent | 55c138263e190a1e79d4b997bfb9397306c0ec1f (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.zig | 151 |
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); +} |
