diff --git a/src/main/java/org/springframework/shell/core/SimpleParser.java b/src/main/java/org/springframework/shell/core/SimpleParser.java index 6bc93d84..36c4babb 100644 --- a/src/main/java/org/springframework/shell/core/SimpleParser.java +++ b/src/main/java/org/springframework/shell/core/SimpleParser.java @@ -808,10 +808,11 @@ public class SimpleParser implements Parser { for (Completion currentValue : allValues) { // Only add the result **if** what they've typed is compatible *AND* they haven't // already typed it in full - if (currentValue.getValue().toLowerCase().startsWith(lastOptionValue.toLowerCase()) - && lastOptionValue.length() < currentValue.getValue().length() + String proposal = currentValue.getValue(); + if (proposal.toLowerCase().startsWith(lastOptionValue.toLowerCase()) + && lastOptionValue.length() < proposal.length() && (!tokenizer.lastValueIsComplete())) { - results.add(new Completion(currentValue.getValue() + suffix, currentValue + results.add(new Completion(tokenizer.escape(proposal) + suffix, currentValue .getFormattedValue(), currentValue.getHeading(), currentValue.getOrder())); } } @@ -822,7 +823,7 @@ public class SimpleParser implements Parser { if (results.size() == 1) { String suggestion = results.iterator().next().getValue().trim(); - if (suggestion.equals(lastOptionValue)) { + if (suggestion.equals(tokenizer.escape(lastOptionValue))) { // They have pressed TAB in the default value, and the default value has already // been provided as an explicit option return -1; diff --git a/src/main/java/org/springframework/shell/core/Tokenizer.java b/src/main/java/org/springframework/shell/core/Tokenizer.java index ef7937cc..890ad8f1 100644 --- a/src/main/java/org/springframework/shell/core/Tokenizer.java +++ b/src/main/java/org/springframework/shell/core/Tokenizer.java @@ -183,6 +183,13 @@ public class Tokenizer { return !openingQuotesHaveNotBeenClosed && lastValueDelimiter != ' '; } + /** + * Apply delimiter escaping to the given string, using the actual delimiter that was used for the last value. + */ + public String escape(String value) { + return value.replace("" + lastValueDelimiter, "" + ESCAPE_CHAR + lastValueDelimiter); + } + /** * Consume a full @code{--key value} pair *unless* we're at the very end, in which case allow for @code {--key}, * using "" for the value. diff --git a/src/test/java/org/springframework/shell/core/SimpleParserTests.java b/src/test/java/org/springframework/shell/core/SimpleParserTests.java index 556bed91..0f101554 100644 --- a/src/test/java/org/springframework/shell/core/SimpleParserTests.java +++ b/src/test/java/org/springframework/shell/core/SimpleParserTests.java @@ -34,7 +34,6 @@ import java.util.List; import org.hamcrest.Description; import org.hamcrest.DiagnosingMatcher; import org.hamcrest.Matcher; -import org.junit.Ignore; import org.junit.Test; import org.springframework.shell.core.annotation.CliCommand; import org.springframework.shell.core.annotation.CliOption; @@ -163,7 +162,6 @@ public class SimpleParserTests { } @Test - @Ignore("TODO") public void testArgumentValueWithEscapedQuotes() { parser.add(new MyCommands()); parser.add(new StringCompletions(Arrays.asList("he said \"hello\" to me")));