diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index 962243c9f..646672d2f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -273,8 +273,8 @@ public int generate(Player player, LocalSession session, EditSession editSession @Selection Region region, @Arg(desc = "The pattern of blocks to set") Pattern pattern, - @Arg(desc = "Expression to test block placement locations and set block type") - String expression, + @Arg(desc = "Expression to test block placement locations and set block type", variable = true) + List expression, @Switch(name = 'h', desc = "Generate a hollow shape") boolean hollow, @Switch(name = 'r', desc = "Use the game's coordinate origin") @@ -312,7 +312,7 @@ public int generate(Player player, LocalSession session, EditSession editSession } try { - final int affected = editSession.makeShape(region, zero, unit, pattern, expression, hollow, session.getTimeout()); + final int affected = editSession.makeShape(region, zero, unit, pattern, String.join(" ", expression), hollow, session.getTimeout()); player.findFreePosition(); player.print(affected + " block(s) have been created."); return affected; @@ -334,8 +334,8 @@ public int generateBiome(Player player, LocalSession session, EditSession editSe @Selection Region region, @Arg(desc = "The biome type to set") BiomeType target, - @Arg(desc = "Expression to test block placement locations and set biome type") - String expression, + @Arg(desc = "Expression to test block placement locations and set biome type", variable = true) + List expression, @Switch(name = 'h', desc = "Generate a hollow shape") boolean hollow, @Switch(name = 'r', desc = "Use the game's coordinate origin") @@ -372,7 +372,7 @@ public int generateBiome(Player player, LocalSession session, EditSession editSe } try { - final int affected = editSession.makeBiomeShape(region, zero, unit, target, expression, hollow, session.getTimeout()); + final int affected = editSession.makeBiomeShape(region, zero, unit, target, String.join(" ", expression), hollow, session.getTimeout()); player.findFreePosition(); player.print("" + affected + " columns affected."); return affected; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index b016128e8..a8591e1de 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -382,8 +382,8 @@ public void regenerateChunk(Player player, LocalSession session, EditSession edi @Logging(ALL) public int deform(Player player, LocalSession session, EditSession editSession, @Selection Region region, - @Arg(desc = "The expression to use") - String expression, + @Arg(desc = "The expression to use", variable = true) + List expression, @Switch(name = 'r', desc = "Use the game's coordinate origin") boolean useRawCoords, @Switch(name = 'o', desc = "Use the selection's center as origin") @@ -410,7 +410,7 @@ public int deform(Player player, LocalSession session, EditSession editSession, } try { - final int affected = editSession.deformRegion(region, zero, unit, expression, session.getTimeout()); + final int affected = editSession.deformRegion(region, zero, unit, String.join(" ", expression), session.getTimeout()); player.findFreePosition(); player.print(affected + " block(s) have been deformed."); return affected; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index da09cc5b3..0bdcf7425 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -492,10 +492,10 @@ private int killMatchingEntities(Integer radius, Player player, Supplier input) { try { - Expression expression = Expression.compile(input); + Expression expression = Expression.compile(String.join(" ", input)); double result = expression.evaluate( new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout()); String formatted = formatter.format(result); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index bfc362a6d..be9a03500 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -89,12 +89,12 @@ import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.util.command.CommandArgParser; import com.sk89q.worldedit.util.command.CommandRegistrationHandler; import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.logging.DynamicStreamHandler; import com.sk89q.worldedit.util.logging.LogFormat; @@ -439,12 +439,16 @@ public String[] commandDetection(String[] split) { return split; } + private String[] parseArgs(String input) { + return new CommandArgParser(input).parseArgs().toArray(String[]::new); + } + @Subscribe public void handleCommand(CommandEvent event) { Request.reset(); Actor actor = platformManager.createProxyActor(event.getActor()); - String[] split = commandDetection(event.getArguments().substring(1).split(" ")); + String[] split = commandDetection(parseArgs(event.getArguments().substring(1))); // No command found! if (!commandManager.containsCommand(split[0])) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java new file mode 100644 index 000000000..293664a07 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java @@ -0,0 +1,85 @@ +package com.sk89q.worldedit.util.command; + +import java.util.stream.Stream; + +public class CommandArgParser { + + private enum State { + NORMAL, + QUOTE + } + + private final Stream.Builder args = Stream.builder(); + private final StringBuilder currentArg = new StringBuilder(); + private final String input; + private int index = 0; + private State state = State.NORMAL; + + public CommandArgParser(String input) { + this.input = input; + } + + public Stream parseArgs() { + for (; index < input.length(); index++) { + char c = input.charAt(index); + switch (state) { + case NORMAL: + handleNormal(c); + break; + case QUOTE: + handleQuote(c); + } + } + finishArg(true); + return args.build(); + } + + private void handleNormal(char c) { + switch (c) { + case '"': + state = State.QUOTE; + break; + case ' ': + finishArg(true); + break; + case '\\': + if (index + 1 < input.length()) { + index++; + } + appendChar(input.charAt(index)); + break; + default: + appendChar(c); + } + } + + private void handleQuote(char c) { + switch (c) { + case '"': + state = State.NORMAL; + finishArg(false); + break; + case '\\': + if (index + 1 < input.length()) { + index++; + } + appendChar(input.charAt(index)); + break; + default: + appendChar(c); + } + } + + private void finishArg(boolean requireText) { + if (currentArg.length() == 0 && requireText) { + return; + } + args.add(currentArg.toString()); + currentArg.setLength(0); + } + + private void appendChar(char c) { + currentArg.append(c); + } + +}