/** * PermissionsEx * Copyright (C) zml and PermissionsEx contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ninja.leaping.permissionsex.util.command; import com.google.common.collect.ImmutableList; import ninja.leaping.permissionsex.util.Translatable; import ninja.leaping.permissionsex.util.command.args.ArgumentParseException; import ninja.leaping.permissionsex.util.command.args.CommandArgs; import ninja.leaping.permissionsex.util.command.args.CommandElement; import ninja.leaping.permissionsex.util.command.args.GenericArguments; import ninja.leaping.permissionsex.util.command.args.QuotedStringParser; import java.util.Collections; import java.util.List; import static ninja.leaping.permissionsex.util.Translations.t; /** * Specification for how command arguments should be parsed */ public class CommandSpec { private final CommandElement args; private final CommandExecutor executor; private final List<String> aliases; private final Translatable description; private final Translatable extendedDescription; private final String permission; private CommandSpec(CommandElement args, CommandExecutor executor, List<String> aliases, Translatable description, Translatable extendedDescription, String permission) { this.args = args; this.executor = executor; this.permission = permission; this.aliases = aliases; this.description = description; this.extendedDescription = extendedDescription; } public static Builder builder() { return new Builder(); } public static final class Builder { private CommandElement args = GenericArguments.none(); private List<String> aliases; private Translatable description, extendedDescription; private String permission; private CommandExecutor executor; private Builder() {} /** * Sets the aliases to use for this command. * The first of this list is considered the command's primary name * * @param aliases The aliases to set * @return this */ public Builder setAliases(String... aliases) { this.aliases = ImmutableList.copyOf(aliases); return this; } /** * Set the permission that will be checked before using this command. May be null. * * @param permission The permission to check * @return this */ public Builder setPermission(String permission) { this.permission = permission; return this; } /** * Set the callback that will handle this command's execution * * @param executor The executor that will be called with this command's parsed arguments * @return this */ public Builder setExecutor(CommandExecutor executor) { this.executor = executor; return this; } public Builder setChildren(CommandSpec... children) { final CommandElement usage = ChildCommands.args(children); setArguments(usage); setExecutor(ChildCommands.executor(usage)); return this; } /** * A short, one-line description of this command's purpose * * @param description The description to set * @return this */ public Builder setDescription(Translatable description) { this.description = description; return this; } /** * Sets an extended description to use in longer help listings for this command. * Will be appended to the short description and the command's usage. * Command flag descriptions are already included in this * * @param extendedDescription The description to set * @return this */ public Builder setExtendedDescription(Translatable extendedDescription) { this.extendedDescription = extendedDescription; return this; } /** * Set the argument specification for this command * * @see ninja.leaping.permissionsex.util.command.args.GenericArguments * @see ninja.leaping.permissionsex.util.command.args.GameArguments * @param args The arguments object to use * @return this */ public Builder setArguments(CommandElement args) { this.args = args; return this; } public CommandSpec build() { if (this.executor == null) { throw new IllegalArgumentException("An executor is required"); } if (this.aliases == null || this.aliases.isEmpty()) { throw new IllegalArgumentException("A command may not have no aliases"); } return new CommandSpec(args, executor, aliases, description, extendedDescription, permission); } } public <TextType> void process(Commander<TextType> commander, String arguments) { if (executor == null) { return; } try { checkPermission(commander); CommandContext args = parse(arguments); executor.execute(commander, args); } catch (CommandException ex) { commander.error(ex.getTranslatableMessage()); commander.error(t("Usage: %s", getUsage(commander))); } catch (Throwable t) { commander.error(t("Error occurred while executing command: %s", String.valueOf(t.getMessage()))); t.printStackTrace(); } } public <TextType> void checkPermission(Commander<TextType> commander) throws CommandException { if (this.permission != null && !commander.hasPermission(permission)) { throw new CommandException(t("You do not have permission to use this command!")); } } public CommandContext parse(String commandLine) throws ArgumentParseException { CommandArgs args = argsFor(commandLine, false); CommandContext context = new CommandContext(this, commandLine); parse(args, context); return context; } void parse(CommandArgs args, CommandContext context) throws ArgumentParseException { this.args.parse(args, context); if (args.hasNext()) { args.next(); throw args.createError(t("Too many arguments!")); } } public <TextType> List<String> tabComplete(Commander<TextType> src, String commandLine) { try { checkPermission(src); } catch (CommandException ex) { return Collections.emptyList(); } try { CommandArgs args = argsFor(commandLine, true); CommandContext context = new CommandContext(this, commandLine); return tabComplete(src, args, context); } catch (ArgumentParseException e) { src.debug(e.getTranslatableMessage()); return Collections.emptyList(); } } <TextType> List<String> tabComplete(Commander<TextType> src, CommandArgs args, CommandContext context) { return this.args.tabComplete(src, args, context); } /** * Get the active executor for this command. Generally not a good idea to call this directly, * unless you are handling arg parsing specially * * @return The active executor for this command */ public CommandExecutor getExecutor() { return executor; } private CommandArgs argsFor(String commandline, boolean lenient) throws ArgumentParseException { return QuotedStringParser.parseFrom(commandline, lenient); } public List<String> getAliases() { return this.aliases; } public <TextType> TextType getDescription(Commander<TextType> commander) { return this.description == null ? null : commander.fmt().tr(this.description); } public <TextType> TextType getUsage(Commander<TextType> commander) { return commander.fmt().combined("/", getAliases().get(0), " ", args.getUsage(commander)); } public <TextType> TextType getExtendedDescription(Commander<TextType> src) { TextType desc = getDescription(src); if (desc == null) { if (this.extendedDescription == null) { return getUsage(src); } else { return src.fmt().combined(getUsage(src), '\n', src.fmt().tr(this.extendedDescription)); } } else if (this.extendedDescription == null) { return src.fmt().combined(desc, '\n', getUsage(src)); } else { return src.fmt().combined(desc, '\n', getUsage(src), '\n', src.fmt().tr(this.extendedDescription)); } } }