Skip to content

Interior hyphen in a short option cluster silently ends option parsing #216

Description

@borkdude

An interior hyphen in a short option cluster silently stops option parsing for the rest of the command line.

(cli/parse-args ["-ab"  "--foo" "1"])
;=> {:opts {:a true, :b true, :foo 1}}

(cli/parse-args ["-a-b" "--foo" "1"])
;=> {:opts {:a true}, :args [true "-b" true "--foo" "1"]}

--foo 1 is never parsed. There is no error, and parse-opts drops :args, so the caller sees only {:a true}.

(cli/parse-opts ["-J-D"])
;=> {:J true}

The composite expansion emits each character as its own flag:

(mapcat (fn [c] [(str "-" c) true]) (name :a-b))
;=> ("-a" true "-" true "-b" true)

The "-" pairs into a "--" token, which takes the end-of-options path, so everything after it becomes positional. The guard in analyze-arg only rejects a hyphen in the second character, which keeps --foo from being composite but allows -a-b.

Requiring the cluster to be hyphen-free would send -a-b and -J-D down the normal unknown-option path, an error under :restrict:

composite-opt? (when hyphen-opt?
                 (and snd-char (not= \- snd-char)
                      (> (count arg) 2)
                      (not (str/includes? (subs arg 1) "-"))))

Found while adding -J passthrough to a bb task, where bb dev -J-Xmx4g --with-transactor dropped --with-transactor. :restrict true does report Unknown option: -J, so specs that restrict are not affected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions