Skip to content

Don't treat unknown short option packs as help requests - #1000

Open
ravindudanthanarayana wants to merge 1 commit into
apple:mainfrom
ravindudanthanarayana:fix-help-in-unknown-short-pack
Open

ravindudanthanarayana wants to merge 1 commit into
apple:mainfrom
ravindudanthanarayana:fix-help-in-unknown-short-pack

Conversation

@ravindudanthanarayana

@ravindudanthanarayana ravindudanthanarayana commented Nov 1, 2026 •

Copy link
Copy Markdown

Single-dash input that isn't a valid option can print the help screen and exit 0 instead of failing, if it happens to contain an h. Related to #325, where a quoted argument starting with - and containing a URL printed help.

Original behavior

Using the math example:

$ math add -path; echo "exit=$?"
OVERVIEW: Print the sum of the values.
...
exit=0

The input isn't reported, and a script sees success. The same happens for -hey, -xzh, "- [a](https://b)", and at any level of the command tree (math -path, math stats average -path). -path doesn't request help; -pat correctly fails with Unknown option.

Minimal reproduction

struct Example: ParsableCommand {
  @Argument var input: String
}
$ example -path input   # prints help, exits 0
$ example -pat input    # Error: Unknown option '-pat', exits 64

Root cause

parseIndividualArg splits any single-dash input into a complete element plus one element per character, since it could be a pack of short names. checkForBuiltInFlags then uses SplitArguments.contains(anyOf:), which looks at every element without distinguishing pack members, so the h in -path matches the -h help name.

Implementation

contains(anyOf:isRecognized:) still matches complete elements as before. A match that comes from a pack now only counts if one of these is true:

  • The input spells a long name from the list with a single dash. This keeps -help working, which the comment in checkForBuiltInFlags already calls out.
  • Every other remaining member of the pack is either a name from the list or is recognized by the current command.

The second check needs the current command's ArgumentSet because checkForBuiltInFlags also runs after a decoding failure, when flags haven't been removed from the input yet. Without it, -vh on a command missing a required argument would report the missing argument instead of showing help. The set is only built when a pack contains a help name, so ordinary parsing doesn't pay for it.

Behavior changes to review

Input Before After
-path, -hey help, exit 0 Unknown option '-path', exit 64
-vzh (-v valid, -z not) help, exit 0 Unknown option '-z', exit 64
-h, --help, -help, -vh, -hv, -hh help help (unchanged)
-vh with -v on the default subcommand root help default subcommand's help
-help when helpNames is .short only help Unknown option '-help'
-help-hidden help Unknown option '-help-hidden' (--help-hidden unchanged)

Scripts that relied on a malformed pack exiting 0 would now fail, though that was never a documented way to request help. This is a behavior change only; no API changes, and contains(anyOf:) is internal.

Limitations

Tests

Added to ShortNameEndToEndTests.swift, covering unknown packs (including custom help names), default subcommands, help names alone, packs of known names through both the normal path and the decode and validation failure paths, and help-like text passed as a value.

Validation

macOS, Swift 6.4 (swiftlang-6.4.0.34.1). Linux and Windows were not run locally.

  • Without the fix: swift test --filter ShortNameEndToEndTests fails, 7 issues across the 2 new unknown-pack tests. The tests pinning existing help behavior pass.
  • With the fix: swift test passes, 580 Swift Testing tests across 7 test runs.
  • swift format lint --strict --recursive Sources Tests reports nothing.

This change was developed with AI assistance (Claude Code).

Checklist

  • I've added at least one test that validates that my change is working, if appropriate
  • I've followed the code style of the rest of the project
  • I've read the Contribution Guidelines
  • I've updated the documentation if necessary

Any single-dash input is split into a pack of short names, and the
built-in flag check matched `-h` against each member. As a result, an
input like `-path` printed help and exited successfully instead of
reporting an unknown option, so typos went unnoticed by scripts.

Only count a help name from a pack when the other members are help names
or are valid for the current command. `-vh` and `-help` still show help.
@ravindudanthanarayana
ravindudanthanarayana marked this pull request as ready for review November 1, 2026 11:15

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant