Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions src/cli.toit
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,16 @@ class Command:
/** The rest arguments. */
rest_/List

/**
Whether '--' is treated as a regular rest argument.

When false (the default), '--' stops option parsing and all subsequent
arguments become rest arguments.
When true, '--' is treated as a normal rest argument and option parsing
continues for subsequent arguments.
*/
dash-dash-is-rest_/bool

/** Whether this command should show up in the help. */
is-hidden_/bool

Expand Down Expand Up @@ -227,51 +237,52 @@ class Command:
*/
constructor name --usage/string?=null --help/string?=null --examples/List=[] \
--aliases/List=[] --options/List=[] --rest/List=[] --subcommands/List=[] --hidden/bool=false \
--run/Lambda?=null:
--dash-dash-is-rest/bool=false --run/Lambda?=null:
return Command.private name --usage=usage --help=help --examples=examples \
--aliases=aliases --options=options --rest=rest --subcommands=subcommands --hidden=hidden \
--run=run
--dash-dash-is-rest=dash-dash-is-rest --run=run

/**
Deprecated. Use '--help' instead of '--short-help'.
*/
constructor name --usage/string?=null --short-help/string --examples/List=[] \
--aliases/List=[] --options/List=[] --rest/List=[] --subcommands/List=[] --hidden/bool=false \
--run/Lambda?=null:
--dash-dash-is-rest/bool=false --run/Lambda?=null:
return Command.private name --usage=usage --short-help=short-help --examples=examples \
--aliases=aliases --options=options --rest=rest --subcommands=subcommands --hidden=hidden \
--run=run
--dash-dash-is-rest=dash-dash-is-rest --run=run

/**
Deprecated. Use '--help' instead of '--long-help'.
*/
constructor name --usage/string?=null --long-help/string --examples/List=[] \
--aliases/List=[] --options/List=[] --rest/List=[] --subcommands/List=[] --hidden/bool=false \
--run/Lambda?=null:
--dash-dash-is-rest/bool=false --run/Lambda?=null:
return Command.private name --usage=usage --help=long-help --examples=examples \
--aliases=aliases --options=options --rest=rest --subcommands=subcommands --hidden=hidden \
--run=run
--dash-dash-is-rest=dash-dash-is-rest --run=run

/**
Deprecated. Use '--help' with a meaningful first paragraph instead of '--short-help' and '--long-help'.
*/
constructor name --usage/string?=null --short-help/string --long-help/string --examples/List=[] \
--aliases/List=[] --options/List=[] --rest/List=[] --subcommands/List=[] --hidden/bool=false \
--run/Lambda?=null:
--dash-dash-is-rest/bool=false --run/Lambda?=null:
return Command.private name --usage=usage --short-help=short-help --help=long-help --examples=examples \
--aliases=aliases --options=options --rest=rest --subcommands=subcommands --hidden=hidden \
--run=run
--dash-dash-is-rest=dash-dash-is-rest --run=run

constructor.private .name --usage/string?=null --short-help/string?=null --help/string?=null --examples/List=[] \
--aliases/List=[] --options/List=[] --rest/List=[] --subcommands/List=[] --hidden/bool=false \
--run/Lambda?=null:
--dash-dash-is-rest/bool=false --run/Lambda?=null:
usage_ = usage
short-help_ = short-help
help_ = help
examples_ = examples
aliases_ = aliases
options_ = options
rest_ = rest
dash-dash-is-rest_ = dash-dash-is-rest
subcommands_ = subcommands
run-callback_ = run
is-hidden_ = hidden
Expand Down
9 changes: 8 additions & 1 deletion src/completion_.toit
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,14 @@ complete_ root/Command arguments/List -> CompletionResult_:
all-named-options.clear
all-short-options.clear
add-options-for-command_ current-command all-named-options all-short-options
past-dashdash = true
if not current-command.dash-dash-is-rest_:
past-dashdash = true
continue.repeat
// Treat "--" as a regular rest argument.
rest-option := rest-option-for-index_ current-command positional-index
if rest-option:
(seen-options.get rest-option.name --init=:[]).add arg
positional-index++
continue.repeat

if arg.starts-with "--":
Expand Down
2 changes: 1 addition & 1 deletion src/help-generator_.toit
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ class HelpGenerator:
write-usage-suffix_ command/Command --has-more-options/bool -> none:
if not command.subcommands_.is-empty: write_ " <command>"
if has-more-options: write_ " [<options>]"
if not command.rest_.is-empty: write_ " [--]"
if not command.rest_.is-empty and not command.dash-dash-is-rest_: write_ " [--]"
command.rest_.do: | option/Option |
type := option.type
option-str/string := ?
Expand Down
9 changes: 6 additions & 3 deletions src/parser_.toit
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,13 @@ class Parser_:
remaining := ["--"] + arguments[index..]
parse group.default_ remaining block
return
rest.add-all arguments[index ..]
break // We're done!
if not command.dash-dash-is-rest_:
rest.add-all arguments[index ..]
break // We're done!
// Treat "--" as a regular rest argument.
rest.add argument

if argument.starts-with "--":
else if argument.starts-with "--":
value/string? := null
// Get the option name.
split := argument.index-of "="
Expand Down
47 changes: 37 additions & 10 deletions tests/dashdash_test.toit
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,43 @@ import cli
import expect show *

main:
test-dashdash-separator
test-no-allow-dashdash
test-no-allow-dashdash-with-options

test-dashdash-separator:
root := cli.Command "root"
--rest=[
cli.Option "first" --required,
cli.Option "arg" --multi
]
--run=:: test-dashdash it
--rest=[
cli.Option "first" --required,
cli.Option "arg" --multi,
]
--run=:: | invocation/cli.Invocation |
expect-equals "prog" invocation["first"]
expect-list-equals ["arg1", "arg2", "arg3"] invocation["arg"]
root.run ["--", "prog", "arg1", "arg2", "arg3"]

test-dashdash invocation/cli.Invocation:
first := invocation["first"]
rest := invocation["arg"]
expect-equals "prog" first
expect-list-equals ["arg1", "arg2", "arg3"] rest
test-no-allow-dashdash:
// When --allow-dash-dash is false, "--" becomes a regular rest argument.
root := cli.Command "root"
--dash-dash-is-rest
--rest=[
cli.Option "arg" --multi,
]
--run=:: | invocation/cli.Invocation |
expect-list-equals ["--", "foo", "bar"] invocation["arg"]
root.run ["--", "foo", "bar"]

test-no-allow-dashdash-with-options:
// Options after "--" are still parsed when allow-dash-dash is false.
root := cli.Command "root"
--dash-dash-is-rest
--options=[
cli.Flag "verbose" --short-name="v",
]
--rest=[
cli.Option "arg" --multi,
]
--run=:: | invocation/cli.Invocation |
expect invocation["verbose"]
expect-list-equals ["--", "foo"] invocation["arg"]
root.run ["--", "foo", "--verbose"]