Skip to content

Commit d64904e

Browse files
committed
cli(stop,new,copy,delete[help]): Show help when called with no arguments
why: These commands showed a terse argparse error on missing args instead of the full subcommand help page, unlike the search command. what: - Make positional args optional via nargs="?"/"*" in subparser setup - Stash subparser print_help via set_defaults for dispatch access - Add no-args guards in cli() dispatch using args.print_help() - Add parametrized test for all four commands
1 parent 36ba0d0 commit d64904e

File tree

6 files changed

+53
-1
lines changed

6 files changed

+53
-1
lines changed

src/tmuxp/cli/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,19 +420,28 @@ def cli(_args: list[str] | None = None) -> None:
420420
color=args.color,
421421
)
422422
elif args.subparser_name == "new":
423+
if not args.workspace_name:
424+
args.print_help()
425+
return
423426
command_new(
424427
workspace_name=args.workspace_name,
425428
parser=parser,
426429
color=args.color,
427430
)
428431
elif args.subparser_name == "copy":
432+
if not args.source or not args.destination:
433+
args.print_help()
434+
return
429435
command_copy(
430436
source=args.source,
431437
destination=args.destination,
432438
parser=parser,
433439
color=args.color,
434440
)
435441
elif args.subparser_name == "delete":
442+
if not args.workspace_names:
443+
args.print_help()
444+
return
436445
command_delete(
437446
workspace_names=args.workspace_names,
438447
answer_yes=args.answer_yes,
@@ -445,6 +454,9 @@ def cli(_args: list[str] | None = None) -> None:
445454
parser=parser,
446455
)
447456
elif args.subparser_name == "stop":
457+
if not args.session_name:
458+
args.print_help()
459+
return
448460
command_stop(
449461
args=CLIStopNamespace(**vars(args)),
450462
parser=parser,

src/tmuxp/cli/copy.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,30 @@ def create_copy_subparser(
5252
>>> args = parser.parse_args(["src", "dst"])
5353
>>> args.source, args.destination
5454
('src', 'dst')
55+
56+
No arguments yields ``None``:
57+
58+
>>> args = parser.parse_args([])
59+
>>> args.source is None and args.destination is None
60+
True
5561
"""
5662
parser.add_argument(
5763
dest="source",
5864
metavar="source",
65+
nargs="?",
66+
default=None,
5967
type=str,
6068
help="source workspace name or file path.",
6169
)
6270
parser.add_argument(
6371
dest="destination",
6472
metavar="destination",
73+
nargs="?",
74+
default=None,
6575
type=str,
6676
help="destination workspace name or file path.",
6777
)
78+
parser.set_defaults(print_help=parser.print_help)
6879
return parser
6980

7081

src/tmuxp/cli/delete.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,17 @@ def create_delete_subparser(
5353
['proj1', 'proj2']
5454
>>> args.answer_yes
5555
True
56+
57+
No arguments yields an empty list:
58+
59+
>>> args = parser.parse_args([])
60+
>>> args.workspace_names
61+
[]
5662
"""
5763
parser.add_argument(
5864
dest="workspace_names",
5965
metavar="workspace-name",
60-
nargs="+",
66+
nargs="*",
6167
type=str,
6268
help="workspace name(s) or file path(s) to delete.",
6369
)
@@ -68,6 +74,7 @@ def create_delete_subparser(
6874
action="store_true",
6975
help="skip confirmation prompt.",
7076
)
77+
parser.set_defaults(print_help=parser.print_help)
7178
return parser
7279

7380

src/tmuxp/cli/new.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,22 @@ def create_new_subparser(
5959
>>> args = parser.parse_args(["myproject"])
6060
>>> args.workspace_name
6161
'myproject'
62+
63+
No arguments yields ``None``:
64+
65+
>>> args = parser.parse_args([])
66+
>>> args.workspace_name is None
67+
True
6268
"""
6369
parser.add_argument(
6470
dest="workspace_name",
6571
metavar="workspace-name",
72+
nargs="?",
73+
default=None,
6674
type=str,
6775
help="name for the new workspace config.",
6876
)
77+
parser.set_defaults(print_help=parser.print_help)
6978
return parser
7079

7180

src/tmuxp/cli/stop.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def create_stop_subparser(
7575
metavar="socket-name",
7676
help="pass-through for tmux -L",
7777
)
78+
parser.set_defaults(print_help=parser.print_help)
7879
return parser
7980

8081

tests/cli/test_help_examples.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,18 @@ def test_search_no_args_shows_help() -> None:
300300
assert result.returncode == 0
301301

302302

303+
@pytest.mark.parametrize("subcommand", ["stop", "new", "copy", "delete"])
304+
def test_new_commands_no_args_shows_help(subcommand: str) -> None:
305+
"""Running new commands with no args shows help."""
306+
result = subprocess.run(
307+
["tmuxp", subcommand],
308+
capture_output=True,
309+
text=True,
310+
)
311+
assert f"usage: tmuxp {subcommand}" in result.stdout
312+
assert result.returncode == 0
313+
314+
303315
def test_main_help_example_sections_have_examples_suffix() -> None:
304316
"""Main --help should have section headings ending with 'examples:'."""
305317
help_text = _get_help_text()

0 commit comments

Comments
 (0)