From f4bb5272e1eac090fb264ecbeb807ac73d9f2832 Mon Sep 17 00:00:00 2001 From: Albert Pham Date: Tue, 27 Oct 2015 13:51:45 -0700 Subject: [PATCH] Update new commands with suggestion and help support. --- config/checkstyle/import-control.xml | 3 +- .../argument/BooleanFlag.java} | 43 ++++--- .../DeformArg.java} | 28 +++-- .../ItemArg.java} | 32 ++++- .../ItemUserArg.java} | 22 +++- .../worldedit/command/argument/NumberArg.java | 83 +++++++++++++ .../PatternArg.java} | 28 ++++- .../command/argument/PointGeneratorArg.java | 40 +++++++ .../command/argument/RegionFactoryArg.java | 78 ++++++++++++ .../RegionReplaceArg.java} | 44 ++++--- .../worldedit/command/argument/StringArg.java | 78 ++++++++++++ .../TreeGeneratorArg.java} | 61 ++++++++-- .../brush => composition}/ApplyCommand.java | 32 ++++- .../composition/RegionFactoryCommand.java | 48 -------- ...hCommand.java => ReplaceBrushCommand.java} | 28 +++-- .../command/composition/ScatterCommand.java | 25 +++- .../composition/ShapedBrushCommand.java | 44 +++---- .../extension/platform/CommandManager.java | 17 +-- .../sk89q/worldedit/util/TreeGenerator.java | 15 +++ .../util/command/SimpleDescription.java | 3 +- .../command/argument/ArgumentException.java} | 20 +++- .../argument/ArgumentParseException.java | 39 ++++++ .../util/command/argument/ArgumentUtils.java | 45 +++++++ .../util/command/argument/CommandArgs.java | 89 ++++++++------ .../argument/MissingArgumentException.java | 39 ++++++ .../argument/UnusedArgumentsException.java | 39 ++++++ .../command/composition/BranchingCommand.java | 111 ++++++++++++++++++ .../command/composition/CommandExecutor.java} | 22 ++-- .../composition/LegacyCommandAdapter.java | 79 +++++++++++++ .../command/composition/ParameterCommand.java | 63 ++++++++++ .../command/composition/SimpleCommand.java | 49 ++++++++ .../sk89q/worldedit/forge/CommandWrapper.java | 18 ++- 32 files changed, 1150 insertions(+), 215 deletions(-) rename worldedit-core/src/main/java/com/sk89q/worldedit/{util/command/CommandExecutor.java => command/argument/BooleanFlag.java} (60%) rename worldedit-core/src/main/java/com/sk89q/worldedit/command/{composition/DeformCommand.java => argument/DeformArg.java} (68%) rename worldedit-core/src/main/java/com/sk89q/worldedit/command/{composition/ItemCommand.java => argument/ItemArg.java} (72%) rename worldedit-core/src/main/java/com/sk89q/worldedit/command/{composition/ItemUseCommand.java => argument/ItemUserArg.java} (81%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberArg.java rename worldedit-core/src/main/java/com/sk89q/worldedit/command/{composition/PatternCommand.java => argument/PatternArg.java} (76%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PointGeneratorArg.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryArg.java rename worldedit-core/src/main/java/com/sk89q/worldedit/command/{composition/PointGeneratorCommand.java => argument/RegionReplaceArg.java} (51%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/StringArg.java rename worldedit-core/src/main/java/com/sk89q/worldedit/command/{composition/TreeGeneratorCommand.java => argument/TreeGeneratorArg.java} (52%) rename worldedit-core/src/main/java/com/sk89q/worldedit/command/{tool/brush => composition}/ApplyCommand.java (63%) delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/RegionFactoryCommand.java rename worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/{FillBrushCommand.java => ReplaceBrushCommand.java} (70%) rename worldedit-core/src/main/java/com/sk89q/worldedit/{command/composition/ForestCommand.java => util/command/argument/ArgumentException.java} (67%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentParseException.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/MissingArgumentException.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/UnusedArgumentsException.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/BranchingCommand.java rename worldedit-core/src/main/java/com/sk89q/worldedit/{command/composition/RegionReplaceCommand.java => util/command/composition/CommandExecutor.java} (67%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/LegacyCommandAdapter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/ParameterCommand.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/SimpleCommand.java diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 6d581e702..7a5600470 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -51,8 +51,9 @@ + - \ No newline at end of file + diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandExecutor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanFlag.java similarity index 60% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandExecutor.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanFlag.java index f943a15b0..be96c0210 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandExecutor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanFlag.java @@ -17,40 +17,49 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.util.command; +package com.sk89q.worldedit.command.argument; import com.google.common.collect.Lists; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandLocals; import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.composition.CommandExecutor; import java.util.List; -public abstract class CommandExecutor implements CommandCallable { +public class BooleanFlag implements CommandExecutor { - @Override - public final T call(String arguments, CommandLocals locals, String[] parentCommands) throws CommandException { - CommandArgs args = new CommandArgs.Parser().parse(arguments); - T ret = call(args, locals, parentCommands); - args.requireAllConsumed(); - return ret; + private final char flag; + private final String description; + + public BooleanFlag(char flag, String description) { + this.flag = flag; + this.description = description; } - public abstract T call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException; + @Override + public Boolean call(CommandArgs args, CommandLocals locals) throws CommandException { + return args.containsFlag(flag); + } @Override - public Description getDescription() { - return new SimpleDescription(); + public List getSuggestions(CommandArgs args, CommandLocals locals) { + return Lists.newArrayList("-" + flag); + } + + @Override + public String getUsage() { + return "[-" + flag + "]"; + } + + @Override + public String getDescription() { + return description; } @Override public boolean testPermission(CommandLocals locals) { - return false; - } - - @Override - public List getSuggestions(String arguments, CommandLocals locals) throws CommandException { - return Lists.newArrayList(); + return true; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/DeformCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DeformArg.java similarity index 68% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/DeformCommand.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DeformArg.java index daa6d7417..6c684f908 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/DeformCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DeformArg.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.command.composition; +package com.sk89q.worldedit.command.argument; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandLocals; @@ -29,16 +29,20 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.factory.Deform; import com.sk89q.worldedit.function.factory.Deform.Mode; -import com.sk89q.worldedit.util.command.CommandExecutor; import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.composition.SimpleCommand; -public class DeformCommand extends CommandExecutor { +public class DeformArg extends SimpleCommand { + + private final BooleanFlag rawCoordsFlag = addParameter(new BooleanFlag('r', "Raw coords mode")); + private final BooleanFlag offsetFlag = addParameter(new BooleanFlag('o', "Offset mode")); + private final StringArg expressionParser = addParameter(new StringArg("expression", "Expression to apply")); @Override - public Deform call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException { - String expression = args.next(); - boolean rawCoords = args.containsFlag('r'); - boolean offset = args.containsFlag('o'); + public Deform call(CommandArgs args, CommandLocals locals) throws CommandException { + String expression = expressionParser.call(args, locals); + boolean rawCoords = rawCoordsFlag.call(args, locals); + boolean offset = offsetFlag.call(args, locals); Deform deform = new Deform(expression); @@ -60,4 +64,14 @@ public class DeformCommand extends CommandExecutor { return deform; } + @Override + public String getDescription() { + return "Deforms an area by applying a math expression"; + } + + @Override + protected boolean testPermission0(CommandLocals locals) { + return true; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ItemCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemArg.java similarity index 72% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ItemCommand.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemArg.java index 4335ec94f..e6eb8d1ed 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ItemCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemArg.java @@ -17,27 +17,39 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.command.composition; +package com.sk89q.worldedit.command.argument; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandLocals; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.util.command.composition.SimpleCommand; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.util.command.CommandExecutor; import com.sk89q.worldedit.util.command.argument.CommandArgs; import com.sk89q.worldedit.world.World; -public class ItemCommand extends CommandExecutor { +public class ItemArg extends SimpleCommand { + + private final StringArg stringArg; + + public ItemArg(String name) { + stringArg = addParameter(new StringArg(name, "The item name", null)); + } + + public ItemArg(String name, String defaultSuggestion) { + stringArg = addParameter(new StringArg(name, "The item name", defaultSuggestion)); + } @Override - public BaseItem call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException { + public BaseItem call(CommandArgs args, CommandLocals locals) throws CommandException { + String itemString = stringArg.call(args, locals); + Actor actor = locals.get(Actor.class); LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor); @@ -52,7 +64,7 @@ public class ItemCommand extends CommandExecutor { parserContext.setSession(session); try { - return WorldEdit.getInstance().getItemFactory().parseFromInput(args.next(), parserContext); + return WorldEdit.getInstance().getItemFactory().parseFromInput(itemString, parserContext); } catch (NoMatchException e) { throw new CommandException(e.getMessage(), e); } catch (InputParseException e) { @@ -60,4 +72,14 @@ public class ItemCommand extends CommandExecutor { } } + @Override + public String getDescription() { + return "Match an item"; + } + + @Override + protected boolean testPermission0(CommandLocals locals) { + return true; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ItemUseCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemUserArg.java similarity index 81% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ItemUseCommand.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemUserArg.java index 1c0558bb1..252838b91 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ItemUseCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemUserArg.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.command.composition; +package com.sk89q.worldedit.command.argument; import com.google.common.base.Function; import com.sk89q.minecraft.util.commands.CommandException; @@ -29,20 +29,32 @@ import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.function.EditContext; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.util.Direction; -import com.sk89q.worldedit.util.command.CommandExecutor; import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.composition.SimpleCommand; import com.sk89q.worldedit.world.World; import javax.annotation.Nullable; -public class ItemUseCommand extends CommandExecutor> { +public class ItemUserArg extends SimpleCommand> { + + private final ItemArg itemArg = addParameter(new ItemArg("item", "minecraft:dye:15")); @Override - public Function call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException { - BaseItem item = new ItemCommand().call(args, locals, parentCommands); + public Function call(CommandArgs args, CommandLocals locals) throws CommandException { + BaseItem item = itemArg.call(args, locals); return new ItemUseFactory(item); } + @Override + public String getDescription() { + return "Applies an item"; + } + + @Override + protected boolean testPermission0(CommandLocals locals) { + return true; + } + private static final class ItemUseFactory implements Function { private final BaseItem item; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberArg.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberArg.java new file mode 100644 index 000000000..54ccb7bc5 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberArg.java @@ -0,0 +1,83 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.collect.Lists; +import com.sk89q.minecraft.util.commands.CommandException; +import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.argument.MissingArgumentException; +import com.sk89q.worldedit.util.command.composition.CommandExecutor; + +import java.util.Collections; +import java.util.List; + +public class NumberArg implements CommandExecutor { + + private final String name; + private final String description; + private final String defaultSuggestion; + + public NumberArg(String name, String description) { + this(name, description, null); + } + + public NumberArg(String name, String description, String defaultSuggestion) { + this.name = name; + this.description = description; + this.defaultSuggestion = defaultSuggestion; + } + + @Override + public Number call(CommandArgs args, CommandLocals locals) throws CommandException { + try { + String next = args.next(); + try { + return Double.parseDouble(next); + } catch (NumberFormatException ignored) { + throw new CommandException("The value for <" + name + "> should be a number. '" + next + "' is not a number."); + } + } catch (MissingArgumentException e) { + throw new CommandException("Missing value for <" + name + "> (try a number)."); + } + } + + @Override + public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { + String value = args.next(); + return value.isEmpty() && defaultSuggestion != null ? Lists.newArrayList(defaultSuggestion) : Collections.emptyList(); + } + + @Override + public String getUsage() { + return "<" + name + ">"; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public boolean testPermission(CommandLocals locals) { + return true; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/PatternCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternArg.java similarity index 76% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/PatternCommand.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternArg.java index 258dd5f09..ac4f57d79 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/PatternCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternArg.java @@ -17,12 +17,13 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.command.composition; +package com.sk89q.worldedit.command.argument; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandLocals; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.util.command.composition.SimpleCommand; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; @@ -30,14 +31,21 @@ import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.util.command.CommandExecutor; import com.sk89q.worldedit.util.command.argument.CommandArgs; import com.sk89q.worldedit.world.World; -public class PatternCommand extends CommandExecutor { +public class PatternArg extends SimpleCommand { + + private final StringArg stringArg; + + public PatternArg(String name) { + stringArg = addParameter(new StringArg(name, "The pattern")); + } @Override - public Pattern call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException { + public Pattern call(CommandArgs args, CommandLocals locals) throws CommandException { + String patternString = stringArg.call(args, locals); + Actor actor = locals.get(Actor.class); LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor); @@ -52,7 +60,7 @@ public class PatternCommand extends CommandExecutor { parserContext.setSession(session); try { - return WorldEdit.getInstance().getPatternFactory().parseFromInput(args.next(), parserContext); + return WorldEdit.getInstance().getPatternFactory().parseFromInput(patternString, parserContext); } catch (NoMatchException e) { throw new CommandException(e.getMessage(), e); } catch (InputParseException e) { @@ -60,4 +68,14 @@ public class PatternCommand extends CommandExecutor { } } + @Override + public String getDescription() { + return "Choose a pattern"; + } + + @Override + public boolean testPermission0(CommandLocals locals) { + return true; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PointGeneratorArg.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PointGeneratorArg.java new file mode 100644 index 000000000..f7057595b --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PointGeneratorArg.java @@ -0,0 +1,40 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.base.Function; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.util.command.composition.BranchingCommand; + +public class PointGeneratorArg extends BranchingCommand> { + + public PointGeneratorArg() { + super("generatorType"); + putOption(new TreeGeneratorArg("treeType"), "tree", "forest"); + putOption(new ItemUserArg(), "item", "itemstack", "use"); + } + + @Override + public String getDescription() { + return "Choose a point generator function"; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryArg.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryArg.java new file mode 100644 index 000000000..3b73142cf --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryArg.java @@ -0,0 +1,78 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.collect.Lists; +import com.sk89q.minecraft.util.commands.CommandException; +import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.regions.factory.CuboidRegionFactory; +import com.sk89q.worldedit.regions.factory.CylinderRegionFactory; +import com.sk89q.worldedit.regions.factory.RegionFactory; +import com.sk89q.worldedit.regions.factory.SphereRegionFactory; +import com.sk89q.worldedit.util.command.argument.ArgumentUtils; +import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.argument.MissingArgumentException; +import com.sk89q.worldedit.util.command.composition.CommandExecutor; + +import java.util.List; + +public class RegionFactoryArg implements CommandExecutor { + + @Override + public RegionFactory call(CommandArgs args, CommandLocals locals) throws CommandException { + try { + String type = args.next(); + + if (type.equals("cuboid")) { + return new CuboidRegionFactory(); + } else if (type.equals("sphere")) { + return new SphereRegionFactory(); + } else if (type.equals("cyl") || type.equals("cylinder")) { + return new CylinderRegionFactory(1); // TODO: Adjustable height + } else { + throw new CommandException("Unknown shape type: " + type + " (try one of " + getUsage() + ")"); + } + } catch (MissingArgumentException e) { + throw new CommandException("Missing shape type (try one of " + getUsage() + ")"); + + } + } + + @Override + public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { + return ArgumentUtils.getMatchingSuggestions(Lists.newArrayList("cuboid", "sphere", "cyl"), args.next()); + } + + @Override + public String getUsage() { + return "(cuboid | sphere | cyl)"; + } + + @Override + public String getDescription() { + return "Defines a region"; + } + + @Override + public boolean testPermission(CommandLocals locals) { + return true; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/PointGeneratorCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionReplaceArg.java similarity index 51% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/PointGeneratorCommand.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionReplaceArg.java index d618db25d..793e0d8ba 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/PointGeneratorCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionReplaceArg.java @@ -17,29 +17,43 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.command.composition; +package com.sk89q.worldedit.command.argument; -import com.google.common.base.Function; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.function.EditContext; -import com.sk89q.worldedit.function.RegionFunction; -import com.sk89q.worldedit.util.command.CommandExecutor; +import com.sk89q.worldedit.function.factory.RegionReplace; +import com.sk89q.worldedit.util.command.argument.MissingArgumentException; +import com.sk89q.worldedit.util.command.composition.CommandExecutor; import com.sk89q.worldedit.util.command.argument.CommandArgs; -public class PointGeneratorCommand extends CommandExecutor> { +import java.util.Collections; +import java.util.List; + +public class RegionReplaceArg implements CommandExecutor { @Override - public Function call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException { - String type = args.next(); + public RegionReplace call(CommandArgs args, CommandLocals locals) throws CommandException { + return new RegionReplace(); + } - if (type.equalsIgnoreCase("forest") || type.equalsIgnoreCase("tree")) { - return new TreeGeneratorCommand().call(args, locals, parentCommands); - } else if (type.equalsIgnoreCase("item") || type.equalsIgnoreCase("itemstack")) { - return new ItemUseCommand().call(args, locals, parentCommands); - } else { - throw new CommandException("Unknown type of generator: " + type); - } + @Override + public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { + return Collections.emptyList(); + } + + @Override + public String getUsage() { + return ""; + } + + @Override + public String getDescription() { + return "Replaces a region"; + } + + @Override + public boolean testPermission(CommandLocals locals) { + return true; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/StringArg.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/StringArg.java new file mode 100644 index 000000000..5f76f5bb2 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/StringArg.java @@ -0,0 +1,78 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.command.argument; + +import com.google.common.collect.Lists; +import com.sk89q.minecraft.util.commands.CommandException; +import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.argument.MissingArgumentException; +import com.sk89q.worldedit.util.command.composition.CommandExecutor; + +import java.util.Collections; +import java.util.List; + +public class StringArg implements CommandExecutor { + + private final String name; + private final String description; + private final String defaultSuggestion; + + public StringArg(String name, String description) { + this(name, description, null); + } + + public StringArg(String name, String description, String defaultSuggestion) { + this.name = name; + this.description = description; + this.defaultSuggestion = defaultSuggestion; + } + + @Override + public String call(CommandArgs args, CommandLocals locals) throws CommandException { + try { + return args.next(); + } catch (MissingArgumentException e) { + throw new CommandException("Missing value for <" + name + ">."); + } + } + + @Override + public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { + String value = args.next(); + return value.isEmpty() && defaultSuggestion != null ? Lists.newArrayList(defaultSuggestion) : Collections.emptyList(); + } + + @Override + public String getUsage() { + return "<" + name + ">"; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public boolean testPermission(CommandLocals locals) { + return true; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/TreeGeneratorCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/TreeGeneratorArg.java similarity index 52% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/TreeGeneratorCommand.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/TreeGeneratorArg.java index e8e740076..091364d0a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/TreeGeneratorCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/TreeGeneratorArg.java @@ -17,9 +17,11 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.command.composition; +package com.sk89q.worldedit.command.argument; import com.google.common.base.Function; +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandLocals; import com.sk89q.worldedit.EditSession; @@ -27,25 +29,63 @@ import com.sk89q.worldedit.function.EditContext; import com.sk89q.worldedit.function.generator.ForestGenerator; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator.TreeType; -import com.sk89q.worldedit.util.command.CommandExecutor; +import com.sk89q.worldedit.util.command.argument.ArgumentUtils; import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.argument.MissingArgumentException; +import com.sk89q.worldedit.util.command.composition.CommandExecutor; import javax.annotation.Nullable; import java.util.Arrays; +import java.util.List; -public class TreeGeneratorCommand extends CommandExecutor> { +public class TreeGeneratorArg implements CommandExecutor> { + + private final String name; + + public TreeGeneratorArg(String name) { + this.name = name; + } + + private String getOptionsList() { + return Joiner.on(" | ").join(Arrays.asList(TreeType.values())); + } @Override - public Function call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException { - String input = args.next(); - TreeType type = TreeGenerator.lookup(input); - if (type != null) { - return new GeneratorFactory(type); - } else { - throw new CommandException(String.format("Can't recognize tree type '%s' -- choose from: %s", input, Arrays.toString(TreeType.values()))); + public Function call(CommandArgs args, CommandLocals locals) throws CommandException { + try { + String input = args.next(); + TreeType type = TreeGenerator.lookup(input); + if (type != null) { + return new GeneratorFactory(type); + } else { + throw new CommandException("Unknown value for <" + name + "> (try one of " + getOptionsList() + ")."); + } + } catch (MissingArgumentException e) { + throw new CommandException("Missing value for <" + name + "> (try one of " + getOptionsList() + ")."); } } + @Override + public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { + String s = args.next(); + return s.isEmpty() ? Lists.newArrayList(TreeType.getPrimaryAliases()) : ArgumentUtils.getMatchingSuggestions(TreeType.getAliases(), s); + } + + @Override + public String getUsage() { + return "<" + name + ">"; + } + + @Override + public String getDescription() { + return "Choose a tree generator"; + } + + @Override + public boolean testPermission(CommandLocals locals) { + return true; + } + private static class GeneratorFactory implements Function { private final TreeType type; @@ -64,4 +104,5 @@ public class TreeGeneratorCommand extends CommandExecutor. */ -package com.sk89q.worldedit.command.tool.brush; +package com.sk89q.worldedit.command.composition; import com.google.common.base.Function; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.command.composition.PointGeneratorCommand; +import com.sk89q.worldedit.command.argument.PointGeneratorArg; import com.sk89q.worldedit.function.EditContext; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.factory.RegionApply; -import com.sk89q.worldedit.util.command.CommandExecutor; import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.composition.ParameterCommand; -public class ApplyCommand extends CommandExecutor { +import java.util.Collections; +import java.util.List; + +public class ApplyCommand extends ParameterCommand { + + private final PointGeneratorArg pointGeneratorArg = addParameter(new PointGeneratorArg()); @Override - public RegionApply call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException { - Function function = new PointGeneratorCommand().call(args, locals, parentCommands); + public RegionApply call(CommandArgs args, CommandLocals locals) throws CommandException { + Function function = pointGeneratorArg.call(args, locals); return new RegionApply(function); } + @Override + public List getSuggestions(CommandArgs args, CommandLocals locals) { + return Collections.emptyList(); + } + + @Override + public String getDescription() { + return "Applies a point generator to an area"; + } + + @Override + protected boolean testPermission0(CommandLocals locals) { + return true; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/RegionFactoryCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/RegionFactoryCommand.java deleted file mode 100644 index 4b152d14e..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/RegionFactoryCommand.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.command.composition; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.regions.factory.CuboidRegionFactory; -import com.sk89q.worldedit.regions.factory.CylinderRegionFactory; -import com.sk89q.worldedit.regions.factory.RegionFactory; -import com.sk89q.worldedit.regions.factory.SphereRegionFactory; -import com.sk89q.worldedit.util.command.CommandExecutor; -import com.sk89q.worldedit.util.command.argument.CommandArgs; - -public class RegionFactoryCommand extends CommandExecutor { - - @Override - public RegionFactory call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException { - String type = args.next(); - - if (type.equals("cuboid")) { - return new CuboidRegionFactory(); - } else if (type.equals("sphere")) { - return new SphereRegionFactory(); - } else if (type.equals("cyl") || type.equals("cylinder")) { - return new CylinderRegionFactory(1); // TODO: Adjustable height - } else { - throw new CommandException("Unknown shape type: " + type); - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/FillBrushCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ReplaceBrushCommand.java similarity index 70% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/FillBrushCommand.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ReplaceBrushCommand.java index 276d7d30f..7a583da0a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/FillBrushCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ReplaceBrushCommand.java @@ -23,28 +23,31 @@ import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandLocals; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.argument.PatternArg; import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.command.tool.InvalidToolBindException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.util.command.CommandExecutor; +import com.sk89q.worldedit.util.command.composition.CommandExecutor; import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.composition.SimpleCommand; import static com.google.common.base.Preconditions.checkNotNull; -public class FillBrushCommand extends CommandExecutor { +public class ReplaceBrushCommand extends SimpleCommand { + private final PatternArg patternArg = addParameter(new PatternArg("fillPattern")); private final CommandExecutor delegate; - public FillBrushCommand(CommandExecutor delegate) { + public ReplaceBrushCommand(CommandExecutor delegate) { checkNotNull(delegate, "delegate"); - this.delegate = delegate; + this.delegate = addParameter(delegate); } @Override - public T call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException { - Pattern pattern = new PatternCommand().call(args, locals, parentCommands); + public T call(CommandArgs args, CommandLocals locals) throws CommandException { + Pattern pattern = patternArg.call(args, locals); Player player = (Player) locals.get(Actor.class); LocalSession session = WorldEdit.getInstance().getSessionManager().get(player); @@ -56,6 +59,17 @@ public class FillBrushCommand extends CommandExecutor { WorldEdit.getInstance().getPlatformManager().getCommandManager().getExceptionConverter().convert(e); } - return delegate.call(args, locals, parentCommands); + return delegate.call(args, locals); } + + @Override + public String getDescription() { + return "Replaces an area with a pattern"; + } + + @Override + protected boolean testPermission0(CommandLocals locals) { + return true; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ScatterCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ScatterCommand.java index 8dbc86483..a5667fe07 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ScatterCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ScatterCommand.java @@ -22,19 +22,34 @@ package com.sk89q.worldedit.command.composition; import com.google.common.base.Function; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.command.argument.NumberArg; +import com.sk89q.worldedit.command.argument.PointGeneratorArg; import com.sk89q.worldedit.function.EditContext; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.factory.Scatter; -import com.sk89q.worldedit.util.command.CommandExecutor; import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.composition.SimpleCommand; -public class ScatterCommand extends CommandExecutor { +public class ScatterCommand extends SimpleCommand { + + private final NumberArg densityCommand = addParameter(new NumberArg("density", "0-100", "20")); + private final PointGeneratorArg pointGeneratorArg = addParameter(new PointGeneratorArg()); @Override - public Scatter call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException { - double density = args.nextDouble() / 100.0; - Function function = new PointGeneratorCommand().call(args, locals, parentCommands); + public Scatter call(CommandArgs args, CommandLocals locals) throws CommandException { + double density = densityCommand.call(args, locals).doubleValue() / 100.0; + Function function = pointGeneratorArg.call(args, locals); return new Scatter(function, density); } + @Override + public String getDescription() { + return "Scatters a function over an area"; + } + + @Override + protected boolean testPermission0(CommandLocals locals) { + return true; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java index 62bb338bf..f99e4e543 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java @@ -19,13 +19,14 @@ package com.sk89q.worldedit.command.composition; -import com.google.common.collect.Lists; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandLocals; import com.sk89q.minecraft.util.commands.CommandPermissionsException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.MaxBrushRadiusException; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.argument.NumberArg; +import com.sk89q.worldedit.command.argument.RegionFactoryArg; import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.command.tool.InvalidToolBindException; import com.sk89q.worldedit.command.tool.brush.OperationFactoryBrush; @@ -33,39 +34,36 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.factory.OperationFactory; import com.sk89q.worldedit.regions.factory.RegionFactory; -import com.sk89q.worldedit.util.command.CommandExecutor; -import com.sk89q.worldedit.util.command.Description; -import com.sk89q.worldedit.util.command.Parameter; -import com.sk89q.worldedit.util.command.SimpleDescription; -import com.sk89q.worldedit.util.command.SimpleParameter; +import com.sk89q.worldedit.util.command.composition.CommandExecutor; import com.sk89q.worldedit.util.command.argument.CommandArgs; - -import java.util.List; +import com.sk89q.worldedit.util.command.composition.SimpleCommand; import static com.google.common.base.Preconditions.checkNotNull; -public class ShapedBrushCommand extends CommandExecutor { +public class ShapedBrushCommand extends SimpleCommand { private final CommandExecutor delegate; private final String permission; + private final RegionFactoryArg regionFactoryArg = addParameter(new RegionFactoryArg()); + private final NumberArg radiusCommand = addParameter(new NumberArg("size", "The size of the brush", "5")); + public ShapedBrushCommand(CommandExecutor delegate, String permission) { checkNotNull(delegate, "delegate"); this.permission = permission; this.delegate = delegate; + addParameter(delegate); } @Override - public Object call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException { + public Object call(CommandArgs args, CommandLocals locals) throws CommandException { if (!testPermission(locals)) { throw new CommandPermissionsException(); } - RegionFactory regionFactory = new RegionFactoryCommand().call(args, locals, parentCommands); - int radius = args.nextInt(); - OperationFactory factory = delegate.call(args, locals, parentCommands); - - args.requireAllConsumed(); + RegionFactory regionFactory = regionFactoryArg.call(args, locals); + int radius = radiusCommand.call(args, locals).intValue(); + OperationFactory factory = delegate.call(args, locals); Player player = (Player) locals.get(Actor.class); LocalSession session = WorldEdit.getInstance().getSessionManager().get(player); @@ -87,22 +85,12 @@ public class ShapedBrushCommand extends CommandExecutor { } @Override - public Description getDescription() { - List parameters = Lists.newArrayList(); - parameters.add(new SimpleParameter("radius")); - parameters.add(new SimpleParameter("shape")); - parameters.add(new SimpleParameter("...shapeArgs...").setOptional(true)); - parameters.add(new SimpleParameter("...brushArgs...").setOptional(true)); - - SimpleDescription desc = new SimpleDescription(); - desc.setDescription(delegate.getDescription().getDescription()); - desc.setHelp(delegate.getDescription().getHelp()); - desc.setPermissions(Lists.newArrayList(permission)); - return desc; + public String getDescription() { + return delegate.getDescription(); } @Override - public boolean testPermission(CommandLocals locals) { + public boolean testPermission0(CommandLocals locals) { Actor sender = locals.get(Actor.class); if (sender == null) { throw new RuntimeException("Uh oh! No 'Actor' specified so that we can check permissions"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java index 549f6b924..75f64cba9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java @@ -47,12 +47,12 @@ import com.sk89q.worldedit.command.ToolCommands; import com.sk89q.worldedit.command.ToolUtilCommands; import com.sk89q.worldedit.command.UtilityCommands; import com.sk89q.worldedit.command.WorldEditCommands; -import com.sk89q.worldedit.command.composition.DeformCommand; -import com.sk89q.worldedit.command.composition.FillBrushCommand; -import com.sk89q.worldedit.command.composition.RegionReplaceCommand; +import com.sk89q.worldedit.command.argument.DeformArg; +import com.sk89q.worldedit.command.composition.ReplaceBrushCommand; +import com.sk89q.worldedit.command.argument.RegionReplaceArg; import com.sk89q.worldedit.command.composition.ScatterCommand; import com.sk89q.worldedit.command.composition.ShapedBrushCommand; -import com.sk89q.worldedit.command.tool.brush.ApplyCommand; +import com.sk89q.worldedit.command.composition.ApplyCommand; import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.function.factory.OperationFactory; @@ -64,6 +64,7 @@ import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.InvalidUsageException; +import com.sk89q.worldedit.util.command.composition.LegacyCommandAdapter; import com.sk89q.worldedit.util.command.fluent.CommandGraph; import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.util.command.parametric.LegacyCommandsHandler; @@ -161,10 +162,10 @@ public final class CommandManager { .group("brush", "br") .describeAs("Brushing commands") .registerMethods(new BrushCommands(worldEdit)) - .register(new ShapedBrushCommand(new DeformCommand(), "worldedit.brush.deform"), "deform") - .register(new ShapedBrushCommand(new FillBrushCommand(new RegionReplaceCommand()), "worldedit.brush.set"), "set") - .register(new ShapedBrushCommand(new ScatterCommand(), "worldedit.brush.scatter"), "scatter") - .register(new ShapedBrushCommand(new ApplyCommand(), "worldedit.brush.apply"), "apply") + .register(new LegacyCommandAdapter(new ShapedBrushCommand(new DeformArg(), "worldedit.brush.deform")), "deform") + .register(new LegacyCommandAdapter(new ShapedBrushCommand(new ReplaceBrushCommand(new RegionReplaceArg()), "worldedit.brush.set")), "set") + .register(new LegacyCommandAdapter(new ShapedBrushCommand(new ScatterCommand(), "worldedit.brush.scatter")), "scatter") + .register(new LegacyCommandAdapter(new ShapedBrushCommand(new ApplyCommand(), "worldedit.brush.apply")), "apply") .parent() .group("superpickaxe", "pickaxe", "sp") .describeAs("Super-pickaxe commands") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java index ea5ce2e44..18c9b0702 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.util; +import com.google.common.collect.Sets; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; @@ -26,10 +27,12 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; import javax.annotation.Nullable; +import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import java.util.Random; +import java.util.Set; /** * Tree generator. @@ -105,6 +108,7 @@ public class TreeGenerator { * Stores a map of the names for fast access. */ private static final Map lookup = new HashMap(); + private static final Set primaryAliases = Sets.newHashSet(); private final String name; private final String[] lookupKeys; @@ -114,6 +118,9 @@ public class TreeGenerator { for (String key : type.lookupKeys) { lookup.put(key, type); } + if (type.lookupKeys.length > 0) { + primaryAliases.add(type.lookupKeys[0]); + } } } @@ -122,6 +129,14 @@ public class TreeGenerator { this.lookupKeys = lookupKeys; } + public static Set getAliases() { + return Collections.unmodifiableSet(lookup.keySet()); + } + + public static Set getPrimaryAliases() { + return Collections.unmodifiableSet(primaryAliases); + } + public boolean generate(EditSession editSession, Vector pos) throws MaxChangedBlocksException { return editSession.getWorld().generateTree(this, editSession, pos); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java index a789e68cf..ad3047117 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java @@ -102,8 +102,9 @@ public class SimpleDescription implements Description { * * @param usage usage string, or null */ - public void overrideUsage(String usage) { + public SimpleDescription overrideUsage(String usage) { this.overrideUsage = usage; + return this; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ForestCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentException.java similarity index 67% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ForestCommand.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentException.java index 09869e62a..37dc70f86 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ForestCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentException.java @@ -17,7 +17,23 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.command.composition; +package com.sk89q.worldedit.util.command.argument; + +public class ArgumentException extends Exception { + + public ArgumentException() { + } + + public ArgumentException(String message) { + super(message); + } + + public ArgumentException(String message, Throwable cause) { + super(message, cause); + } + + public ArgumentException(Throwable cause) { + super(cause); + } -public class ForestCommand { } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentParseException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentParseException.java new file mode 100644 index 000000000..fd2fc6f4f --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentParseException.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.command.argument; + +public class ArgumentParseException extends ArgumentException { + + public ArgumentParseException() { + } + + public ArgumentParseException(String message) { + super(message); + } + + public ArgumentParseException(String message, Throwable cause) { + super(message, cause); + } + + public ArgumentParseException(Throwable cause) { + super(cause); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java new file mode 100644 index 000000000..22141fedd --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java @@ -0,0 +1,45 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.command.argument; + +import com.google.common.collect.Lists; + +import java.util.Collection; +import java.util.List; + +public final class ArgumentUtils { + + private ArgumentUtils() { + } + + public static List getMatchingSuggestions(Collection items, String s) { + if (s.isEmpty()) { + return Lists.newArrayList(items); + } + List suggestions = Lists.newArrayList(); + for (String item : items) { + if (item.toLowerCase().startsWith(s)) { + suggestions.add(item); + } + } + return suggestions; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/CommandArgs.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/CommandArgs.java index 986a98c26..55537ec3f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/CommandArgs.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/CommandArgs.java @@ -46,23 +46,23 @@ public class CommandArgs { return position < arguments.size(); } - public String next() throws CommandException { + public String next() throws MissingArgumentException { try { return arguments.get(position++); } catch (IndexOutOfBoundsException ignored) { - throw new CommandException("Too few arguments specified."); + throw new MissingArgumentException("Too few arguments specified."); } } - public String peek() throws CommandException { + public String peek() throws MissingArgumentException { try { return arguments.get(position); } catch (IndexOutOfBoundsException ignored) { - throw new CommandException("Too few arguments specified."); + throw new MissingArgumentException("Too few arguments specified."); } } - public String remaining() throws CommandException { + public String remaining() throws MissingArgumentException { if (hasNext()) { StringBuilder builder = new StringBuilder(); boolean first = true; @@ -75,11 +75,11 @@ public class CommandArgs { } return builder.toString(); } else { - throw new CommandException("Too few arguments specified."); + throw new MissingArgumentException("Too few arguments specified."); } } - public String peekRemaining() throws CommandException { + public String peekRemaining() throws MissingArgumentException { if (hasNext()) { StringBuilder builder = new StringBuilder(); boolean first = true; @@ -92,7 +92,7 @@ public class CommandArgs { } return builder.toString(); } else { - throw new CommandException("Too few arguments specified."); + throw new MissingArgumentException(); } } @@ -131,7 +131,7 @@ public class CommandArgs { return flags; } - public void requireAllConsumed() throws CommandException { + public void requireAllConsumed() throws UnusedArgumentsException { StringBuilder builder = new StringBuilder(); boolean hasUnconsumed = false; @@ -149,67 +149,71 @@ public class CommandArgs { if (hasNext()) { hasUnconsumed = true; - builder.append(peekRemaining()); + try { + builder.append(peekRemaining()); + } catch (MissingArgumentException e) { + throw new RuntimeException("This should not have happened", e); + } } if (hasUnconsumed) { - throw new CommandException("There were unused arguments: " + builder); + throw new UnusedArgumentsException("There were unused arguments: " + builder); } } - public int nextInt() throws CommandException { + public int nextInt() throws ArgumentParseException, MissingArgumentException { String next = next(); try { return Integer.parseInt(next); } catch (NumberFormatException ignored) { - throw new CommandException("Expected a number, got '" + next + "'"); + throw new ArgumentParseException("Expected a number, got '" + next + "'"); } } - public short nextShort() throws CommandException { + public short nextShort() throws ArgumentParseException, MissingArgumentException { String next = next(); try { return Short.parseShort(next); } catch (NumberFormatException ignored) { - throw new CommandException("Expected a number, got '" + next + "'"); + throw new ArgumentParseException("Expected a number, got '" + next + "'"); } } - public byte nextByte() throws CommandException { + public byte nextByte() throws ArgumentParseException, MissingArgumentException { String next = next(); try { return Byte.parseByte(next); } catch (NumberFormatException ignored) { - throw new CommandException("Expected a number, got '" + next + "'"); + throw new ArgumentParseException("Expected a number, got '" + next + "'"); } } - public double nextDouble() throws CommandException { + public double nextDouble() throws ArgumentParseException, MissingArgumentException { String next = next(); try { return Double.parseDouble(next); } catch (NumberFormatException ignored) { - throw new CommandException("Expected a number, got '" + next + "'"); + throw new ArgumentParseException("Expected a number, got '" + next + "'"); } } - public float nextFloat() throws CommandException { + public float nextFloat() throws ArgumentParseException, MissingArgumentException { String next = next(); try { return Float.parseFloat(next); } catch (NumberFormatException ignored) { - throw new CommandException("Expected a number, got '" + next + "'"); + throw new ArgumentParseException("Expected a number, got '" + next + "'"); } } - public boolean nextBoolean() throws CommandException { + public boolean nextBoolean() throws ArgumentParseException, MissingArgumentException { String next = next(); if (next.equalsIgnoreCase("yes") || next.equalsIgnoreCase("true") || next.equalsIgnoreCase("y") || next.equalsIgnoreCase("1")) { return true; } else if (next.equalsIgnoreCase("no") || next.equalsIgnoreCase("false") || next.equalsIgnoreCase("n") || next.equalsIgnoreCase("0")) { return false; } else { - throw new CommandException("Expected a boolean (yes/no), got '" + next + "'"); + throw new ArgumentParseException("Expected a boolean (yes/no), got '" + next + "'"); } } @@ -235,64 +239,65 @@ public class CommandArgs { return fallback; } - public int getIntFlag(char c, int fallback) throws CommandException { + public int getIntFlag(char c, int fallback) throws ArgumentParseException { String next = getFlag(c, String.valueOf(fallback)); try { return Integer.parseInt(next); } catch (NumberFormatException ignored) { - throw new CommandException("Expected a number for flag '-" + c + "', got '" + next + "'"); + throw new ArgumentParseException("Expected a number for flag '-" + c + "', got '" + next + "'"); } } - public short getShortFlag(char c, short fallback) throws CommandException { + public short getShortFlag(char c, short fallback) throws ArgumentParseException { String next = getFlag(c, String.valueOf(fallback)); try { return Short.parseShort(next); } catch (NumberFormatException ignored) { - throw new CommandException("Expected a number for flag '-" + c + "', got '" + next + "'"); + throw new ArgumentParseException("Expected a number for flag '-" + c + "', got '" + next + "'"); } } - public byte getByteFlag(char c, byte fallback) throws CommandException { + public byte getByteFlag(char c, byte fallback) throws ArgumentParseException { String next = getFlag(c, String.valueOf(fallback)); try { return Byte.parseByte(next); } catch (NumberFormatException ignored) { - throw new CommandException("Expected a number for flag '-" + c + "', got '" + next + "'"); + throw new ArgumentParseException("Expected a number for flag '-" + c + "', got '" + next + "'"); } } - public double getDoubleFlag(char c, double fallback) throws CommandException { + public double getDoubleFlag(char c, double fallback) throws ArgumentParseException { String next = getFlag(c, String.valueOf(fallback)); try { return Double.parseDouble(next); } catch (NumberFormatException ignored) { - throw new CommandException("Expected a number for flag '-" + c + "', got '" + next + "'"); + throw new ArgumentParseException("Expected a number for flag '-" + c + "', got '" + next + "'"); } } - public float getFloatFlag(char c, float fallback) throws CommandException { + public float getFloatFlag(char c, float fallback) throws ArgumentParseException { String next = getFlag(c, String.valueOf(fallback)); try { return Float.parseFloat(next); } catch (NumberFormatException ignored) { - throw new CommandException("Expected a number for flag '-" + c + "', got '" + next + "'"); + throw new ArgumentParseException("Expected a number for flag '-" + c + "', got '" + next + "'"); } } - public boolean getBooleanFlag(char c, boolean fallback) throws CommandException { + public boolean getBooleanFlag(char c, boolean fallback) throws ArgumentParseException { String next = getFlag(c, String.valueOf(fallback)); if (next.equalsIgnoreCase("yes") || next.equalsIgnoreCase("true") || next.equalsIgnoreCase("y") || next.equalsIgnoreCase("1")) { return true; } else if (next.equalsIgnoreCase("no") || next.equalsIgnoreCase("false") || next.equalsIgnoreCase("n") || next.equalsIgnoreCase("0")) { return false; } else { - throw new CommandException("Expected a boolean (yes/no), got '" + next + "'"); + throw new ArgumentParseException("Expected a boolean (yes/no), got '" + next + "'"); } } public static class Parser { private boolean parseFlags = true; + private boolean usingHangingArguments = false; private Set valueFlags = Sets.newHashSet(); public boolean isParseFlags() { @@ -304,6 +309,15 @@ public class CommandArgs { return this; } + public boolean isUsingHangingArguments() { + return usingHangingArguments; + } + + public Parser setUsingHangingArguments(boolean usingHangingArguments) { + this.usingHangingArguments = usingHangingArguments; + return this; + } + public Set getValueFlags() { return valueFlags; } @@ -319,6 +333,11 @@ public class CommandArgs { for (int i = 0; i < context.argsLength(); i++) { args.add(context.getString(i)); } + if (isUsingHangingArguments()) { + if (arguments.isEmpty() || arguments.endsWith(" ")) { + args.add(""); + } + } Map flags = Maps.newHashMap(context.getValueFlags()); for (Character c : context.getFlags()) { flags.put(c, null); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/MissingArgumentException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/MissingArgumentException.java new file mode 100644 index 000000000..db0267727 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/MissingArgumentException.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.command.argument; + +public class MissingArgumentException extends ArgumentException { + + public MissingArgumentException() { + } + + public MissingArgumentException(String message) { + super(message); + } + + public MissingArgumentException(String message, Throwable cause) { + super(message, cause); + } + + public MissingArgumentException(Throwable cause) { + super(cause); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/UnusedArgumentsException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/UnusedArgumentsException.java new file mode 100644 index 000000000..efd7984e5 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/UnusedArgumentsException.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.command.argument; + +public class UnusedArgumentsException extends ArgumentException { + + public UnusedArgumentsException() { + } + + public UnusedArgumentsException(String message) { + super(message); + } + + public UnusedArgumentsException(String message, Throwable cause) { + super(message, cause); + } + + public UnusedArgumentsException(Throwable cause) { + super(cause); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/BranchingCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/BranchingCommand.java new file mode 100644 index 000000000..ce4ba58fe --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/BranchingCommand.java @@ -0,0 +1,111 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.command.composition; + +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.sk89q.minecraft.util.commands.CommandException; +import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.util.command.argument.ArgumentUtils; +import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.argument.MissingArgumentException; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public abstract class BranchingCommand implements CommandExecutor { + + private final String name; + private final Map> options = Maps.newHashMap(); + private final Set primaryAliases = Sets.newHashSet(); + + public BranchingCommand(String name) { + this.name = name; + } + + public void putOption(CommandExecutor executor, String primaryAlias, String... aliases) { + options.put(primaryAlias, executor); + primaryAliases.add(primaryAlias); + for (String alias : aliases) { + options.put(alias, executor); + } + } + + @Override + public T call(CommandArgs args, CommandLocals locals) throws CommandException { + try { + String classifier = args.next(); + CommandExecutor executor = options.get(classifier.toLowerCase()); + if (executor != null) { + return executor.call(args, locals); + } else { + throw new CommandException("'" + classifier + "' isn't a valid option for '" + name + "'. " + + "Try one of: " + Joiner.on(", ").join(primaryAliases)); + } + } catch (MissingArgumentException e) { + throw new CommandException("Missing value for <" + name + "> " + + "(try one of " + Joiner.on(" | ").join(primaryAliases) + ")."); + } + } + + @Override + public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { + String classifier = args.next(); + try { + CommandExecutor executor = options.get(classifier.toLowerCase()); + if (executor != null) { + return executor.getSuggestions(args, locals); + } + } catch (MissingArgumentException ignored) { + } + + return ArgumentUtils.getMatchingSuggestions((classifier.isEmpty() ? primaryAliases : options.keySet()), classifier); + } + + @Override + public String getUsage() { + List optionUsages = Lists.newArrayList(); + for (String alias : primaryAliases) { + CommandExecutor executor = options.get(alias); + String usage = executor.getUsage(); + if (usage.isEmpty()) { + optionUsages.add(alias); + } else { + optionUsages.add(alias + " " + executor.getUsage()); + } + } + + return "(" + Joiner.on(" | ").join(optionUsages) + ")"; + } + + @Override + public boolean testPermission(CommandLocals locals) { + for (CommandExecutor executor : options.values()) { + if (!executor.testPermission(locals)) { + return false; + } + } + return true; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/RegionReplaceCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/CommandExecutor.java similarity index 67% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/RegionReplaceCommand.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/CommandExecutor.java index cff0e9c8a..a9729884b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/RegionReplaceCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/CommandExecutor.java @@ -17,19 +17,25 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.command.composition; +package com.sk89q.worldedit.util.command.composition; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.function.factory.RegionReplace; -import com.sk89q.worldedit.util.command.CommandExecutor; import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.argument.MissingArgumentException; -public class RegionReplaceCommand extends CommandExecutor { +import java.util.List; - @Override - public RegionReplace call(CommandArgs args, CommandLocals locals, String[] parentCommands) throws CommandException { - return new RegionReplace(); - } +public interface CommandExecutor { + + T call(CommandArgs args, CommandLocals locals) throws CommandException; + + List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException; + + String getUsage(); + + String getDescription(); + + boolean testPermission(CommandLocals locals); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/LegacyCommandAdapter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/LegacyCommandAdapter.java new file mode 100644 index 000000000..e6c69fdeb --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/LegacyCommandAdapter.java @@ -0,0 +1,79 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.command.composition; + +import com.google.common.collect.Lists; +import com.sk89q.minecraft.util.commands.CommandException; +import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.util.command.CommandCallable; +import com.sk89q.worldedit.util.command.Description; +import com.sk89q.worldedit.util.command.SimpleDescription; +import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.argument.MissingArgumentException; +import com.sk89q.worldedit.util.command.argument.UnusedArgumentsException; + +import java.util.List; + +public class LegacyCommandAdapter implements CommandCallable { + + private final CommandExecutor executor; + + public LegacyCommandAdapter(CommandExecutor executor) { + this.executor = executor; + } + + @Override + public final Object call(String arguments, CommandLocals locals, String[] parentCommands) throws CommandException { + CommandArgs args = new CommandArgs.Parser().parse(arguments); + if (args.containsFlag('?')) { + throw new CommandException(executor.getUsage()); + } else { + Object ret = executor.call(args, locals); + try { + args.requireAllConsumed(); + } catch (UnusedArgumentsException e) { + throw new CommandException(e.getMessage()); + } + return ret; + } + } + + @Override + public Description getDescription() { + return new SimpleDescription() + .setDescription(executor.getDescription()) + .overrideUsage(executor.getUsage()); + } + + @Override + public boolean testPermission(CommandLocals locals) { + return executor.testPermission(locals); + } + + @Override + public List getSuggestions(String arguments, CommandLocals locals) throws CommandException { + CommandArgs args = new CommandArgs.Parser().setUsingHangingArguments(true).parse(arguments); + try { + return executor.getSuggestions(args, locals); + } catch (MissingArgumentException e) { + return Lists.newArrayList(); + } + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/ParameterCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/ParameterCommand.java new file mode 100644 index 000000000..542514ce1 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/ParameterCommand.java @@ -0,0 +1,63 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.command.composition; + +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; +import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.util.command.composition.CommandExecutor; + +import java.util.List; + +public abstract class ParameterCommand implements CommandExecutor { + + private final List> parameters = Lists.newArrayList(); + + protected List> getParameters() { + return parameters; + } + + public > T addParameter(T executor) { + parameters.add(executor); + return executor; + } + + @Override + public final String getUsage() { + List parts = Lists.newArrayList(); + for (CommandExecutor executor : parameters) { + parts.add(executor.getUsage()); + } + return Joiner.on(" ").join(parts); + } + + @Override + public final boolean testPermission(CommandLocals locals) { + for (CommandExecutor executor : parameters) { + if (!executor.testPermission(locals)) { + return false; + } + } + return testPermission0(locals); + } + + protected abstract boolean testPermission0(CommandLocals locals); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/SimpleCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/SimpleCommand.java new file mode 100644 index 000000000..003ee313a --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/SimpleCommand.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.command.composition; + +import com.google.common.collect.Lists; +import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.util.command.argument.CommandArgs; +import com.sk89q.worldedit.util.command.argument.MissingArgumentException; + +import java.util.List; + +public abstract class SimpleCommand extends ParameterCommand { + + @Override + public final List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { + List suggestions = Lists.newArrayList(); + boolean seenParameter = false; + for (CommandExecutor parameter : getParameters()) { + try { + suggestions = parameter.getSuggestions(args, locals); + seenParameter = true; + } catch (MissingArgumentException e) { + if (seenParameter) { + return suggestions; + } else { + throw e; + } + } + } + return suggestions; + } +} diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java index 1a725fad1..fb5c55550 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java @@ -19,10 +19,14 @@ package com.sk89q.worldedit.forge; +import com.google.common.base.Joiner; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.util.command.CommandMapping; import net.minecraft.command.CommandBase; import net.minecraft.command.ICommand; import net.minecraft.command.ICommandSender; +import net.minecraft.entity.player.EntityPlayerMP; import javax.annotation.Nullable; import java.util.Arrays; @@ -48,6 +52,17 @@ public class CommandWrapper extends CommandBase { @Override public void processCommand(ICommandSender var1, String[] var2) {} + @Override + public List addTabCompletionOptions(ICommandSender sender, String[] arguments) { + if (sender instanceof EntityPlayerMP) { + CommandSuggestionEvent event = new CommandSuggestionEvent(ForgeWorldEdit.inst.wrap((EntityPlayerMP) sender), command.getPrimaryAlias() + " " + Joiner.on(" ").join(arguments)); + WorldEdit.getInstance().getEventBus().post(event); + return event.getSuggestions(); + } else { + return super.addTabCompletionOptions(sender, arguments); + } + } + @Override public String getCommandUsage(ICommandSender icommandsender) { return "/" + command.getPrimaryAlias() + " " + command.getDescription().getUsage(); @@ -64,8 +79,7 @@ public class CommandWrapper extends CommandBase { } @Override - public int compareTo(@Nullable - Object o) { + public int compareTo(@Nullable Object o) { if (o == null) { return 0; } else if (o instanceof ICommand) {