Skip to content
Snippets Groups Projects
Commit 29be62a2 authored by dgelessus's avatar dgelessus
Browse files

Add internal documentation for the new command parsing code

parent 032af96e
No related branches found
No related tags found
No related merge requests found
Pipeline #41417 passed
......@@ -90,6 +90,26 @@ public final class CommandUtils {
}
}
/**
* <p>
* Split an argument string according to the given parameter specification.
* The splitting process stops either when the {@code upToPosition} index is exceeded,
* when all parameters have been fully parsed,
* or when the entire argument string has been consumed.
* </p>
* <p>
* This method only splits the argument string and does not perform any validation,
* which means that it will parse any input string without errors
* (although the result might not be meaningful).
* Use {@link #validateSplitArgs(Parameters, SplitResult)} to validate the result of this method,
* or use {@link #parseArgs(Parameters, String)} to perform splitting and validation in a single call.
* </p>
*
* @param parameters the parameter specification based on which the arguments should be split
* @param argString the argument string to split
* @param upToPosition the position in the argument string after which to stop splitting
* @return the result of the split operation (see {@link SplitResult} for details)
*/
public static @NotNull SplitResult splitArgs(final @NotNull Parameters parameters, final @NotNull String argString, final int upToPosition) {
final SplitArguments splitArgs = new SplitArguments(Collections.emptyMap());
PositionedString remainingArgs = new PositionedString(argString, 0);
......@@ -134,6 +154,27 @@ public final class CommandUtils {
return new SplitResult(splitArgs, parameterAtPosition, remainingArgs);
}
/**
* <p>
* Split an argument string according to the given parameter specification.
* The splitting process stops either when all parameters have been fully parsed,
* or when the entire argument string has been consumed.
* </p>
* <p>
* This method only splits the argument string and does not perform any validation,
* which means that it will parse any input string without errors
* (although the result might not be meaningful).
* Use {@link #validateSplitArgs(Parameters, SplitResult)} to validate the result of this method,
* or use {@link #parseArgs(Parameters, String)} to perform splitting and validation in a single call.
* </p>
* <p>
* This method is equivalent to calling {@link #splitArgs(Parameters, String, int)} with {@code upToPosition} set so that as much as possible of the argument string is consumed.
* </p>
*
* @param parameters the parameter specification based on which the arguments should be split
* @param argString the argument string to split
* @return the result of the split operation (see {@link SplitResult} for details)
*/
public static @NotNull SplitResult splitArgs(final @NotNull Parameters parameters, final @NotNull String argString) {
return splitArgs(parameters, argString, argString.length());
}
......@@ -142,6 +183,14 @@ public final class CommandUtils {
parsed.put(param, param.getValidator().validate(param, splitArgs.get(param)));
}
/**
* Validate a {@link SplitResult} according to the given parameter specification.
*
* @param parameters the parameter specification based on which the split result should be validated
* @param split the split result to validate
* @return the parsed arguments after validation
* @throws UserErrorException if the split arguments are invalid
*/
public static @NotNull ParsedArguments validateSplitArgs(final @NotNull Parameters parameters, final SplitResult split) {
if (!split.getRemaining().getValue().isEmpty()) {
throw new UserErrorException("Expected at most " + parameters.getPositionalParameters().size() + " arguments, got extra argument: " + split.getRemaining().getValue());
......@@ -158,6 +207,15 @@ public final class CommandUtils {
return parsed;
}
/**
* Parse an argument string according to the given parameter specification.
* This is a shorthand for calling {@link #splitArgs(Parameters, String)} followed by {@link #validateSplitArgs(Parameters, SplitResult)}.
*
* @param parameters the parameter specification based on which the argument string should be parsed
* @param argString the argument string to parse
* @return the parsed and validated argument string
* @throws UserErrorException if the argument string is invalid
*/
public static @NotNull ParsedArguments parseArgs(final @NotNull Parameters parameters, final @NotNull String argString) {
return validateSplitArgs(parameters, splitArgs(parameters, argString));
}
......
......@@ -7,7 +7,17 @@ import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
/**
* A parameter of a {@link Command}.
* How a command's arguments are parsed depends on the {@link Parameter} objects returned by its {@link Command#getParameters()} method,
* as well as the {@link Parameter.Splitter} and {@link Parameter.Validator} objects of those parameters.
*
* @param <T> the type of parsed values for this parameter, as returned by its validator
*/
public interface Parameter<T> {
/**
* The result of a {@link Parameter.Splitter#split(PositionedString)} call.
*/
public static final class SplitResult {
private final @NotNull PositionedString splitArg;
private final @NotNull PositionedString remainingArgString;
......@@ -19,16 +29,44 @@ public interface Parameter<T> {
this.remainingArgString = remainingArgString;
}
/**
* Get the argument value that has been split off by the splitter.
*
* @return the argument value that has been split off by the splitter
*/
public @NotNull PositionedString getSplitArg() {
return this.splitArg;
}
/**
* Get the remainder of the argument string that has not been split yet.
* If the argument string has been fully split,
* this is an empty string positioned at the end of the argument string.
*
* @return the remainder of the argument string that has not been split yet
*/
public @NotNull PositionedString getRemainingArgString() {
return this.remainingArgString;
}
}
/**
* <p>Controls how a {@link Parameter} splits its part of the argument string into separate arguments.</p>
* <p>
* Splitters do not perform any kind of validation on the argument strings they receive.
* They must always return some kind of result without failing,
* even when the input string is invalid and would not be accepted by the parameter/command.
* This is necessary because splitters are used to partially parse argument strings that may be incomplete or otherwise invalid,
* for example to implement code completion and inspection.
* Validation of the split arguments is performed separately later,
* by the {@link Parameter.Validator} or the {@link Command#run(ParsedArguments)} method.
* </p>
*/
@FunctionalInterface
public interface Splitter {
/**
* A {@link Parameter.Splitter} that splits on whitespace.
*/
public static final @NotNull Parameter.Splitter REGULAR = argString -> {
final Matcher argSplitMatcher = CommandUtils.ARG_SPLIT_PATTERN.matcher(argString.getValue());
final PositionedString splitArg;
......@@ -42,12 +80,43 @@ public interface Parameter<T> {
}
return new SplitResult(splitArg, remainingArgString);
};
/**
* A {@link Parameter.Splitter} that consumes the entire remaining argument string without splitting.
*/
public static final @NotNull Parameter.Splitter REMAINDER = argString -> new SplitResult(argString, argString.substring(argString.getValue().length()));
/**
* <p>Split an argument off the given argument string.</p>
* <p>
* A call to this method must always return some kind of usable result and never fail -
* see the documentation of {@link Parameter.Splitter} for details.
* </p>
*
* @param argString the argument string from which to split a single argument
* @return the split argument and the not yet split remainder of the argument string
*/
public abstract Parameter.SplitResult split(final @NotNull PositionedString argString);
}
/**
* <p>
* Controls how a {@link Parameter}'s argument values are validated after being split by a {@link Splitter}.
* After the argument values have been validated,
* they may be translated to a different type than the original {@link List}{@code <}{@link String}{@code >}.
* For example,
* single-value parameters are represented as a {@link String} or {@link Optional}{@code <}{@link String}{@code >},
* depending on whether they are required or optional.
* </p>
*
* @param <T> the type to which the argument values are translated after validation
*/
@FunctionalInterface
public interface Validator<T> {
/**
* A {@link Parameter.Validator} that requires exactly one argument value to be present for the parameter.
* The single argument value is returned as a {@link String}.
*/
public static final @NotNull Parameter.Validator<@NotNull String> EXACTLY_ONE = (param, argValues) -> {
if (argValues.isEmpty()) {
throw new UserErrorException("Missing required parameter " + param.getIdentifier());
......@@ -57,6 +126,13 @@ public interface Parameter<T> {
return argValues.get(0).getValue();
};
/**
* A {@link Parameter.Validator} that requires at most one argument value to be present for the parameter.
* The argument value is represented as an {@link Optional}{@code <}{@link String}{@code >},
* which contains the argument value if it was present,
* or is empty otherwise.
*/
public static final @NotNull Parameter.Validator<@NotNull Optional<String>> ZERO_OR_ONE = (param, argValues) -> {
if (argValues.size() > 1) {
throw new UserErrorException("Non-repeating parameter " + param.getIdentifier() + " cannot appear more than once");
......@@ -64,6 +140,12 @@ public interface Parameter<T> {
return argValues.stream().findAny().map(PositionedString::getValue);
};
/**
* A {@link Parameter.Validator} that requires one or more argument value to be present for the parameter.
* The argument values are returned as a {@link List}{@code <}{@link String}{@code >},
* which is never empty.
*/
public static final @NotNull Parameter.Validator<@NotNull List<@NotNull String>> ONE_OR_MORE = (param, argValues) -> {
if (argValues.isEmpty()) {
throw new UserErrorException("Missing required parameter " + param.getIdentifier());
......@@ -73,35 +155,122 @@ public interface Parameter<T> {
.map(PositionedString::getValue)
.collect(Collectors.toList());
};
/**
* A {@link Parameter.Validator} that requires zero or more argument value to be present for the parameter.
* This validator effectively performs no validation.
* The argument values are returned as a {@link List}{@code <}{@link String}{@code >},
* which may be empty.
*/
public static final @NotNull Parameter.Validator<@NotNull List<@NotNull String>> ZERO_OR_MORE = (param, argValues) -> argValues.stream()
.map(PositionedString::getValue)
.collect(Collectors.toList());
/**
* Validate the given split argument values and translate them to this validator's parsed value type.
*
* @param param the identifier of the parameter to which this validator belongs (only for use in error and debugging messages)
* @param argValues the split argument values to validate
* @return the argument values in parsed form after validation
* @throws UserErrorException if the split argument values are not valid
*/
public abstract T validate(final @NotNull Parameter<T> param, final @NotNull List<@NotNull PositionedString> argValues);
}
/**
* A parameter which results in a single value after validation.
*/
public interface RequiredSingle extends Parameter<@NotNull String> {}
/**
* A parameter which results in an optional value after validation.
*/
public interface OptionalSingle extends Parameter<@NotNull Optional<String>> {}
/**
* A parameter which results in a variable number of values after validation.
*/
public interface Multiple extends Parameter<@NotNull List<@NotNull String>> {}
/**
* <p>Return an internal identifier for this parameter.</p>
* <p>
* This identifier should only be used in error messages and for debugging purposes.
* It is <em>not</em> used to programmatically identify the parameter during argument splitting/validation/parsing -
* instead,
* the parameter object itself is used as the identifier,
* for example in the maps in {@link SplitArguments} or {@link ParsedArguments}.
* Because of this,
* parameter identifiers are technically not required to be unique,
* even within a single command,
* although this is strongly recommended.
* </p>
*
* @return an internal identifier for this parameter
*/
public abstract @NotNull String getIdentifier();
/**
* <p>
* Return whether this parameter is repeating.
* If false,
* the argument parser will use this parameter's splitter to split an argument once,
* and then continue with the next parameters to parse the following arguments.
* If true,
* the argument parser will use this parameter's splitter repeatedly to split the remainder of the argument string.
* </p>
* <p>
* This setting has no meaning in some cases,
* for example for body parameters,
* or parameters whose splitter always consumes the entire remaining argument string anyway.
* </p>
*
* @return whether this parameter is repeating
*/
public abstract boolean isRepeating();
/**
* Return this parameter's splitter.
* See the documentation of {@link Parameter.Splitter} for details about the role of splitters in argument parsing.
*
* @return this parameter's splitter
*/
public abstract @NotNull Parameter.Splitter getSplitter();
/**
* Return this parameter's validator.
* See the documentation of {@link Parameter.Validator} for details about the role of validators in argument parsing.
*
* @return this parameter's validator
*/
public abstract @NotNull Parameter.Validator<T> getValidator();
/**
* Create a new parameter that accepts a single value and must always be present.
*
* @param identifier an identifier for the parameter
* @return a required single-value parameter
*/
public static Parameter.RequiredSingle required(final String identifier) {
return new ParameterBase.RequiredSingle(identifier);
}
/**
* Create a new parameter that accepts a single value and might not be present.
*
* @param identifier an identifier for the parameter
* @return an optional single-value parameter
*/
public static Parameter.OptionalSingle optional(final String identifier) {
return new ParameterBase.OptionalSingle(identifier);
}
/**
* Create a new parameter that accepts multiple values and must always have at least one value present.
*
* @param identifier an identifier for the parameter
* @return a required multi-value parameter
*/
public static Parameter.Multiple requiredMultiple(final String identifier) {
return new ParameterBase.Multiple(identifier) {
@Override
......@@ -111,6 +280,12 @@ public interface Parameter<T> {
};
}
/**
* Create a new parameter that accepts multiple values and might not have any value present.
*
* @param identifier an identifier for the parameter
* @return an optional multi-value parameter
*/
public static Parameter.Multiple optionalMultiple(final String identifier) {
return new ParameterBase.Multiple(identifier) {
@Override
......@@ -120,6 +295,12 @@ public interface Parameter<T> {
};
}
/**
* Create a new parameter that consumes the entire remaining argument string as a single value and must always be present.
*
* @param identifier an identifier for the parameter
* @return a required remainder parameter
*/
public static Parameter.RequiredSingle requiredRemainder(final String identifier) {
return new ParameterBase.RequiredSingle(identifier) {
@Override
......@@ -129,6 +310,12 @@ public interface Parameter<T> {
};
}
/**
* Create a new parameter that consumes the entire remaining argument string as a single value and might not be present.
*
* @param identifier an identifier for the parameter
* @return an optional remainder parameter
*/
public static Parameter.OptionalSingle optionalRemainder(final String identifier) {
return new ParameterBase.OptionalSingle(identifier) {
@Override
......@@ -138,6 +325,12 @@ public interface Parameter<T> {
};
}
/**
* Create a body parameter that must always be present.
*
* @param identifier an identifier for the parameter
* @return a required body parameter
*/
public static Parameter.RequiredSingle body(final String identifier) {
return new ParameterBase.RequiredSingle(identifier) {
@Override
......
......@@ -7,6 +7,11 @@ import com.google.common.base.MoreObjects;
import org.jetbrains.annotations.NotNull;
/**
* Internal base classes for the {@link Parameter} implementations returned by {@link Parameter}'s static factory methods.
*
* @param <T> the type of parsed values for this parameter, as returned by its validator
*/
abstract class ParameterBase<T> implements Parameter<T> {
static class RequiredSingle extends ParameterBase<@NotNull String> implements Parameter.RequiredSingle {
protected RequiredSingle(final @NotNull String identifier) {
......
......@@ -9,7 +9,14 @@ import com.google.common.base.MoreObjects;
import org.jetbrains.annotations.NotNull;
/**
* An unmodifiable collection of per-parameter code completion handlers for a command.
*/
public final class ParameterCompleters {
/**
* An empty set of code completion handlers,
* for commands that do not accept any arguments or do not implement code completion.
*/
public static final @NotNull ParameterCompleters NONE = new ParameterCompleters(Collections.emptyMap());
private final @NotNull Map<@NotNull Parameter<?>, CommandUtils.@NotNull Completer> completers;
......@@ -20,6 +27,11 @@ public final class ParameterCompleters {
this.completers = Collections.unmodifiableMap(new HashMap<>(completers));
}
/**
* Return the stored mapping of parameters to code completion handlers.
*
* @return the stored mapping of parameters to code completion handlers
*/
public @NotNull Map<@NotNull Parameter<?>, CommandUtils.@NotNull Completer> getCompleters() {
return this.completers;
}
......@@ -31,6 +43,13 @@ public final class ParameterCompleters {
.toString();
}
/**
* Return the code completion handler for a parameter, if any.
*
* @param parameter the parameter for which to look up the code completion handler
* @return the code completion handler for a parameter,
* or {@link Optional#empty()} if there is none
*/
public @NotNull Optional<CommandUtils.Completer> getCompleterForParameter(final @NotNull Parameter<?> parameter) {
if (this.getCompleters().containsKey(parameter)) {
return Optional.of(this.getCompleters().get(parameter));
......
......@@ -9,7 +9,14 @@ import com.google.common.base.MoreObjects;
import org.jetbrains.annotations.NotNull;
/**
* An unmodifiable collection of per-parameter inspection handlers for a command.
*/
public final class ParameterInspectors {
/**
* An empty set of inspection handlers,
* for commands that do not accept any arguments or do not implement inspection.
*/
public static final @NotNull ParameterInspectors NONE = new ParameterInspectors(Collections.emptyMap());
private final @NotNull Map<@NotNull Parameter<?>, CommandUtils.@NotNull Inspector> inspectors;
......@@ -20,6 +27,11 @@ public final class ParameterInspectors {
this.inspectors = Collections.unmodifiableMap(new HashMap<>(inspectors));
}
/**
* Return the stored mapping of parameters to inspection handlers.
*
* @return the stored mapping of parameters to inspection handlers
*/
public @NotNull Map<@NotNull Parameter<?>, CommandUtils.@NotNull Inspector> getInspectors() {
return this.inspectors;
}
......@@ -31,6 +43,13 @@ public final class ParameterInspectors {
.toString();
}
/**
* Return the inspection handler for a parameter, if any.
*
* @param parameter the parameter for which to look up the inspection handler
* @return the inspection handler for a parameter,
* or {@link Optional#empty()} if there is none
*/
public @NotNull Optional<CommandUtils.Inspector> getInspectorForParameter(final @NotNull Parameter<?> parameter) {
if (this.getInspectors().containsKey(parameter)) {
return Optional.of(this.getInspectors().get(parameter));
......
......@@ -7,7 +7,15 @@ import java.util.Optional;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A specification for the parameters accepted by a {@link Command}.
* This information is used by {@link ProBKernel} to parse the arguments of a command call for exection, inspection, and code completion.
*/
public final class Parameters {
/**
* A parameter specification that has no parameters,
* for commands that do not accept any arguments.
*/
public static final @NotNull Parameters NONE = new Parameters(Collections.emptyList());
private final @NotNull List<Parameter<?>> positionalParameters;
......@@ -40,10 +48,20 @@ public final class Parameters {
this(positionalParameters, null);
}
/**
* Return the list of accepted positional parameters.
*
* @return the list of accepted positional parameters
*/
public @NotNull List<Parameter<?>> getPositionalParameters() {
return this.positionalParameters;
}
/**
* Return the positional parameter for the body, if any.
*
* @return the positional parameter for the body, if any
*/
public @NotNull Optional<Parameter.RequiredSingle> getBodyParam() {
return Optional.ofNullable(this.bodyParam);
}
......
......@@ -7,6 +7,12 @@ import com.google.common.base.MoreObjects;
import org.jetbrains.annotations.NotNull;
/**
* A collection of parsed and validated command arguments,
* mapped to their parameters.
* Internally this is a map of parameters to arbitrary objects,
* but the methods of this class ensure that parameters can only be mapped to their declared parsed value type.
*/
public final class ParsedArguments {
private final @NotNull Map<@NotNull Parameter<?>, Object> values;
......@@ -16,10 +22,23 @@ public final class ParsedArguments {
this.values = new HashMap<>(values);
}
/**
* Return whether a value has been associated with the given parameter.
*
* @param parameter the parameter for which to check for a value
* @return whether a value has been associated with the given parameter
*/
public boolean containsKey(final @NotNull Parameter<?> parameter) {
return this.values.containsKey(parameter);
}
/**
* Return the parsed value associated with the given parameter.
*
* @param parameter the parameter for which to return the value
* @param <T> the type of parsed value for the parameter
* @return the parsed value associated with the given parameter
*/
public <T> T get(final @NotNull Parameter<T> parameter) {
if (!this.containsKey(parameter)) {
throw new IllegalArgumentException("No value present for parameter " + parameter);
......@@ -29,6 +48,13 @@ public final class ParsedArguments {
return value;
}
/**
* Associate a parsed value with the given parameter.
*
* @param parameter the parameter with which to associate the value
* @param value the parsed value to associate with the parameter
* @param <T> the type of parsed value for the parameter
*/
public <T> void put(final @NotNull Parameter<T> parameter, final T value) {
this.values.put(parameter, value);
}
......
......@@ -4,6 +4,10 @@ import com.google.common.base.MoreObjects;
import org.jetbrains.annotations.NotNull;
/**
* A string with a known position relative to a known origin or larger string.
* This class is used while splitting/parsing commands and arguments to track the position of individual argument strings within the source code.
*/
public final class PositionedString {
private final @NotNull String value;
private final int startPosition;
......@@ -15,22 +19,64 @@ public final class PositionedString {
this.startPosition = startPosition;
}
/**
* Return this string's text value.
*
* @return this string's text value
*/
public @NotNull String getValue() {
return this.value;
}
/**
* Return the position of the start of this string.
*
* @return the position of the start of this string relative to a known origin
*/
public int getStartPosition() {
return this.startPosition;
}
/**
* <p>
* Return a substring of this string, with the position adjusted accordingly.
* This method behaves like {@link String#substring(int, int)}.
* </p>
* <p>
* {@code beginIndex} and {@code endIndex} are relative to the underlying text value and are not affected by this string's position information.
* </p>
*
* @param beginIndex the beginning index of the substring, inclusive
* @param endIndex the end index of the substring, exclusive
* @return the substring of this string, from {@code beginIndex} to {@code endIndex}, with the position increased by {@code beginIndex}
*/
public PositionedString substring(final int beginIndex, final int endIndex) {
return new PositionedString(this.getValue().substring(beginIndex, endIndex), this.getStartPosition() + beginIndex);
}
/**
* <p>
* Return a substring of this string, with the position adjusted accordingly.
* This method behaves like {@link String#substring(int)}.
* </p>
* <p>
* {@code beginIndex} is relative to the underlying text value and is not affected by this string's position information.
* </p>
*
* @param beginIndex the beginning index of the substring, inclusive
* @return the substring of this string, from {@code beginIndex} to the end of the string, with the position increased by {@code beginIndex}
*/
public PositionedString substring(final int beginIndex) {
return this.substring(beginIndex, this.getValue().length());
}
/**
* Return a text representation of this string for debugging purposes.
* This method does <em>not</em> return the string's underyling text value -
* {@link #getValue()} should be used for that purpose.
*
* @return a text representation of this string for debugging
*/
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
......
......@@ -10,6 +10,12 @@ import com.google.common.base.MoreObjects;
import org.jetbrains.annotations.NotNull;
/**
* A collection of command arguments that have been split and mapped to their parameters,
* but not fully validated yet.
* Internally this is a simple map of parameter objects to lists of strings,
* but this class provides a more convenient interface for the specialized purpose of this map.
*/
public final class SplitArguments {
private final @NotNull Map<@NotNull Parameter<?>, @NotNull List<@NotNull PositionedString>> values;
......@@ -19,14 +25,36 @@ public final class SplitArguments {
this.values = new HashMap<>(values);
}
/**
* Return whether any values have been associated with the given parameter.
*
* @param parameter the parameter for which to check for values
* @return whether any values have been associated with the given parameter
*/
public boolean containsKey(final @NotNull Parameter<?> parameter) {
return this.values.containsKey(parameter);
}
/**
* Return the list of values associated with the given parameter.
* If there are no associated values
* (i. e. {@link #containsKey(Parameter)} returns {@code false} for the parameter),
* no exception is thrown and an empty list is returned.
*
* @param parameter the parameter for which to get values
* @return the list of values associated with the given parameter,
* or an empty list if there are none
*/
public @NotNull List<@NotNull PositionedString> get(final @NotNull Parameter<?> parameter) {
return this.values.getOrDefault(parameter, Collections.emptyList());
}
/**
* Add a new value to the list of values associated with the given parameter.
*
* @param parameter the parameter with which to associate the value
* @param value the value to add
*/
public void add(final @NotNull Parameter<?> parameter, final PositionedString value) {
this.values.computeIfAbsent(parameter, p -> new ArrayList<>()).add(value);
}
......
......@@ -7,6 +7,9 @@ import com.google.common.base.MoreObjects;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* The unvalidated result of a command argument splitting operation ({@link CommandUtils#splitArgs(Parameters, String, int)} or {@link CommandUtils#splitArgs(Parameters, String)}).
*/
public final class SplitResult {
private final @NotNull SplitArguments arguments;
private final @Nullable Parameter<?> parameterAtPosition;
......@@ -20,14 +23,36 @@ public final class SplitResult {
this.remaining = remaining;
}
/**
* Return the split arguments from the input string,
* mapped to their respective parameters.
*
* @return the split arguments from the input string,
* mapped to their respective parameters
*/
public @NotNull SplitArguments getArguments() {
return this.arguments;
}
/**
* Return the parameter to which the last split argument belongs,
* or {@link Optional#empty()} if no arguments have been split.
* This information is mainly useful when calling {@link CommandUtils#splitArgs(Parameters, String, int)} with an explicit {@code upToPosition} argument.
*
* @return the parameter to which the last split argument belongs,
* or {@link Optional#empty()} if no arguments have been split
*/
public @NotNull Optional<Parameter<?>> getParameterAtPosition() {
return Optional.ofNullable(this.parameterAtPosition);
}
/**
* Return the remainder of the argument string that has not been split.
* If the argument string was consumed completely by the split operation,
* this is an empty string.
*
* @return the remainder of the argument string that has not been split
*/
public @NotNull PositionedString getRemaining() {
return this.remaining;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment