summaryrefslogtreecommitdiff
path: root/src/cli
diff options
context:
space:
mode:
authorJason Rayne <yo@arcayne.dev>2025-06-25 12:47:38 -0700
committerJason Rayne <yo@arcayne.dev>2025-06-25 15:46:18 -0700
commit0565ed39546a982b7f47d0dd0ba341bc41cc092f (patch)
treeb2cc6fa4f0609c4befe649b30afcbb864aff15a6 /src/cli
parent6789b7fb6e459b8ca143b946fd0f4f7e6d8fda34 (diff)
refactor: replace ghostty wrapper with proper CLI actions for terminfo cache management
- Add +list-ssh-cache and +clear-ssh-cache CLI actions - Remove ghostty() wrapper functions from all shell integrations - Improve variable naming in shell scripts for readability Addresses @00-kat's feedback about CLI discoverability and naming consistency. The new CLI actions follow established Ghostty patterns and are discoverable via `ghostty --help`, while maintaining clean separation of concerns between shell logic and cache management.
Diffstat (limited to 'src/cli')
-rw-r--r--src/cli/action.zig12
-rw-r--r--src/cli/clear_ssh_cache.zig40
-rw-r--r--src/cli/list_ssh_cache.zig38
-rw-r--r--src/cli/ssh_cache.zig71
4 files changed, 161 insertions, 0 deletions
diff --git a/src/cli/action.zig b/src/cli/action.zig
index 009afb4c9..1d1c3bfa0 100644
--- a/src/cli/action.zig
+++ b/src/cli/action.zig
@@ -9,6 +9,8 @@ const list_keybinds = @import("list_keybinds.zig");
const list_themes = @import("list_themes.zig");
const list_colors = @import("list_colors.zig");
const list_actions = @import("list_actions.zig");
+const list_ssh_cache = @import("list_ssh_cache.zig");
+const clear_ssh_cache = @import("clear_ssh_cache.zig");
const edit_config = @import("edit_config.zig");
const show_config = @import("show_config.zig");
const validate_config = @import("validate_config.zig");
@@ -41,6 +43,12 @@ pub const Action = enum {
/// List keybind actions
@"list-actions",
+ /// List hosts with Ghostty SSH terminfo installed
+ @"list-ssh-cache",
+
+ /// Clear Ghostty SSH terminfo cache
+ @"clear-ssh-cache",
+
/// Edit the config file in the configured terminal editor.
@"edit-config",
@@ -155,6 +163,8 @@ pub const Action = enum {
.@"list-themes" => try list_themes.run(alloc),
.@"list-colors" => try list_colors.run(alloc),
.@"list-actions" => try list_actions.run(alloc),
+ .@"list-ssh-cache" => @import("list_ssh_cache.zig").run(alloc),
+ .@"clear-ssh-cache" => @import("clear_ssh_cache.zig").run(alloc),
.@"edit-config" => try edit_config.run(alloc),
.@"show-config" => try show_config.run(alloc),
.@"validate-config" => try validate_config.run(alloc),
@@ -192,6 +202,8 @@ pub const Action = enum {
.@"list-themes" => list_themes.Options,
.@"list-colors" => list_colors.Options,
.@"list-actions" => list_actions.Options,
+ .@"list-ssh-cache" => list_ssh_cache.Options,
+ .@"clear-ssh-cache" => clear_ssh_cache.Options,
.@"edit-config" => edit_config.Options,
.@"show-config" => show_config.Options,
.@"validate-config" => validate_config.Options,
diff --git a/src/cli/clear_ssh_cache.zig b/src/cli/clear_ssh_cache.zig
new file mode 100644
index 000000000..062af4221
--- /dev/null
+++ b/src/cli/clear_ssh_cache.zig
@@ -0,0 +1,40 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const args = @import("args.zig");
+const Action = @import("action.zig").Action;
+const ssh_cache = @import("ssh_cache.zig");
+
+pub const Options = struct {
+ pub fn deinit(self: Options) void {
+ _ = self;
+ }
+
+ /// Enables `-h` and `--help` to work.
+ pub fn help(self: Options) !void {
+ _ = self;
+ return Action.help_error;
+ }
+};
+
+/// Clear the Ghostty SSH terminfo cache.
+///
+/// This command removes the cache of hosts where Ghostty's terminfo has been installed
+/// via the ssh-terminfo shell integration feature. After clearing, terminfo will be
+/// reinstalled on the next SSH connection to previously cached hosts.
+///
+/// Use this if you need to force reinstallation of terminfo or clean up old entries.
+pub fn run(alloc: Allocator) !u8 {
+ var opts: Options = .{};
+ defer opts.deinit();
+
+ {
+ var iter = try args.argsIterator(alloc);
+ defer iter.deinit();
+ try args.parse(Options, alloc, &opts, &iter);
+ }
+
+ const stdout = std.io.getStdOut().writer();
+ try ssh_cache.clearCache(alloc, stdout);
+
+ return 0;
+}
diff --git a/src/cli/list_ssh_cache.zig b/src/cli/list_ssh_cache.zig
new file mode 100644
index 000000000..a799d95bd
--- /dev/null
+++ b/src/cli/list_ssh_cache.zig
@@ -0,0 +1,38 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const args = @import("args.zig");
+const Action = @import("action.zig").Action;
+const ssh_cache = @import("ssh_cache.zig");
+
+pub const Options = struct {
+ pub fn deinit(self: Options) void {
+ _ = self;
+ }
+
+ /// Enables `-h` and `--help` to work.
+ pub fn help(self: Options) !void {
+ _ = self;
+ return Action.help_error;
+ }
+};
+
+/// List hosts with Ghostty SSH terminfo installed via the ssh-terminfo shell integration feature.
+///
+/// This command shows all remote hosts where Ghostty's terminfo has been successfully
+/// installed through the SSH integration. The cache is automatically maintained when
+/// connecting to remote hosts with `shell-integration-features = ssh-terminfo` enabled.
+pub fn run(alloc: Allocator) !u8 {
+ var opts: Options = .{};
+ defer opts.deinit();
+
+ {
+ var iter = try args.argsIterator(alloc);
+ defer iter.deinit();
+ try args.parse(Options, alloc, &opts, &iter);
+ }
+
+ const stdout = std.io.getStdOut().writer();
+ try ssh_cache.listCachedHosts(alloc, stdout);
+
+ return 0;
+}
diff --git a/src/cli/ssh_cache.zig b/src/cli/ssh_cache.zig
new file mode 100644
index 000000000..c3484735a
--- /dev/null
+++ b/src/cli/ssh_cache.zig
@@ -0,0 +1,71 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const Child = std.process.Child;
+
+/// Get the path to the shared cache script
+fn getCacheScriptPath(alloc: Allocator) ![]u8 {
+ // Use GHOSTTY_RESOURCES_DIR if available, otherwise assume relative path
+ const resources_dir = std.process.getEnvVarOwned(alloc, "GHOSTTY_RESOURCES_DIR") catch {
+ // Fallback: assume we're running from build directory
+ return try alloc.dupe(u8, "src/shell-integration/shared/ghostty-ssh-cache");
+ };
+ defer alloc.free(resources_dir);
+
+ return try std.fs.path.join(alloc, &[_][]const u8{ resources_dir, "shell-integration", "shared", "ghostty-ssh-cache" });
+}
+
+/// List cached hosts by calling the external script
+pub fn listCachedHosts(alloc: Allocator, writer: anytype) !void {
+ const script_path = try getCacheScriptPath(alloc);
+ defer alloc.free(script_path);
+
+ var child = Child.init(&[_][]const u8{ script_path, "list" }, alloc);
+ child.stdout_behavior = .Pipe;
+ child.stderr_behavior = .Pipe;
+
+ try child.spawn();
+
+ const stdout = try child.stdout.?.readToEndAlloc(alloc, std.math.maxInt(usize));
+ defer alloc.free(stdout);
+
+ const stderr = try child.stderr.?.readToEndAlloc(alloc, std.math.maxInt(usize));
+ defer alloc.free(stderr);
+
+ _ = try child.wait();
+
+ // Output the results regardless of exit code
+ try writer.writeAll(stdout);
+ if (stderr.len > 0) {
+ try writer.writeAll(stderr);
+ }
+
+ // Script handles its own success/error messaging, so we don't need to check exit code
+}
+
+/// Clear cache by calling the external script
+pub fn clearCache(alloc: Allocator, writer: anytype) !void {
+ const script_path = try getCacheScriptPath(alloc);
+ defer alloc.free(script_path);
+
+ var child = Child.init(&[_][]const u8{ script_path, "clear" }, alloc);
+ child.stdout_behavior = .Pipe;
+ child.stderr_behavior = .Pipe;
+
+ try child.spawn();
+
+ const stdout = try child.stdout.?.readToEndAlloc(alloc, std.math.maxInt(usize));
+ defer alloc.free(stdout);
+
+ const stderr = try child.stderr.?.readToEndAlloc(alloc, std.math.maxInt(usize));
+ defer alloc.free(stderr);
+
+ _ = try child.wait();
+
+ // Output the results regardless of exit code
+ try writer.writeAll(stdout);
+ if (stderr.len > 0) {
+ try writer.writeAll(stderr);
+ }
+
+ // Script handles its own success/error messaging, so we don't need to check exit code
+}