Skip to content

Commit

Permalink
#284 stopAtPositional flag to treat first positional parameter as e…
Browse files Browse the repository at this point in the history
…nd-of-options
  • Loading branch information
remkop committed Feb 11, 2018
1 parent e17afee commit e39438c
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 2 deletions.
36 changes: 36 additions & 0 deletions src/main/java/picocli/CommandLine.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ public class CommandLine {
private final Interpreter interpreter;
private final IFactory factory;

private boolean stopAtPositional = false;
private boolean overwrittenOptionsAllowed = false;
private boolean unmatchedArgumentsAllowed = false;
private boolean expandAtFiles = true;
Expand Down Expand Up @@ -334,6 +335,33 @@ public CommandLine setOverwrittenOptionsAllowed(boolean newValue) {
return this;
}

/** Returns whether the parser interprets the first positional parameter as "end of options" so the remaining
* arguments are all treated as positional parameters. The default is {@code false}.
* @return {@code true} if all values following the first positional parameter should be treated as positional parameters, {@code false} otherwise
* @since 2.3
*/
public boolean isStopAtPositional() {
return stopAtPositional;
}

/** Sets whether the parser interprets the first positional parameter as "end of options" so the remaining
* arguments are all treated as positional parameters. The default is {@code false}.
* <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.</p>
* @param newValue {@code true} if all values following the first positional parameter should be treated as positional parameters, {@code false} otherwise
* @return this {@code CommandLine} object, to allow method chaining
* @since 2.3
*/
public CommandLine setStopAtPositional(boolean newValue) {
this.stopAtPositional = newValue;
for (CommandLine command : interpreter.commands.values()) {
command.setStopAtPositional(newValue);
}
return this;
}

/** Returns whether the end user may specify arguments on the command line that are not matched to any option or parameter fields.
* The default is {@code false} and a {@link UnmatchedArgumentException} is thrown if this happens.
* When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method.
Expand Down Expand Up @@ -3498,6 +3526,10 @@ private void processArguments(List<CommandLine> parsedCommands,

String separator = commandSpec.separator();
while (!args.isEmpty()) {
if (endOfOptions) {
processRemainderAsPositionalParameters(required, initialized, args);
return;
}
String arg = args.pop();
if (tracer.isDebug()) {tracer.debug("Processing argument '%s'. Remainder=%s%n", arg, reverse(copy(args)));}

Expand Down Expand Up @@ -3592,6 +3624,10 @@ private void processRemainderAsPositionalParameters(Collection<ArgSpec<?>> requi
}
private void processPositionalParameter(Collection<ArgSpec<?>> required, Set<ArgSpec<?>> initialized, Stack<String> args) throws Exception {
if (tracer.isDebug()) {tracer.debug("Processing next arg as a positional parameter at index=%d. Remainder=%s%n", position, reverse(copy(args)));}
if (stopAtPositional) {
if (!endOfOptions && tracer.isDebug()) {tracer.debug("Parser was configured with stopAtPositional=true, treating remaining arguments as positional parameters.%n");}
endOfOptions = true;
}
int consumed = 0;
for (PositionalParamSpec positionalParam : commandSpec.positionalParameters()) {
Range indexRange = positionalParam.index();
Expand Down
32 changes: 30 additions & 2 deletions src/test/java/picocli/CommandLineArityTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -921,7 +921,7 @@ class Arg {
}

@Test
public void test284VarargPositionalShouldNotConsumeOptions() {
public void test285VarargPositionalShouldNotConsumeOptions() {
class Cmd {
@Option(names = "--alpha") String alpha;
@Parameters(index = "0", arity = "1") String foo;
Expand All @@ -934,7 +934,7 @@ class Cmd {
}

@Test
public void test284VarargPositionalShouldConsumeOptionsAfterDoubleDash() {
public void test285VarargPositionalShouldConsumeOptionsAfterDoubleDash() {
class Cmd {
@Option(names = "--alpha") String alpha;
@Parameters(index = "0", arity = "1") String foo;
Expand Down Expand Up @@ -963,4 +963,32 @@ class Cmd {
Cmd cmd = CommandLine.populateCommand(new Cmd(), "foo", "--", "--", "--");
assertEquals(Arrays.asList("foo", "--", "--"), cmd.params);
}

@Test
public void testIfStopAtPositional_VarargPositionalShouldConsumeOptions() {
class Cmd {
@Option(names = "--alpha") String alpha;
@Parameters(index = "0", arity = "1") String foo;
@Parameters(index = "1..*", arity = "*") List<String> params;
}
Cmd cmd = new Cmd();
new CommandLine(cmd).setStopAtPositional(true).parse("foo", "xx", "--alpha", "--beta");
assertEquals("foo", cmd.foo);
assertEquals(null, cmd.alpha);
assertEquals(Arrays.asList("xx", "--alpha", "--beta"), cmd.params);
}

@Test
public void testIfStopAtPositional_PositionalShouldConsumeOptions() {
class Cmd {
@Option(names = "--alpha") String alpha;
@Parameters(index = "0") String foo;
@Parameters(index = "1..*") List<String> params;
}
Cmd cmd = new Cmd();
new CommandLine(cmd).setStopAtPositional(true).parse("foo", "xx", "--alpha", "--beta");
assertEquals("foo", cmd.foo);
assertEquals(null, cmd.alpha);
assertEquals(Arrays.asList("xx", "--alpha", "--beta"), cmd.params);
}
}

0 comments on commit e39438c

Please sign in to comment.