Merge pull request #499 from EngineHub/fix/quoted

Fixes using suggestions with quoted args, as well as a few other minor issues with suggestions.
This commit is contained in:
wizjany 2019-07-28 10:07:32 -04:00 committed by GitHub
commit 6855f22152
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 75 additions and 25 deletions

View File

@ -335,7 +335,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
// code of WorldEdit expects it
String[] split = new String[args.length + 1];
System.arraycopy(args, 0, split, 1, args.length);
split[0] = "/" + cmd.getName();
split[0] = "/" + commandLabel;
CommandEvent event = new CommandEvent(wrapCommandSender(sender), Joiner.on(" ").join(split));
getWorldEdit().getEventBus().post(event);
@ -349,7 +349,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
// code of WorldEdit expects it
String[] split = new String[args.length + 1];
System.arraycopy(args, 0, split, 1, args.length);
split[0] = "/" + cmd.getName();
split[0] = "/" + commandLabel;
String arguments = Joiner.on(" ").join(split);
CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), arguments);

View File

@ -49,11 +49,12 @@ public final class SuggestionHelper {
public static Stream<String> getBlockCategorySuggestions(String tag, boolean allowRandom) {
if (tag.isEmpty() || tag.equals("#")) {
return Stream.of("##", "##*");
return allowRandom ? Stream.of("##", "##*") : Stream.of("##");
}
if (tag.startsWith("#")) {
if (tag.startsWith("##")) {
if (tag.equals("##")) {
return Stream.concat(Stream.of("##*"), getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(2)).map(s -> "##" + s));
return Stream.concat(allowRandom ? Stream.of("##*") : Stream.empty(),
getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(2)).map(s -> "##" + s));
} else if (tag.equals("##*") && allowRandom) {
return getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(3)).map(s -> "##*" + s);
} else {

View File

@ -42,6 +42,7 @@ import com.sk89q.worldedit.internal.registry.InputParser;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* A registry of known {@link Mask}s. Provides methods to instantiate
@ -74,6 +75,16 @@ public final class MaskFactory extends AbstractFactory<Mask> {
register(new BiomeMaskParser(worldEdit));
}
@Override
public List<String> getSuggestions(String input) {
final String[] split = input.split(" ");
if (split.length > 1) {
String prev = input.substring(0, input.lastIndexOf(" ")) + " ";
return super.getSuggestions(split[split.length -1]).stream().map(s -> prev + s).collect(Collectors.toList());
}
return super.getSuggestions(input);
}
@Override
public Mask parseFromInput(String input, ParserContext context) throws InputParseException {
List<Mask> masks = new ArrayList<>();

View File

@ -431,7 +431,7 @@ public final class PlatformCommandManager {
}
private Stream<Substring> parseArgs(String input) {
return new CommandArgParser(CommandArgParser.spaceSplit(input.substring(1))).parseArgs();
return CommandArgParser.forArgString(input.substring(1)).parseArgs();
}
@Subscribe

View File

@ -31,6 +31,10 @@ import java.util.stream.Stream;
public class CommandArgParser {
public static CommandArgParser forArgString(String argString) {
return new CommandArgParser(spaceSplit(argString));
}
public static ImmutableList<Substring> spaceSplit(String string) {
ImmutableList.Builder<Substring> result = ImmutableList.builder();
int index = 0;
@ -67,16 +71,28 @@ public class CommandArgParser {
handleQuote(nextPart);
}
}
if (currentArg.size() > 0) {
finishArg(); // force finish "hanging" args
}
return args.build();
}
private void handleNormal(Substring part) {
if (part.getSubstring().startsWith("\"")) {
state = State.QUOTE;
currentArg.add(Substring.wrap(
part.getSubstring().substring(1),
part.getStart(), part.getEnd()
));
final String strPart = part.getSubstring();
if (strPart.startsWith("\"")) {
if (strPart.endsWith("\"") && strPart.length() > 1) {
currentArg.add(Substring.wrap(
strPart.substring(1, strPart.length() - 1),
part.getStart() + 1, part.getEnd() - 1
));
finishArg();
} else {
state = State.QUOTE;
currentArg.add(Substring.wrap(
strPart.substring(1),
part.getStart() + 1, part.getEnd()
));
}
} else {
currentArg.add(part);
finishArg();
@ -88,7 +104,7 @@ public class CommandArgParser {
state = State.NORMAL;
currentArg.add(Substring.wrap(
part.getSubstring().substring(0, part.getSubstring().length() - 1),
part.getStart(), part.getEnd()
part.getStart(), part.getEnd() - 1
));
finishArg();
} else {

View File

@ -65,20 +65,33 @@ public class CommandUtil {
* Fix {@code suggestions} to replace the last space-separated word in {@code arguments}.
*/
public static List<String> fixSuggestions(String arguments, List<Substring> suggestions) {
Substring lastArg = Iterables.getLast(CommandArgParser.spaceSplit(arguments));
Substring lastArg = Iterables.getLast(
CommandArgParser.spaceSplit(arguments)
);
return suggestions.stream()
// Re-map suggestions to only operate on the last non-quoted word
.map(CommandUtil::onlyOnLastQuotedWord)
.map(suggestion -> CommandUtil.suggestLast(lastArg, suggestion))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toList());
}
private static Substring onlyOnLastQuotedWord(Substring suggestion) {
String substr = suggestion.getSubstring();
int sp = substr.lastIndexOf(' ');
if (sp < 0) {
return suggestion;
}
return Substring.wrap(substr.substring(sp + 1), suggestion.getStart() + sp + 1, suggestion.getEnd());
}
/**
* Given the last word of a command, mutate the suggestion to replace the last word, if
* possible.
*/
private static Optional<String> suggestLast(Substring last, Substring suggestion) {
if (suggestion.getStart() == last.getEnd()) {
if (suggestion.getStart() == last.getEnd() && !last.getSubstring().equals("\"")) {
// this suggestion is for the next argument.
if (last.getSubstring().isEmpty()) {
return Optional.of(suggestion.getSubstring());

View File

@ -23,29 +23,36 @@ import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.internal.util.Substring;
import org.junit.jupiter.api.Test;
import static com.sk89q.worldedit.internal.command.CommandArgParser.spaceSplit;
import java.util.List;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CommandArgParserTest {
class CommandArgParserTest {
private static List<Substring> argParse(String s) {
return CommandArgParser.forArgString(s).parseArgs().collect(Collectors.toList());
}
@Test
public void testSpaceSplit() {
void testArgumentParsing() {
assertEquals(ImmutableList.of(
Substring.wrap("", 0, 0)
), spaceSplit(""));
), argParse(""));
assertEquals(ImmutableList.of(
Substring.wrap("ab", 0, 2)
), spaceSplit("ab"));
), argParse("ab"));
assertEquals(ImmutableList.of(
Substring.wrap("", 0, 0),
Substring.wrap("", 1, 1)
), spaceSplit(" "));
), argParse(" "));
assertEquals(ImmutableList.of(
Substring.wrap("a", 0, 1),
Substring.wrap("", 2, 2)
), spaceSplit("a "));
), argParse("a "));
assertEquals(ImmutableList.of(
Substring.wrap("a", 0, 1),
Substring.wrap("b", 2, 3)
), spaceSplit("a b"));
), argParse("a b"));
}
}

View File

@ -111,7 +111,8 @@ public final class CommandWrapper {
// Ensure there is a space!
if (suggestion.getStart() == suggestion.getEnd()
&& suggestion.getEnd() == builder.getInput().length()
&& !builder.getInput().endsWith(" ")) {
&& !builder.getInput().endsWith(" ")
&& !builder.getInput().endsWith("\"")) {
suggestionText = " " + suggestionText;
}
result.add(new Suggestion(

View File

@ -103,7 +103,8 @@ public final class CommandWrapper {
// Ensure there is a space!
if (suggestion.getStart() == suggestion.getEnd()
&& suggestion.getEnd() == builder.getInput().length()
&& !builder.getInput().endsWith(" ")) {
&& !builder.getInput().endsWith(" ")
&& !builder.getInput().endsWith("\"")) {
suggestionText = " " + suggestionText;
}
result.add(new Suggestion(