Commit 0ba19cd

Amir B.  ·  2026-05-16 20:32:03 -0400 EDT
parent a28c87a
fix: handle run help flag (#152)

Extends the --help/-h check to all subcommands that accept a session
name or other positional args, so users don't accidentally create a
session named "--help" or trigger confusing errors.

Covers: list, completions, history, attach, send, print, write,
kill, wait, tail.
2 files changed,  +67, -2
+40, -2
......@@ -98,10 +98,19 @@ pub fn main() !void {
9898 } else if (std.mem.eql(u8, cmd, "help") or std.mem.eql(u8, cmd, "h") or std.mem.eql(u8, cmd, "-h")) {
9999 return help();
100100 } else if (std.mem.eql(u8, cmd, "list") or std.mem.eql(u8, cmd, "l") or std.mem.eql(u8, cmd, "ls")) {
101- const short = if (args.next()) |arg| std.mem.eql(u8, arg, "--short") else false;
101+ var short = false;
102+ if (args.next()) |arg| {
103+ if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
104+ return help();
105+ }
106+ short = std.mem.eql(u8, arg, "--short");
107+ }
102108 return list(&cfg, short);
103109 } else if (std.mem.eql(u8, cmd, "completions") or std.mem.eql(u8, cmd, "c")) {
104110 const arg = args.next() orelse return;
111+ if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
112+ return help();
113+ }
105114 const shell = completions.Shell.fromString(arg) orelse return;
106115 return printCompletions(shell);
107116 } else if (std.mem.eql(u8, cmd, "detach") or std.mem.eql(u8, cmd, "d")) {
......@@ -110,7 +119,9 @@ pub fn main() !void {
110119 var session_name: ?[]const u8 = null;
111120 var format: util.HistoryFormat = .plain;
112121 while (args.next()) |arg| {
113- if (std.mem.eql(u8, arg, "--vt")) {
122+ if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
123+ return help();
124+ } else if (std.mem.eql(u8, arg, "--vt")) {
114125 format = .vt;
115126 } else if (std.mem.eql(u8, arg, "--html")) {
116127 format = .html;
......@@ -124,6 +135,9 @@ pub fn main() !void {
124135 return history(&cfg, sesh, format);
125136 } else if (std.mem.eql(u8, cmd, "attach") or std.mem.eql(u8, cmd, "a")) {
126137 const session_name = args.next() orelse "";
138+ if (std.mem.eql(u8, session_name, "--help") or std.mem.eql(u8, session_name, "-h")) {
139+ return help();
140+ }
127141
128142 var command_args: std.ArrayList([]const u8) = .empty;
129143 defer command_args.deinit(alloc);
......@@ -163,6 +177,9 @@ pub fn main() !void {
163177 return attach(&daemon);
164178 } else if (std.mem.eql(u8, cmd, "run") or std.mem.eql(u8, cmd, "r")) {
165179 const session_name = args.next() orelse "";
180+ if (std.mem.eql(u8, session_name, "--help") or std.mem.eql(u8, session_name, "-h")) {
181+ return help();
182+ }
166183
167184 var cmd_args_raw: std.ArrayList([]const u8) = .empty;
168185 defer cmd_args_raw.deinit(alloc);
......@@ -203,6 +220,9 @@ pub fn main() !void {
203220 return run(&daemon, detached, cmd_args_raw.items);
204221 } else if (std.mem.eql(u8, cmd, "send") or std.mem.eql(u8, cmd, "s")) {
205222 const session_name = args.next() orelse "";
223+ if (std.mem.eql(u8, session_name, "--help") or std.mem.eql(u8, session_name, "-h")) {
224+ return help();
225+ }
206226 if (session_name.len == 0) return error.SessionNameRequired;
207227
208228 var text_parts: std.ArrayList([]const u8) = .empty;
......@@ -220,6 +240,9 @@ pub fn main() !void {
220240 return send(&cfg, sesh, socket_path, text_parts.items, .Input);
221241 } else if (std.mem.eql(u8, cmd, "print") or std.mem.eql(u8, cmd, "p")) {
222242 const session_name = args.next() orelse "";
243+ if (std.mem.eql(u8, session_name, "--help") or std.mem.eql(u8, session_name, "-h")) {
244+ return help();
245+ }
223246 if (session_name.len == 0) return error.SessionNameRequired;
224247
225248 var text_parts: std.ArrayList([]const u8) = .empty;
......@@ -249,6 +272,9 @@ pub fn main() !void {
249272 }
250273 var force = false;
251274 while (args.next()) |session_name| {
275+ if (std.mem.eql(u8, session_name, "--help") or std.mem.eql(u8, session_name, "-h")) {
276+ return help();
277+ }
252278 if (std.mem.eql(u8, session_name, "--force")) {
253279 force = true;
254280 continue;
......@@ -292,6 +318,9 @@ pub fn main() !void {
292318 matchers.deinit(alloc);
293319 }
294320 while (args.next()) |session_name| {
321+ if (std.mem.eql(u8, session_name, "--help") or std.mem.eql(u8, session_name, "-h")) {
322+ return help();
323+ }
295324 const m = try parseSessionArg(alloc, session_name);
296325 try matchers.append(alloc, m);
297326 }
......@@ -308,6 +337,9 @@ pub fn main() !void {
308337 matchers.deinit(alloc);
309338 }
310339 while (args.next()) |session_name| {
340+ if (std.mem.eql(u8, session_name, "--help") or std.mem.eql(u8, session_name, "-h")) {
341+ return help();
342+ }
311343 const m = try parseSessionArg(alloc, session_name);
312344 try matchers.append(alloc, m);
313345 }
......@@ -375,8 +407,14 @@ pub fn main() !void {
375407 _ = try tail(client_socket_fds, false, false);
376408 } else if (std.mem.eql(u8, cmd, "write") or std.mem.eql(u8, cmd, "wr")) {
377409 const session_name = args.next() orelse "";
410+ if (std.mem.eql(u8, session_name, "--help") or std.mem.eql(u8, session_name, "-h")) {
411+ return help();
412+ }
378413 if (session_name.len == 0) return error.SessionNameRequired;
379414 const file_path = args.next() orelse "";
415+ if (std.mem.eql(u8, file_path, "--help") or std.mem.eql(u8, file_path, "-h")) {
416+ return help();
417+ }
380418 if (file_path.len == 0) return error.FilePathRequired;
381419
382420 var cwd_buf: [std.fs.max_path_bytes]u8 = undefined;
+27, -0
......@@ -50,6 +50,33 @@ load test_helper
5050 [ "$status" -ne 0 ]
5151 }
5252
53+@test "run --help shows help without creating a session" {
54+ run "$ZMX" run --help
55+ [ "$status" -eq 0 ]
56+ [[ "$output" == *"Usage:"* ]]
57+
58+ run "$ZMX" list --short
59+ [ "$status" -eq 0 ]
60+ [[ "$output" != *"--help"* ]]
61+}
62+
63+@test "subcommands handle --help and -h without side effects" {
64+ for cmd in attach send print write kill wait tail history list completions; do
65+ run "$ZMX" "$cmd" --help
66+ [ "$status" -eq 0 ]
67+ [[ "$output" == *"Usage:"* ]]
68+
69+ run "$ZMX" "$cmd" -h
70+ [ "$status" -eq 0 ]
71+ [[ "$output" == *"Usage:"* ]]
72+ done
73+
74+ run "$ZMX" list --short
75+ [ "$status" -eq 0 ]
76+ [[ "$output" != *"--help"* ]]
77+ [[ "$output" != *"-h"* ]]
78+}
79+
5380 # ============================================================================
5481 # Send (raw PTY input)
5582 # ============================================================================