@@ -16,8 +16,7 @@
|
||||
|
||||
package org.springframework.shell2.standard;
|
||||
|
||||
import static org.springframework.shell2.Utils.unCamelify;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.ArrayList;
|
||||
@@ -48,6 +47,9 @@ import org.springframework.shell2.Utils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import static org.springframework.shell2.Utils.unCamelify;
|
||||
|
||||
/**
|
||||
* Default ParameterResolver implementation that supports the following features:<ul>
|
||||
@@ -178,7 +180,12 @@ public class StandardParameterResolver implements ParameterResolver {
|
||||
if (!resolved.containsKey(param)) {
|
||||
throw new ParameterMissingResolutionException(describe(methodParameter));
|
||||
}
|
||||
String s = resolved.get(param).value;
|
||||
ParameterRawValue parameterRawValue = resolved.get(param);
|
||||
return convertRawValue(parameterRawValue, methodParameter);
|
||||
}
|
||||
|
||||
private Object convertRawValue(ParameterRawValue parameterRawValue, MethodParameter methodParameter) {
|
||||
String s = parameterRawValue.value;
|
||||
if (ShellOption.NULL.equals(s)) {
|
||||
return null;
|
||||
}
|
||||
@@ -261,10 +268,12 @@ public class StandardParameterResolver implements ParameterResolver {
|
||||
Exception unfinished = null;
|
||||
// First try to see if this parameter has been set, even to some unfinished value
|
||||
ParameterRawValue parameterRawValue = null;
|
||||
int arity = 1;
|
||||
try {
|
||||
resolve(methodParameter, context.getWords());
|
||||
CacheKey cacheKey = new CacheKey(methodParameter.getMethod(), context.getWords());
|
||||
Parameter parameter = methodParameter.getMethod().getParameters()[methodParameter.getParameterIndex()];
|
||||
arity = getArity(parameter);
|
||||
parameterRawValue = parameterCache.get(cacheKey).get(parameter);
|
||||
set = parameterRawValue.explicit;
|
||||
}
|
||||
@@ -279,11 +288,12 @@ public class StandardParameterResolver implements ParameterResolver {
|
||||
//return Collections.emptyList();
|
||||
}
|
||||
|
||||
// There are 3 possible cases:
|
||||
// There are 4 possible cases:
|
||||
// 1) parameter not set at all
|
||||
// 2) parameter set via its key, not enough input to consume a value
|
||||
// 3) parameter set, and some value bound. But maybe that value is just a prefix to what the user actually wants
|
||||
// 3.1) or maybe that value was resolved by position, but is a prefix of an actual valid key
|
||||
// 3) parameter set with multiple values, enough to cover arity. We're done
|
||||
// 4) parameter set, and some value bound. But maybe that value is just a prefix to what the user actually wants
|
||||
// 4.1) or maybe that value was resolved by position, but is a prefix of an actual valid key
|
||||
|
||||
if (!set) {
|
||||
if (unfinished == null) { // case 1 above
|
||||
@@ -298,11 +308,18 @@ public class StandardParameterResolver implements ParameterResolver {
|
||||
|
||||
String prefix = context.currentWordUpToCursor() != null ? context.currentWordUpToCursor() : "";
|
||||
// TODO: should not look at last word only, but everything after what was used for key
|
||||
// Case 3
|
||||
|
||||
Object value = convertRawValue(parameterRawValue, methodParameter);
|
||||
if (value instanceof Collection && ((Collection) value).size() == arity
|
||||
|| (ObjectUtils.isArray(value) && Array.getLength(value) == arity)) {
|
||||
// We're done already
|
||||
return result;
|
||||
}
|
||||
// Case 4
|
||||
result.addAll(valueCompletions(methodParameter, context));
|
||||
|
||||
if (parameterRawValue.positional()) {
|
||||
// Case 3.1: There exists "--command foo" and user has typed "--comm" which (wrongly) got resolved as a positional param
|
||||
// Case 4.1: There exists "--command foo" and user has typed "--comm" which (wrongly) got resolved as a positional param
|
||||
result.addAll(commandsThatStartWithContextPrefix(methodParameter, context));
|
||||
}
|
||||
return result;
|
||||
@@ -320,7 +337,7 @@ public class StandardParameterResolver implements ParameterResolver {
|
||||
String prefix = context.currentWordUpToCursor() != null ? context.currentWordUpToCursor() : "";
|
||||
return describe(methodParameter).keys().stream()
|
||||
.filter(k -> k.startsWith(prefix))
|
||||
.map(v -> new CompletionProposal(v))
|
||||
.map(CompletionProposal::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.shell2.standard;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.shell2.CompletionContext;
|
||||
@@ -57,6 +58,11 @@ public class Remote {
|
||||
|
||||
}
|
||||
|
||||
@ShellMethod(help = "add 3 numbers together (array)")
|
||||
public void addAsArray(@ShellOption(arity = 3, valueProvider = NumberValueProvider.class) int[] numbers) {
|
||||
|
||||
}
|
||||
|
||||
public enum Delay {
|
||||
small, medium, big;
|
||||
}
|
||||
@@ -64,12 +70,18 @@ public class Remote {
|
||||
|
||||
public static class NumberValueProvider extends ValueProviderSupport {
|
||||
|
||||
private final String[] values;
|
||||
|
||||
public NumberValueProvider(String... values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompletionProposal> complete(MethodParameter parameter, CompletionContext completionContext, String[] hints) {
|
||||
String prefix = completionContext.currentWord() != null ? completionContext.currentWord() : "";
|
||||
return Arrays.asList("12", "42", "7").stream()
|
||||
return Stream.of(values)
|
||||
.filter(n -> n.startsWith(prefix))
|
||||
.map(n -> new CompletionProposal(n))
|
||||
.map(CompletionProposal::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,18 +16,12 @@
|
||||
|
||||
package org.springframework.shell2.standard;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.util.ReflectionUtils.findMethod;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jline.reader.ParsedLine;
|
||||
import org.jline.reader.impl.DefaultParser;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
@@ -39,6 +33,11 @@ import org.springframework.shell2.ParameterMissingResolutionException;
|
||||
import org.springframework.shell2.UnfinishedParameterResolutionException;
|
||||
import org.springframework.shell2.Utils;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.util.ReflectionUtils.findMethod;
|
||||
|
||||
/**
|
||||
* Unit tests for DefaultParameterResolver.
|
||||
* @author Eric Bottard
|
||||
@@ -208,35 +207,32 @@ public class StandardParameterResolverTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("--numbers 42 34 66 fails")
|
||||
public void testValueCompletionWithNonDefaultArity() {
|
||||
|
||||
resolver.setValueProviders(Arrays.asList(new Remote.NumberValueProvider()));
|
||||
resolver.setValueProviders(singletonList(new Remote.NumberValueProvider("12", "42", "7")));
|
||||
|
||||
Method method = findMethod(Remote.class, "add", List.class);
|
||||
List<String> completions = resolver.complete(
|
||||
Utils.createMethodParameter(method, 0),
|
||||
contextFor("--numbers ")
|
||||
).stream().map(CompletionProposal::value).collect(Collectors.toList());
|
||||
assertThat(completions).contains("12");
|
||||
Method[] methods = {
|
||||
findMethod(org.springframework.shell2.standard.Remote.class, "add", List.class),
|
||||
findMethod(org.springframework.shell2.standard.Remote.class, "addAsArray", int[].class),
|
||||
};
|
||||
for (Method method : methods) {
|
||||
List<String> completions = resolver
|
||||
.complete(Utils.createMethodParameter(method, 0), contextFor("--numbers ")).stream()
|
||||
.map(CompletionProposal::value).collect(Collectors.toList());
|
||||
assertThat(completions).contains("12", "42", "7");
|
||||
|
||||
completions = resolver.complete(
|
||||
Utils.createMethodParameter(method, 0),
|
||||
contextFor("--numbers 42 ")
|
||||
).stream().map(CompletionProposal::value).collect(Collectors.toList());
|
||||
assertThat(completions).contains("12");
|
||||
completions = resolver.complete(Utils.createMethodParameter(method, 0), contextFor("--numbers 42 "))
|
||||
.stream().map(CompletionProposal::value).collect(Collectors.toList());
|
||||
assertThat(completions).contains("12", "7");
|
||||
|
||||
completions = resolver.complete(
|
||||
Utils.createMethodParameter(method, 0),
|
||||
contextFor("--numbers 42 34 ")
|
||||
).stream().map(CompletionProposal::value).collect(Collectors.toList());
|
||||
assertThat(completions).contains("12");
|
||||
completions = resolver.complete(Utils.createMethodParameter(method, 0), contextFor("--numbers 42 34 "))
|
||||
.stream().map(CompletionProposal::value).collect(Collectors.toList());
|
||||
assertThat(completions).contains("12", "7");
|
||||
|
||||
completions = resolver.complete(
|
||||
Utils.createMethodParameter(method, 0),
|
||||
contextFor("--numbers 42 34 66 ")
|
||||
).stream().map(CompletionProposal::value).collect(Collectors.toList());
|
||||
assertThat(completions).isEmpty();
|
||||
completions = resolver.complete(Utils.createMethodParameter(method, 0), contextFor("--numbers 42 34 66 "))
|
||||
.stream().map(CompletionProposal::value).collect(Collectors.toList());
|
||||
assertThat(completions).isEmpty(); // All 3 have already been set
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
package org.springframework.shell2.samples.standard;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.shell2.standard.ShellComponent;
|
||||
import org.springframework.shell2.standard.ShellMethod;
|
||||
import org.springframework.shell2.standard.ShellOption;
|
||||
|
||||
/**
|
||||
* Example commands for the Shell 2 Standard resolver.
|
||||
@@ -54,4 +55,10 @@ public class Commands {
|
||||
public void fail(ElementType elementType) {
|
||||
throw new IllegalArgumentException("You said " + elementType);
|
||||
}
|
||||
|
||||
@ShellMethod(help = "add array numbers")
|
||||
public double addDoubles(@ShellOption(arity = 3) double[] numbers) {
|
||||
return Arrays.stream(numbers).sum();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user