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 { | |
| 98 | 98 | } else if (std.mem.eql(u8, cmd, "help") or std.mem.eql(u8, cmd, "h") or std.mem.eql(u8, cmd, "-h")) { | |
| 99 | 99 | return help(); | |
| 100 | 100 | } 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 | + | } | |
| 102 | 108 | return list(&cfg, short); | |
| 103 | 109 | } else if (std.mem.eql(u8, cmd, "completions") or std.mem.eql(u8, cmd, "c")) { | |
| 104 | 110 | 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 | + | } | |
| 105 | 114 | const shell = completions.Shell.fromString(arg) orelse return; | |
| 106 | 115 | return printCompletions(shell); | |
| 107 | 116 | } else if (std.mem.eql(u8, cmd, "detach") or std.mem.eql(u8, cmd, "d")) { |
| ... | ... | @@ -110,7 +119,9 @@ pub fn main() !void { | |
| 110 | 119 | var session_name: ?[]const u8 = null; | |
| 111 | 120 | var format: util.HistoryFormat = .plain; | |
| 112 | 121 | 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")) { | |
| 114 | 125 | format = .vt; | |
| 115 | 126 | } else if (std.mem.eql(u8, arg, "--html")) { | |
| 116 | 127 | format = .html; |
| ... | ... | @@ -124,6 +135,9 @@ pub fn main() !void { | |
| 124 | 135 | return history(&cfg, sesh, format); | |
| 125 | 136 | } else if (std.mem.eql(u8, cmd, "attach") or std.mem.eql(u8, cmd, "a")) { | |
| 126 | 137 | 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 | + | } | |
| 127 | 141 | ||
| 128 | 142 | var command_args: std.ArrayList([]const u8) = .empty; | |
| 129 | 143 | defer command_args.deinit(alloc); |
| ... | ... | @@ -163,6 +177,9 @@ pub fn main() !void { | |
| 163 | 177 | return attach(&daemon); | |
| 164 | 178 | } else if (std.mem.eql(u8, cmd, "run") or std.mem.eql(u8, cmd, "r")) { | |
| 165 | 179 | 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 | + | } | |
| 166 | 183 | ||
| 167 | 184 | var cmd_args_raw: std.ArrayList([]const u8) = .empty; | |
| 168 | 185 | defer cmd_args_raw.deinit(alloc); |
| ... | ... | @@ -203,6 +220,9 @@ pub fn main() !void { | |
| 203 | 220 | return run(&daemon, detached, cmd_args_raw.items); | |
| 204 | 221 | } else if (std.mem.eql(u8, cmd, "send") or std.mem.eql(u8, cmd, "s")) { | |
| 205 | 222 | 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 | + | } | |
| 206 | 226 | if (session_name.len == 0) return error.SessionNameRequired; | |
| 207 | 227 | ||
| 208 | 228 | var text_parts: std.ArrayList([]const u8) = .empty; |
| ... | ... | @@ -220,6 +240,9 @@ pub fn main() !void { | |
| 220 | 240 | return send(&cfg, sesh, socket_path, text_parts.items, .Input); | |
| 221 | 241 | } else if (std.mem.eql(u8, cmd, "print") or std.mem.eql(u8, cmd, "p")) { | |
| 222 | 242 | 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 | + | } | |
| 223 | 246 | if (session_name.len == 0) return error.SessionNameRequired; | |
| 224 | 247 | ||
| 225 | 248 | var text_parts: std.ArrayList([]const u8) = .empty; |
| ... | ... | @@ -249,6 +272,9 @@ pub fn main() !void { | |
| 249 | 272 | } | |
| 250 | 273 | var force = false; | |
| 251 | 274 | 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 | + | } | |
| 252 | 278 | if (std.mem.eql(u8, session_name, "--force")) { | |
| 253 | 279 | force = true; | |
| 254 | 280 | continue; |
| ... | ... | @@ -292,6 +318,9 @@ pub fn main() !void { | |
| 292 | 318 | matchers.deinit(alloc); | |
| 293 | 319 | } | |
| 294 | 320 | 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 | + | } | |
| 295 | 324 | const m = try parseSessionArg(alloc, session_name); | |
| 296 | 325 | try matchers.append(alloc, m); | |
| 297 | 326 | } |
| ... | ... | @@ -308,6 +337,9 @@ pub fn main() !void { | |
| 308 | 337 | matchers.deinit(alloc); | |
| 309 | 338 | } | |
| 310 | 339 | 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 | + | } | |
| 311 | 343 | const m = try parseSessionArg(alloc, session_name); | |
| 312 | 344 | try matchers.append(alloc, m); | |
| 313 | 345 | } |
| ... | ... | @@ -375,8 +407,14 @@ pub fn main() !void { | |
| 375 | 407 | _ = try tail(client_socket_fds, false, false); | |
| 376 | 408 | } else if (std.mem.eql(u8, cmd, "write") or std.mem.eql(u8, cmd, "wr")) { | |
| 377 | 409 | 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 | + | } | |
| 378 | 413 | if (session_name.len == 0) return error.SessionNameRequired; | |
| 379 | 414 | 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 | + | } | |
| 380 | 418 | if (file_path.len == 0) return error.FilePathRequired; | |
| 381 | 419 | ||
| 382 | 420 | var cwd_buf: [std.fs.max_path_bytes]u8 = undefined; |
+27,
-0
| ... | ... | @@ -50,6 +50,33 @@ load test_helper | |
| 50 | 50 | [ "$status" -ne 0 ] | |
| 51 | 51 | } | |
| 52 | 52 | ||
| 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 | + | ||
| 53 | 80 | # ============================================================================ | |
| 54 | 81 | # Send (raw PTY input) | |
| 55 | 82 | # ============================================================================ |