SHL-113: Don't report ambiguity on an exact match
This commit is contained in:
@@ -103,6 +103,7 @@ public class SimpleParser implements Parser {
|
||||
return optionsKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParseResult parse(final String rawInput) {
|
||||
synchronized (mutex) {
|
||||
Assert.notNull(rawInput, "Raw input required");
|
||||
@@ -124,12 +125,25 @@ public class SimpleParser implements Parser {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
MethodTarget methodTarget = null;
|
||||
if (matchingTargets.size() > 1) {
|
||||
LOGGER.warning("Ambigious command '" + input + "' (for assistance press "
|
||||
+ AbstractShell.completionKeys + " or type \"hint\" then hit ENTER)");
|
||||
return null;
|
||||
// Any prefix of a valid command will do. Don't fail if the user used
|
||||
// the exact key of a command though.
|
||||
for (MethodTarget candidate : matchingTargets) {
|
||||
if (candidate.getKey().equals(input) || input.startsWith(candidate.getKey() + " ")) {
|
||||
methodTarget = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (methodTarget == null) {
|
||||
LOGGER.warning("Ambigious command '" + input + "' (for assistance press "
|
||||
+ AbstractShell.completionKeys + " or type \"hint\" then hit ENTER)");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
methodTarget = matchingTargets.iterator().next();
|
||||
}
|
||||
MethodTarget methodTarget = matchingTargets.iterator().next();
|
||||
|
||||
// Argument conversion time
|
||||
Annotation[][] parameterAnnotations = methodTarget.getMethod().getParameterAnnotations();
|
||||
@@ -514,6 +528,7 @@ public class SimpleParser implements Parser {
|
||||
return null; // Not a match
|
||||
}
|
||||
|
||||
@Override
|
||||
public int complete(String buffer, int cursor, final List<String> candidates) {
|
||||
final List<Completion> completions = new ArrayList<Completion>();
|
||||
int result = completeAdvanced(buffer, cursor, completions);
|
||||
@@ -523,6 +538,7 @@ public class SimpleParser implements Parser {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int completeAdvanced(String buffer, int cursor, final List<Completion> candidates) {
|
||||
synchronized (mutex) {
|
||||
Assert.notNull(buffer, "Buffer required");
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.hamcrest.Matcher;
|
||||
import org.junit.Test;
|
||||
import org.springframework.shell.core.annotation.CliCommand;
|
||||
import org.springframework.shell.core.annotation.CliOption;
|
||||
import org.springframework.shell.event.ParseResult;
|
||||
|
||||
/**
|
||||
* Tests for parsing and completion logic.
|
||||
@@ -368,6 +369,23 @@ public class SimpleParserTests {
|
||||
assertThat(candidates, hasItem(completionThat(is(equalTo("bar --option1 \"def\" ")))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://jira.spring.io/browse/SHL-113
|
||||
*/
|
||||
@Test
|
||||
public void testFalseAmbiguity() {
|
||||
parser.add(new SamePrefixCommands());
|
||||
ParseResult result = parser.parse("foo");
|
||||
assertThat(result.getMethod().getName(), equalTo("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRealAmbiguity() {
|
||||
parser.add(new SamePrefixCommands());
|
||||
ParseResult result = parser.parse("fo");
|
||||
assertThat(result, nullValue(ParseResult.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a matcher that asserts that a completion, when added to {@link #buffer} at the given {@link #offset},
|
||||
* indeed matches the provided matcher.
|
||||
@@ -375,6 +393,7 @@ public class SimpleParserTests {
|
||||
private Matcher<Completion> completionThat(final Matcher<String> matcher) {
|
||||
return new DiagnosingMatcher<Completion>() {
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("a completion that ").appendDescriptionOf(matcher);
|
||||
}
|
||||
@@ -448,6 +467,20 @@ public class SimpleParserTests {
|
||||
}
|
||||
}
|
||||
|
||||
public static class SamePrefixCommands implements CommandMarker {
|
||||
@CliCommand(value = "foo")
|
||||
public String foo(@CliOption(key = "")
|
||||
String arg) {
|
||||
return "foo " + arg;
|
||||
}
|
||||
|
||||
@CliCommand(value = "fooBar")
|
||||
public String fooBar(@CliOption(key = "")
|
||||
String arg) {
|
||||
return "fooBar " + arg;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StringCompletions implements Converter<String> {
|
||||
|
||||
private final List<String> completions;
|
||||
@@ -463,14 +496,17 @@ public class SimpleParserTests {
|
||||
this.canContinue = canContinue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> type, String optionContext) {
|
||||
return type == String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertFromText(String value, Class<?> targetType, String optionContext) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType, String existingData,
|
||||
String optionContext, MethodTarget target) {
|
||||
for (String s : this.completions) {
|
||||
|
||||
Reference in New Issue
Block a user