diff --git a/airline-core/src/main/java/com/github/rvesse/airline/annotations/PositionalArgument.java b/airline-core/src/main/java/com/github/rvesse/airline/annotations/PositionalArgument.java
index 2bbb56812..85853a192 100644
--- a/airline-core/src/main/java/com/github/rvesse/airline/annotations/PositionalArgument.java
+++ b/airline-core/src/main/java/com/github/rvesse/airline/annotations/PositionalArgument.java
@@ -18,7 +18,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
-import com.github.rvesse.airline.model.ArgumentMetadata;
+import com.github.rvesse.airline.model.PositionalArgumentMetadata;
import com.github.rvesse.airline.types.DefaultTypeConverterProvider;
import com.github.rvesse.airline.types.TypeConverterProvider;
@@ -65,7 +65,7 @@
* the argument definitions are compatible.
*
* See
- * {@link ArgumentMetadata#override(ArgumentMetadata, ArgumentMetadata)}
+ * {@link PositionalArgumentMetadata#override(PositionalArgumentMetadata, PositionalArgumentMetadata)}
* for legal overrides
*
*
diff --git a/airline-core/src/main/java/com/github/rvesse/airline/help/suggester/SuggestCommand.java b/airline-core/src/main/java/com/github/rvesse/airline/help/suggester/SuggestCommand.java
index 449ceacaa..22d857286 100644
--- a/airline-core/src/main/java/com/github/rvesse/airline/help/suggester/SuggestCommand.java
+++ b/airline-core/src/main/java/com/github/rvesse/airline/help/suggester/SuggestCommand.java
@@ -24,6 +24,7 @@
import com.github.rvesse.airline.model.GlobalMetadata;
import com.github.rvesse.airline.model.MetadataLoader;
import com.github.rvesse.airline.model.OptionMetadata;
+import com.github.rvesse.airline.model.PositionalArgumentMetadata;
import com.github.rvesse.airline.model.SuggesterMetadata;
import com.github.rvesse.airline.parser.ParseState;
import com.github.rvesse.airline.parser.suggester.SuggestionParser;
@@ -79,7 +80,8 @@ public Iterable generateSuggestions() {
}
Suggester suggester = createInstance(suggesterMetadata.getSuggesterClass(),
- Collections. emptyList(), null, null, null,
+ Collections. emptyList(), null,
+ Collections. emptyList(), null, null, null,
suggesterMetadata.getMetadataInjections(), AirlineUtils.unmodifiableMapCopy(bindings));
return suggester.suggest();
diff --git a/airline-core/src/main/java/com/github/rvesse/airline/model/CommandMetadata.java b/airline-core/src/main/java/com/github/rvesse/airline/model/CommandMetadata.java
index 943d763da..433dca973 100644
--- a/airline-core/src/main/java/com/github/rvesse/airline/model/CommandMetadata.java
+++ b/airline-core/src/main/java/com/github/rvesse/airline/model/CommandMetadata.java
@@ -34,7 +34,7 @@ public class CommandMetadata {
private final List groupOptions;
private final List commandOptions;
private final OptionMetadata defaultOption;
- private final List positionalArgs;
+ private final List positionalArgs;
private final ArgumentsMetadata arguments;
private final List metadataInjections;
private final Class> type;
@@ -50,7 +50,7 @@ public CommandMetadata(String name,
Iterable groupOptions,
Iterable commandOptions,
OptionMetadata defaultOption,
- List positionalArguments,
+ List positionalArguments,
ArgumentsMetadata arguments,
Iterable metadataInjections,
Class> type,
@@ -151,7 +151,7 @@ public OptionMetadata getDefaultOption() {
return defaultOption;
}
- public List getPositionalArguments() {
+ public List getPositionalArguments() {
return positionalArgs;
}
diff --git a/airline-core/src/main/java/com/github/rvesse/airline/model/MetadataLoader.java b/airline-core/src/main/java/com/github/rvesse/airline/model/MetadataLoader.java
index ee4c53f0d..8da72bb6b 100644
--- a/airline-core/src/main/java/com/github/rvesse/airline/model/MetadataLoader.java
+++ b/airline-core/src/main/java/com/github/rvesse/airline/model/MetadataLoader.java
@@ -52,7 +52,7 @@
import javax.inject.Inject;
-import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.ArrayUtils;
@@ -254,7 +254,7 @@ public static GlobalMetadata loadGlobal(Class> cliClass, ParserMetadata
}
// Maybe a top level group we've already seen
- CommandGroupMetadata group = CollectionUtils.find(groups, new GroupFinder(groupName));
+ CommandGroupMetadata group = IterableUtils.find(groups, new GroupFinder(groupName));
if (group == null) {
// Maybe a sub-group we've already seen
group = subGroups.get(subGroupPath);
@@ -750,7 +750,7 @@ public static void loadInjectionMetadata(Class> type, InjectionMetadata inject
List restrictions = collectArgumentRestrictions(field, false);
//@formatter:off
- injectionMetadata.positionalArgs.add(new ArgumentMetadata(positionalArgumentAnnotation.position(),
+ injectionMetadata.positionalArgs.add(new PositionalArgumentMetadata(positionalArgumentAnnotation.position(),
title,
positionalArgumentAnnotation.description(),
positionalArgumentAnnotation.sealed(),
@@ -940,12 +940,12 @@ private static void tryOverrideOptions(Map, OptionMetadata> optionIn
optionIndex.put(names, merged);
}
- private static List overridePositionalArgumentSet(List args) {
+ private static List overridePositionalArgumentSet(List args) {
args = ListUtils.unmodifiableList(args);
- Map argsIndex = new HashMap<>();
+ Map argsIndex = new HashMap<>();
int maxIndex = -1;
- for (ArgumentMetadata arg : args) {
+ for (PositionalArgumentMetadata arg : args) {
maxIndex = Math.max(maxIndex, arg.getZeroBasedPosition());
if (argsIndex.containsKey(arg.getZeroBasedPosition())) {
@@ -956,7 +956,7 @@ private static List overridePositionalArgumentSet(List posArgs = new ArrayList<>(maxIndex);
+ List posArgs = new ArrayList<>(maxIndex);
for (int i = 0; i < maxIndex; i++) {
posArgs.set(i, argsIndex.get(i));
if (posArgs.get(i) == null) {
@@ -969,13 +969,13 @@ private static List overridePositionalArgumentSet(List argsIndex,
- ArgumentMetadata parent) {
+ private static void tryOverridePositionalArgument(Map argsIndex,
+ PositionalArgumentMetadata parent) {
// As the metadata is extracted from the deepest class in the hierarchy
// going upwards we need to treat the passed option as the parent and
// the pre-existing option definition as the child
- ArgumentMetadata child = argsIndex.get(parent.getZeroBasedPosition());
+ PositionalArgumentMetadata child = argsIndex.get(parent.getZeroBasedPosition());
Accessor parentField = parent.getAccessors().iterator().next();
Accessor childField = child.getAccessors().iterator().next();
@@ -999,7 +999,7 @@ private static void tryOverridePositionalArgument(Map
parentField, childField, parent.getZeroBasedPosition(), parent.getTitle()));
// Attempt overriding, this will error if the overriding is not possible
- ArgumentMetadata merged = ArgumentMetadata.override(parent, child);
+ PositionalArgumentMetadata merged = PositionalArgumentMetadata.override(parent, child);
argsIndex.put(parent.getZeroBasedPosition(), merged);
}
@@ -1017,7 +1017,7 @@ public static void loadCommandsIntoGroupsByAnnotation(List allC
// now add the command to any groupNames specified in the Command
// annotation
for (String groupName : command.getGroupNames()) {
- CommandGroupMetadata group = CollectionUtils.find(commandGroups, new GroupFinder(groupName));
+ CommandGroupMetadata group = IterableUtils.find(commandGroups, new GroupFinder(groupName));
if (group != null) {
// Add to existing top level group
group.addCommand(command);
@@ -1030,7 +1030,7 @@ public static void loadCommandsIntoGroupsByAnnotation(List allC
for (int i = 0; i < groups.length; i++) {
if (i == 0) {
// Find/create the necessary top level group
- subGroup = CollectionUtils.find(commandGroups, new GroupFinder(groups[i]));
+ subGroup = IterableUtils.find(commandGroups, new GroupFinder(groups[i]));
if (subGroup == null) {
subGroup = new CommandGroupMetadata(groups[i], "", false,
Collections. emptyList(),
@@ -1040,7 +1040,7 @@ Collections. emptyList(), null,
}
} else {
// Find/create the next sub-group
- CommandGroupMetadata nextSubGroup = CollectionUtils.find(subGroup.getSubGroups(),
+ CommandGroupMetadata nextSubGroup = IterableUtils.find(subGroup.getSubGroups(),
new GroupFinder(groups[i]));
if (nextSubGroup == null) {
nextSubGroup = new CommandGroupMetadata(groups[i], "", false,
@@ -1096,7 +1096,7 @@ private static void createGroupsFromAnnotations(List allCommand
// load default command if needed
if (!groupAnno.defaultCommand().equals(Group.NO_DEFAULT.class)) {
defaultCommandClass = groupAnno.defaultCommand();
- defaultCommand = CollectionUtils.find(allCommands, new CommandTypeFinder(defaultCommandClass));
+ defaultCommand = IterableUtils.find(allCommands, new CommandTypeFinder(defaultCommandClass));
if (null == defaultCommand) {
defaultCommand = loadCommand(defaultCommandClass, baseHelpSections);
newCommands.add(defaultCommand);
@@ -1107,7 +1107,7 @@ private static void createGroupsFromAnnotations(List allCommand
List groupCommands = new ArrayList(groupAnno.commands().length);
CommandMetadata groupCommand = null;
for (Class commandClass : groupAnno.commands()) {
- groupCommand = CollectionUtils.find(allCommands, new CommandTypeFinder(commandClass));
+ groupCommand = IterableUtils.find(allCommands, new CommandTypeFinder(commandClass));
if (null == groupCommand) {
groupCommand = loadCommand(commandClass, baseHelpSections);
newCommands.add(groupCommand);
@@ -1117,7 +1117,7 @@ private static void createGroupsFromAnnotations(List allCommand
// Find the group metadata
// May already exist as a top level group
- CommandGroupMetadata groupMetadata = CollectionUtils.find(commandGroups,
+ CommandGroupMetadata groupMetadata = IterableUtils.find(commandGroups,
new GroupFinder(groupAnno.name()));
if (groupMetadata == null) {
// Not a top level group
@@ -1167,7 +1167,7 @@ protected static void buildGroupsHierarchy(List commandGro
for (int i = 0; i < groups.length - 1; i++) {
if (i == 0) {
// Should be a top level group
- parentGroup = CollectionUtils.find(commandGroups, new GroupFinder(groups[i]));
+ parentGroup = IterableUtils.find(commandGroups, new GroupFinder(groups[i]));
if (parentGroup == null) {
// Top level parent group does not exist so create empty
// top level group
@@ -1179,7 +1179,7 @@ Collections. emptyList(), null,
}
} else {
// Should be a sub-group of the current parent
- CommandGroupMetadata nextParent = CollectionUtils.find(parentGroup.getSubGroups(),
+ CommandGroupMetadata nextParent = IterableUtils.find(parentGroup.getSubGroups(),
new GroupFinder(groups[i]));
if (nextParent == null) {
// Next parent group does not exist so create empty
@@ -1206,7 +1206,7 @@ private static class InjectionMetadata {
private List groupOptions = new ArrayList<>();
private List commandOptions = new ArrayList<>();
private OptionMetadata defaultOption = null;
- private List positionalArgs = new ArrayList<>();
+ private List positionalArgs = new ArrayList<>();
private List arguments = new ArrayList<>();
private List metadataInjections = new ArrayList<>();
diff --git a/airline-core/src/main/java/com/github/rvesse/airline/model/ArgumentMetadata.java b/airline-core/src/main/java/com/github/rvesse/airline/model/PositionalArgumentMetadata.java
similarity index 93%
rename from airline-core/src/main/java/com/github/rvesse/airline/model/ArgumentMetadata.java
rename to airline-core/src/main/java/com/github/rvesse/airline/model/PositionalArgumentMetadata.java
index aa9b8ee50..bf2566bd7 100644
--- a/airline-core/src/main/java/com/github/rvesse/airline/model/ArgumentMetadata.java
+++ b/airline-core/src/main/java/com/github/rvesse/airline/model/PositionalArgumentMetadata.java
@@ -33,7 +33,7 @@
import org.apache.commons.collections4.SetUtils;
import org.apache.commons.lang3.StringUtils;
-public class ArgumentMetadata {
+public class PositionalArgumentMetadata {
private final int position;
private final String title, description;
private final boolean sealed, overrides;
@@ -42,7 +42,7 @@ public class ArgumentMetadata {
private final TypeConverterProvider provider;
/**
- * Creates new argument metadata
+ * Creates new positional argument metadata
*
* @param position
* Zero based position index
@@ -58,7 +58,7 @@ public class ArgumentMetadata {
* Field to modify
*/
//@formatter:off
- public ArgumentMetadata(int position, String title,
+ public PositionalArgumentMetadata(int position, String title,
String description,
boolean sealed, boolean overrides,
Iterable restrictions,
@@ -85,13 +85,13 @@ public ArgumentMetadata(int position, String title,
this.accessors = SetUtils.unmodifiableSet(Collections.singleton(new Accessor(path)));
}
- public ArgumentMetadata(Iterable arguments) {
+ public PositionalArgumentMetadata(Iterable arguments) {
if (arguments == null)
throw new NullPointerException("arguments cannot be null");
if (!arguments.iterator().hasNext())
throw new IllegalArgumentException("arguments cannot be empty");
- ArgumentMetadata first = arguments.iterator().next();
+ PositionalArgumentMetadata first = arguments.iterator().next();
this.sealed = first.sealed;
this.overrides = first.overrides;
@@ -102,7 +102,7 @@ public ArgumentMetadata(Iterable arguments) {
this.provider = first.provider;
Set accessors = new HashSet<>();
- for (ArgumentMetadata other : arguments) {
+ for (PositionalArgumentMetadata other : arguments) {
if (!first.equals(other))
throw new IllegalArgumentException(
String.format("Conflicting arguments definitions: %s, %s", first, other));
@@ -179,7 +179,7 @@ public boolean equals(Object o) {
return false;
}
- ArgumentMetadata that = (ArgumentMetadata) o;
+ PositionalArgumentMetadata that = (PositionalArgumentMetadata) o;
if (this.position != that.position)
return false;
@@ -232,7 +232,7 @@ public String toString() {
* Child
* @return Merged metadata
*/
- public static ArgumentMetadata override(ArgumentMetadata parent, ArgumentMetadata child) {
+ public static PositionalArgumentMetadata override(PositionalArgumentMetadata parent, PositionalArgumentMetadata child) {
// Cannot change position
if (parent.position != child.position)
throw new IllegalArgumentException(
@@ -277,9 +277,9 @@ public static ArgumentMetadata override(ArgumentMetadata parent, ArgumentMetadat
throw new IllegalArgumentException(
String.format("Cannot override positional argument %d (%s) unless child argument sets overrides to true", parent.position, parent.title));
- ArgumentMetadata merged;
+ PositionalArgumentMetadata merged;
//@formatter:off
- merged = new ArgumentMetadata(child.position,
+ merged = new PositionalArgumentMetadata(child.position,
child.title,
child.description,
child.sealed,
diff --git a/airline-core/src/main/java/com/github/rvesse/airline/parser/AbstractCommandParser.java b/airline-core/src/main/java/com/github/rvesse/airline/parser/AbstractCommandParser.java
index a301133f1..cd31bfa2d 100644
--- a/airline-core/src/main/java/com/github/rvesse/airline/parser/AbstractCommandParser.java
+++ b/airline-core/src/main/java/com/github/rvesse/airline/parser/AbstractCommandParser.java
@@ -16,6 +16,7 @@
package com.github.rvesse.airline.parser;
import com.github.rvesse.airline.Context;
+import com.github.rvesse.airline.model.PositionalArgumentMetadata;
import com.github.rvesse.airline.model.ArgumentsMetadata;
import com.github.rvesse.airline.model.CommandGroupMetadata;
import com.github.rvesse.airline.model.CommandMetadata;
@@ -32,7 +33,7 @@
import java.util.List;
-import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.iterators.PeekingIterator;
@@ -166,7 +167,7 @@ protected ParseState parseCommandOptionsAndArguments(PeekingIterator
while (tokens.hasNext()) {
state = parseOptions(tokens, state, command.getCommandOptions());
- state = parseArgs(state, tokens, command.getArguments(), command.getDefaultOption());
+ state = parseArgs(state, tokens, command.getPositionalArguments(), command.getArguments(), command.getDefaultOption());
}
return state;
}
@@ -179,7 +180,7 @@ protected ParseState parseGroup(PeekingIterator tokens, ParseState
? new AbbreviatedGroupFinder(tokens.peek(), state.getGlobal().getCommandGroups())
: new GroupFinder(tokens.peek());
//@formatter:on
- CommandGroupMetadata group = CollectionUtils.find(state.getGlobal().getCommandGroups(), findGroupPredicate);
+ CommandGroupMetadata group = IterableUtils.find(state.getGlobal().getCommandGroups(), findGroupPredicate);
if (group != null) {
tokens.next();
state = state.withGroup(group).pushContext(Context.GROUP);
@@ -192,7 +193,7 @@ protected ParseState parseGroup(PeekingIterator tokens, ParseState
? new AbbreviatedGroupFinder(tokens.peek(), state.getGroup().getSubGroups())
: new GroupFinder(tokens.peek());
//@formatter:on
- group = CollectionUtils.find(state.getGroup().getSubGroups(), findGroupPredicate);
+ group = IterableUtils.find(state.getGroup().getSubGroups(), findGroupPredicate);
if (group != null) {
tokens.next();
state = state.withGroup(group).pushContext(Context.GROUP);
@@ -247,7 +248,7 @@ private ParseState parseOptions(PeekingIterator tokens, ParseState
return state;
}
- private ParseState parseArgs(ParseState state, PeekingIterator tokens, ArgumentsMetadata arguments,
+ private ParseState parseArgs(ParseState state, PeekingIterator tokens, List positionalArgs, ArgumentsMetadata arguments,
OptionMetadata defaultOption) {
String sep = state.getParserConfiguration().getArgumentsSeparator();
@@ -260,21 +261,21 @@ private ParseState parseArgs(ParseState state, PeekingIterator tok
// Default option can't possibly apply at this point because we
// saw the arguments separator
while (tokens.hasNext()) {
- state = parseArg(state, tokens, arguments, null);
+ state = parseArg(state, tokens, positionalArgs, arguments, null);
}
} else {
- state = parseArg(state, tokens, arguments, defaultOption);
+ state = parseArg(state, tokens, positionalArgs, arguments, defaultOption);
}
}
return state;
}
- private ParseState parseArg(ParseState state, PeekingIterator tokens, ArgumentsMetadata arguments,
+ private ParseState parseArg(ParseState state, PeekingIterator tokens, List positionalArgs, ArgumentsMetadata arguments,
OptionMetadata defaultOption) {
- if (arguments != null) {
+ if (arguments != null || positionalArgs.size() > 0) {
// Argument
- state = state.withArgument(arguments, tokens.next());
+ state = state.withArgument(positionalArgs, arguments, tokens.next());
} else if (defaultOption != null) {
// Default Option
state = state.pushContext(Context.OPTION).withOption(defaultOption);
diff --git a/airline-core/src/main/java/com/github/rvesse/airline/parser/ParseResult.java b/airline-core/src/main/java/com/github/rvesse/airline/parser/ParseResult.java
index 7cf744d92..8e5dbd7e0 100644
--- a/airline-core/src/main/java/com/github/rvesse/airline/parser/ParseResult.java
+++ b/airline-core/src/main/java/com/github/rvesse/airline/parser/ParseResult.java
@@ -112,11 +112,13 @@ public T getCommand() {
if (state.getGlobal() != null) {
// Create instance
return createInstance(command.getType(), command.getAllOptions(), state.getParsedOptions(),
- command.getArguments(), state.getParsedArguments(), command.getMetadataInjections(), bindings,
+ command.getPositionalArguments(), state.getParsedPositionalArguments(), command.getArguments(),
+ state.getParsedArguments(), command.getMetadataInjections(), bindings,
state.getParserConfiguration().getCommandFactory());
} else {
return createInstance(command.getType(), command.getAllOptions(), state.getParsedOptions(),
- command.getArguments(), state.getParsedArguments(), command.getMetadataInjections(), bindings,
+ command.getPositionalArguments(), state.getParsedPositionalArguments(), command.getArguments(),
+ state.getParsedArguments(), command.getMetadataInjections(), bindings,
state.getParserConfiguration().getCommandFactory());
}
diff --git a/airline-core/src/main/java/com/github/rvesse/airline/parser/ParseState.java b/airline-core/src/main/java/com/github/rvesse/airline/parser/ParseState.java
index 1fe6fb008..a9a973ddc 100644
--- a/airline-core/src/main/java/com/github/rvesse/airline/parser/ParseState.java
+++ b/airline-core/src/main/java/com/github/rvesse/airline/parser/ParseState.java
@@ -17,6 +17,7 @@
import com.github.rvesse.airline.Context;
import com.github.rvesse.airline.builder.ParserBuilder;
+import com.github.rvesse.airline.model.PositionalArgumentMetadata;
import com.github.rvesse.airline.model.ArgumentsMetadata;
import com.github.rvesse.airline.model.CommandGroupMetadata;
import com.github.rvesse.airline.model.CommandMetadata;
@@ -35,6 +36,12 @@
import org.apache.commons.lang3.tuple.Pair;
+/**
+ * Used to track the state of the parser
+ *
+ * @param
+ * Command type
+ */
public class ParseState {
private final List locationStack;
private final GlobalMetadata global;
@@ -42,13 +49,15 @@ public class ParseState {
private final CommandGroupMetadata group;
private final CommandMetadata command;
private final List> parsedOptions;
+ private final List> parsedPositionalArgs;
private final List