core: Use the ArgumentDescription interface for descriptions

This allows minecraft-extras to provide an implementation that
uses Adventure chat components to represent the description.
This commit is contained in:
Zach Levis 2021-01-11 23:08:24 -08:00 committed by Alexander Söderberg
parent fa16fc8ef2
commit b38c725dc5
19 changed files with 903 additions and 94 deletions

View file

@ -23,9 +23,9 @@
//
package cloud.commandframework.annotations;
import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.Command;
import cloud.commandframework.CommandManager;
import cloud.commandframework.Description;
import cloud.commandframework.annotations.injection.ParameterInjectorRegistry;
import cloud.commandframework.annotations.injection.RawArgs;
import cloud.commandframework.annotations.parsers.MethodArgumentParser;
@ -434,7 +434,7 @@ public final class AnnotationParser<C> {
}
final String description = argumentDescriptions.getOrDefault(argument, "");
builder = builder.argument(argument, Description.of(description));
builder = builder.argument(argument, ArgumentDescription.of(description));
}
}
/* Try to find the command sender type */

View file

@ -23,8 +23,8 @@
//
package cloud.commandframework.annotations;
import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.CommandManager;
import cloud.commandframework.Description;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.flags.CommandFlag;
import cloud.commandframework.arguments.parser.ArgumentParser;
@ -60,7 +60,7 @@ final class FlagExtractor implements Function<@NonNull Method, Collection<@NonNu
final Flag flag = parameter.getAnnotation(Flag.class);
final CommandFlag.Builder<Void> builder = this.commandManager
.flagBuilder(flag.value())
.withDescription(Description.of(flag.description()))
.withDescription(ArgumentDescription.of(flag.description()))
.withAliases(flag.aliases());
if (parameter.getType().equals(boolean.class)) {
flags.add(builder.build());

View file

@ -0,0 +1,80 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework;
import cloud.commandframework.arguments.CommandArgument;
import org.checkerframework.checker.nullness.qual.NonNull;
import static java.util.Objects.requireNonNull;
/**
* A description for a {@link CommandArgument}
*
* @since 1.4.0
*/
public interface ArgumentDescription {
/**
* Get an empty command description.
*
* @return Command description
*/
@SuppressWarnings("deprecation")
static @NonNull ArgumentDescription empty() {
return Description.EMPTY;
}
/**
* Create a command description instance.
*
* @param string Command description
* @return Created command description
*/
@SuppressWarnings("deprecation")
static @NonNull ArgumentDescription of(final @NonNull String string) {
if (requireNonNull(string, "string").isEmpty()) {
return Description.EMPTY;
} else {
return new Description(string);
}
}
/**
* Get the plain-text description.
*
* @return Command description
*/
@NonNull String getDescription();
/**
* Get whether or not this description contains contents.
*
* @return if this description is empty or not
*/
default boolean isEmpty() {
return this.getDescription().isEmpty();
}
}

View file

@ -209,6 +209,7 @@ public class Command<C> {
// Converts a map of CommandArgument and Description pairs to a List of CommandComponent
// Used for backwards-compatibility
@SuppressWarnings("deprecation")
private static <C> @NonNull List<@NonNull CommandComponent<C>> mapToComponents(
final @NonNull Map<@NonNull CommandArgument<C, ?>, @NonNull Description> commandArguments
) {
@ -227,12 +228,35 @@ public class Command<C> {
* @param aliases Command aliases
* @param <C> Command sender type
* @return Command builder
* @deprecated for removal since 1.4.0. Use {@link #newBuilder(String, CommandMeta, ArgumentDescription, String...)} instead.
*/
@Deprecated
public static <C> @NonNull Builder<C> newBuilder(
final @NonNull String commandName,
final @NonNull CommandMeta commandMeta,
final @NonNull Description description,
final @NonNull String... aliases
) {
return newBuilder(commandName, commandMeta, (ArgumentDescription) description, aliases);
}
/**
* Create a new command builder. Is recommended to use the builder methods
* in {@link CommandManager} rather than invoking this method directly.
*
* @param commandName Base command argument
* @param commandMeta Command meta instance
* @param description Command description
* @param aliases Command aliases
* @param <C> Command sender type
* @return Command builder
* @since 1.4.0
*/
public static <C> @NonNull Builder<C> newBuilder(
final @NonNull String commandName,
final @NonNull CommandMeta commandMeta,
final @NonNull ArgumentDescription description,
final @NonNull String... aliases
) {
final List<CommandComponent<C>> commands = new ArrayList<>();
commands.add(CommandComponent.of(StaticArgument.of(commandName, aliases), description));
@ -263,7 +287,7 @@ public class Command<C> {
final @NonNull String... aliases
) {
final List<CommandComponent<C>> commands = new ArrayList<>();
commands.add(CommandComponent.of(StaticArgument.of(commandName, aliases), Description.empty()));
commands.add(CommandComponent.of(StaticArgument.of(commandName, aliases), ArgumentDescription.empty()));
return new Builder<>(
null,
commandMeta,
@ -343,7 +367,7 @@ public class Command<C> {
public @NonNull String getArgumentDescription(final @NonNull CommandArgument<C, ?> argument) {
for (final CommandComponent<C> component : this.components) {
if (component.getArgument().equals(argument)) {
return component.getDescription().getDescription();
return component.getArgumentDescription().getDescription();
}
}
throw new IllegalArgumentException("Command argument not found: " + argument);
@ -512,7 +536,9 @@ public class Command<C> {
* @param description Literal description
* @param aliases Argument aliases
* @return New builder instance with the modified command chain
* @deprecated for removal since 1.4.0. Use {@link #literal(String, ArgumentDescription, String...)} instead.
*/
@Deprecated
public @NonNull Builder<C> literal(
final @NonNull String main,
final @NonNull Description description,
@ -521,6 +547,23 @@ public class Command<C> {
return this.argument(StaticArgument.of(main, aliases), description);
}
/**
* Inserts a required {@link StaticArgument} into the command chain
*
* @param main Main argument name
* @param description Literal description
* @param aliases Argument aliases
* @return New builder instance with the modified command chain
* @since 1.4.0
*/
public @NonNull Builder<C> literal(
final @NonNull String main,
final @NonNull ArgumentDescription description,
final @NonNull String... aliases
) {
return this.argument(StaticArgument.of(main, aliases), description);
}
/**
* Add a new command argument with an empty description to the command
*
@ -530,7 +573,7 @@ public class Command<C> {
* @return New builder instance with the command argument inserted into the argument list
*/
public <T> @NonNull Builder<C> argument(final CommandArgument.@NonNull Builder<C, T> builder) {
return this.argument(builder.build(), Description.empty());
return this.argument(builder.build(), ArgumentDescription.empty());
}
/**
@ -541,7 +584,7 @@ public class Command<C> {
* @return New builder instance with the command argument inserted into the argument list
*/
public <T> @NonNull Builder<C> argument(final @NonNull CommandArgument<C, T> argument) {
return this.argument(argument, Description.empty());
return this.argument(argument, ArgumentDescription.empty());
}
/**
@ -551,10 +594,28 @@ public class Command<C> {
* @param description Argument description
* @param <T> Argument type
* @return New builder instance with the command argument inserted into the argument list
* @deprecated for removal since 1.4.0. Use {@link #argument(CommandArgument, ArgumentDescription)} instead.
*/
@Deprecated
public <T> @NonNull Builder<C> argument(
final @NonNull CommandArgument<C, T> argument,
final @NonNull Description description
) {
return this.argument(argument, (ArgumentDescription) description);
}
/**
* Add a new command argument to the command
*
* @param argument Argument to add
* @param description Argument description
* @param <T> Argument type
* @return New builder instance with the command argument inserted into the argument list
* @since 1.4.0
*/
public <T> @NonNull Builder<C> argument(
final @NonNull CommandArgument<C, T> argument,
final @NonNull ArgumentDescription description
) {
if (argument.isArgumentRegistered()) {
throw new IllegalArgumentException("The provided argument has already been associated with a command."
@ -582,10 +643,29 @@ public class Command<C> {
* @param description Argument description
* @param <T> Argument type
* @return New builder instance with the command argument inserted into the argument list
* @deprecated for removal since 1.4.0. Use {@link #argument(CommandArgument.Builder, ArgumentDescription)} instead.
*/
@Deprecated
public <T> @NonNull Builder<C> argument(
final CommandArgument.@NonNull Builder<C, T> builder,
final @NonNull Description description
) {
return this.argument(builder, (ArgumentDescription) description);
}
/**
* Add a new command argument to the command
*
* @param builder Argument to add. {@link CommandArgument.Builder#build()} will be invoked
* and the result will be registered in the command.
* @param description Argument description
* @param <T> Argument type
* @return New builder instance with the command argument inserted into the argument list
* @since 1.4.0
*/
public <T> @NonNull Builder<C> argument(
final CommandArgument.@NonNull Builder<C, T> builder,
final @NonNull ArgumentDescription description
) {
final List<CommandComponent<C>> commandComponents = new ArrayList<>(this.commandComponents);
commandComponents.add(CommandComponent.of(builder.build(), description));
@ -640,12 +720,41 @@ public class Command<C> {
* @param <U> First type
* @param <V> Second type
* @return Builder instance with the argument inserted
* @deprecated for removal since 1.4.0. Use {@link #argumentPair(String, Pair, Pair, ArgumentDescription)} instead.
*/
@Deprecated
public <U, V> @NonNull Builder<C> argumentPair(
final @NonNull String name,
final @NonNull Pair<@NonNull String, @NonNull String> names,
final @NonNull Pair<@NonNull Class<U>, @NonNull Class<V>> parserPair,
final @NonNull Description description
) {
return this.argumentPair(name, names, parserPair, (ArgumentDescription) description);
}
/**
* Create a new argument pair that maps to {@link Pair}
* <p>
* For this to work, there must be a {@link CommandManager}
* attached to the command builder. To guarantee this, it is recommended to get the command builder instance
* using {@link CommandManager#commandBuilder(String, String...)}
*
* @param name Name of the argument
* @param names Pair containing the names of the sub-arguments
* @param parserPair Pair containing the types of the sub-arguments. There must be parsers for these types registered
* in the {@link cloud.commandframework.arguments.parser.ParserRegistry} used by the
* {@link CommandManager} attached to this command
* @param description Description of the argument
* @param <U> First type
* @param <V> Second type
* @return Builder instance with the argument inserted
* @since 1.4.0
*/
public <U, V> @NonNull Builder<C> argumentPair(
final @NonNull String name,
final @NonNull Pair<@NonNull String, @NonNull String> names,
final @NonNull Pair<@NonNull Class<U>, @NonNull Class<V>> parserPair,
final @NonNull ArgumentDescription description
) {
if (this.commandManager == null) {
throw new IllegalStateException("This cannot be called from a command that has no command manager attached");
@ -672,7 +781,10 @@ public class Command<C> {
* @param <V> Second type
* @param <O> Output type
* @return Builder instance with the argument inserted
* @deprecated for removal since 1.4.0. Use
* {@link #argumentPair(String, TypeToken, Pair, Pair, BiFunction, ArgumentDescription)} instead.
*/
@Deprecated
public <U, V, O> @NonNull Builder<C> argumentPair(
final @NonNull String name,
final @NonNull TypeToken<O> outputType,
@ -680,6 +792,38 @@ public class Command<C> {
final @NonNull Pair<Class<U>, Class<V>> parserPair,
final @NonNull BiFunction<C, Pair<U, V>, O> mapper,
final @NonNull Description description
) {
return this.argumentPair(name, outputType, names, parserPair, mapper, (ArgumentDescription) description);
}
/**
* Create a new argument pair that maps to a custom type.
* <p>
* For this to work, there must be a {@link CommandManager}
* attached to the command builder. To guarantee this, it is recommended to get the command builder instance
* using {@link CommandManager#commandBuilder(String, String...)}
*
* @param name Name of the argument
* @param outputType The output type
* @param names Pair containing the names of the sub-arguments
* @param parserPair Pair containing the types of the sub-arguments. There must be parsers for these types registered
* in the {@link cloud.commandframework.arguments.parser.ParserRegistry} used by the
* {@link CommandManager} attached to this command
* @param mapper Mapper that maps from {@link Pair} to the custom type
* @param description Description of the argument
* @param <U> First type
* @param <V> Second type
* @param <O> Output type
* @return Builder instance with the argument inserted
* @since 1.4.0
*/
public <U, V, O> @NonNull Builder<C> argumentPair(
final @NonNull String name,
final @NonNull TypeToken<O> outputType,
final @NonNull Pair<String, String> names,
final @NonNull Pair<Class<U>, Class<V>> parserPair,
final @NonNull BiFunction<C, Pair<U, V>, O> mapper,
final @NonNull ArgumentDescription description
) {
if (this.commandManager == null) {
throw new IllegalStateException("This cannot be called from a command that has no command manager attached");
@ -707,12 +851,43 @@ public class Command<C> {
* @param <V> Second type
* @param <W> Third type
* @return Builder instance with the argument inserted
* @deprecated for removal since 1.4.0. Use {@link #argumentTriplet(String, Triplet, Triplet, ArgumentDescription)}
* instead.
*/
@Deprecated
public <U, V, W> @NonNull Builder<C> argumentTriplet(
final @NonNull String name,
final @NonNull Triplet<String, String, String> names,
final @NonNull Triplet<Class<U>, Class<V>, Class<W>> parserTriplet,
final @NonNull Description description
) {
return this.argumentTriplet(name, names, parserTriplet, (ArgumentDescription) description);
}
/**
* Create a new argument pair that maps to {@link cloud.commandframework.types.tuples.Triplet}
* <p>
* For this to work, there must be a {@link CommandManager}
* attached to the command builder. To guarantee this, it is recommended to get the command builder instance
* using {@link CommandManager#commandBuilder(String, String...)}
*
* @param name Name of the argument
* @param names Triplet containing the names of the sub-arguments
* @param parserTriplet Triplet containing the types of the sub-arguments. There must be parsers for these types
* registered in the {@link cloud.commandframework.arguments.parser.ParserRegistry}
* used by the {@link CommandManager} attached to this command
* @param description Description of the argument
* @param <U> First type
* @param <V> Second type
* @param <W> Third type
* @return Builder instance with the argument inserted
* @since 1.4.0
*/
public <U, V, W> @NonNull Builder<C> argumentTriplet(
final @NonNull String name,
final @NonNull Triplet<String, String, String> names,
final @NonNull Triplet<Class<U>, Class<V>, Class<W>> parserTriplet,
final @NonNull ArgumentDescription description
) {
if (this.commandManager == null) {
throw new IllegalStateException("This cannot be called from a command that has no command manager attached");
@ -740,15 +915,57 @@ public class Command<C> {
* @param <W> Third type
* @param <O> Output type
* @return Builder instance with the argument inserted
* @deprecated for removal since 1.4.0, use
* {@link #argumentTriplet(String, TypeToken, Triplet, Triplet, BiFunction, ArgumentDescription)} instead.
*/
@Deprecated
public <U, V, W, O> @NonNull Builder<C> argumentTriplet(
final @NonNull String name,
final @NonNull TypeToken<O> outputType,
final @NonNull Triplet<String, String, String> names,
final @NonNull Triplet<Class<U>, Class<V>, Class<W>> parserTriplet,
final @NonNull BiFunction<C, Triplet<U, V, W>, O> mapper,
final @NonNull Description description
) {
return this.argumentTriplet(
name,
outputType,
names,
parserTriplet,
mapper,
(ArgumentDescription) description
);
}
/**
* Create a new argument triplet that maps to a custom type.
* <p>
* For this to work, there must be a {@link CommandManager}
* attached to the command builder. To guarantee this, it is recommended to get the command builder instance
* using {@link CommandManager#commandBuilder(String, String...)}
*
* @param name Name of the argument
* @param outputType The output type
* @param names Triplet containing the names of the sub-arguments
* @param parserTriplet Triplet containing the types of the sub-arguments. There must be parsers for these types
* registered in the {@link cloud.commandframework.arguments.parser.ParserRegistry} used by
* the {@link CommandManager} attached to this command
* @param mapper Mapper that maps from {@link Triplet} to the custom type
* @param description Description of the argument
* @param <U> First type
* @param <V> Second type
* @param <W> Third type
* @param <O> Output type
* @return Builder instance with the argument inserted
* @since 1.4.0
*/
public <U, V, W, O> @NonNull Builder<C> argumentTriplet(
final @NonNull String name,
final @NonNull TypeToken<O> outputType,
final @NonNull Triplet<String, String, String> names,
final @NonNull Triplet<Class<U>, Class<V>,
Class<W>> parserTriplet,
final @NonNull Triplet<Class<U>, Class<V>, Class<W>> parserTriplet,
final @NonNull BiFunction<C, Triplet<U, V, W>, O> mapper,
final @NonNull Description description
final @NonNull ArgumentDescription description
) {
if (this.commandManager == null) {
throw new IllegalStateException("This cannot be called from a command that has no command manager attached");
@ -852,7 +1069,7 @@ public class Command<C> {
continue;
}
final CommandArgument<C, ?> builtArgument = argument.copy();
builder = builder.argument(builtArgument, component.getDescription());
builder = builder.argument(builtArgument, component.getArgumentDescription());
}
if (this.commandPermission.toString().isEmpty()) {
builder = builder.permission(command.getCommandPermission());
@ -910,9 +1127,9 @@ public class Command<C> {
public @NonNull Command<C> build() {
final List<CommandComponent<C>> commandComponents = new ArrayList<>(this.commandComponents);
/* Construct flag node */
if (!flags.isEmpty()) {
if (!this.flags.isEmpty()) {
final FlagArgument<C> flagArgument = new FlagArgument<>(this.flags);
commandComponents.add(CommandComponent.of(flagArgument, Description.of("Command flags")));
commandComponents.add(CommandComponent.of(flagArgument, ArgumentDescription.of("Command flags")));
}
return new Command<>(
Collections.unmodifiableList(commandComponents),

View file

@ -37,7 +37,7 @@ import java.util.Objects;
public final class CommandComponent<C> {
private final CommandArgument<C, ?> argument;
private final Description description;
private final ArgumentDescription description;
/**
* Initializes a new CommandComponent
@ -47,7 +47,7 @@ public final class CommandComponent<C> {
*/
private CommandComponent(
final @NonNull CommandArgument<C, ?> commandArgument,
final @NonNull Description commandDescription
final @NonNull ArgumentDescription commandDescription
) {
this.argument = commandArgument;
this.description = commandDescription;
@ -66,14 +66,30 @@ public final class CommandComponent<C> {
* Gets the command component description
*
* @return command component description
* @deprecated for removal since 1.4.0. Use {@link #getArgumentDescription()} instead.
*/
@Deprecated
public @NonNull Description getDescription() {
if (this.description instanceof Description) {
return (Description) this.description;
} else {
return new Description(this.description.getDescription());
}
}
/**
* Gets the command component description
*
* @return command component description
* @since 1.4.0
*/
public @NonNull ArgumentDescription getArgumentDescription() {
return this.description;
}
@Override
public int hashCode() {
return Objects.hash(getArgument(), getDescription());
return Objects.hash(this.getArgument(), this.getArgumentDescription());
}
@Override
@ -81,9 +97,9 @@ public final class CommandComponent<C> {
if (this == o) {
return true;
} else if (o instanceof CommandComponent) {
CommandComponent<?> that = (CommandComponent<?>) o;
return getArgument().equals(that.getArgument())
&& getDescription().equals(that.getDescription());
final CommandComponent<?> that = (CommandComponent<?>) o;
return this.getArgument().equals(that.getArgument())
&& this.getArgumentDescription().equals(that.getArgumentDescription());
} else {
return false;
}
@ -102,11 +118,28 @@ public final class CommandComponent<C> {
* @param commandArgument Command Component Argument
* @param commandDescription Command Component Description
* @return new CommandComponent
* @deprecated for removal since 1.4.0. Use {@link #of(CommandArgument, ArgumentDescription)} instead.
*/
@Deprecated
public static <C> @NonNull CommandComponent<C> of(
final @NonNull CommandArgument<C, ?> commandArgument,
final @NonNull Description commandDescription
) {
return new CommandComponent<C>(commandArgument, commandDescription);
}
/**
* Creates a new CommandComponent with the provided argument and description
*
* @param <C> Command sender type
* @param commandArgument Command Component Argument
* @param commandDescription Command Component Description
* @return new CommandComponent
*/
public static <C> @NonNull CommandComponent<C> of(
final @NonNull CommandArgument<C, ?> commandArgument,
final @NonNull ArgumentDescription commandDescription
) {
return new CommandComponent<C>(commandArgument, commandDescription);
}
}

View file

@ -353,12 +353,40 @@ public abstract class CommandManager<C> {
* @param description Description for the root literal
* @param meta Command meta
* @return Builder instance
* @deprecated for removal since 1.4.0. Use {@link #commandBuilder(String, Collection, Description, CommandMeta)} instead.
*/
@Deprecated
public Command.@NonNull Builder<C> commandBuilder(
final @NonNull String name,
final @NonNull Collection<String> aliases,
final @NonNull Description description,
final @NonNull CommandMeta meta
) {
return commandBuilder(name, aliases, (ArgumentDescription) description, meta);
}
/**
* Create a new command builder. This will also register the creating manager in the command
* builder using {@link Command.Builder#manager(CommandManager)}, so that the command
* builder is associated with the creating manager. This allows for parser inference based on
* the type, with the help of the {@link ParserRegistry parser registry}
* <p>
* This method will not register the command in the manager. To do that, {@link #command(Command.Builder)}
* or {@link #command(Command)} has to be invoked with either the {@link Command.Builder} instance, or the constructed
* {@link Command command} instance
*
* @param name Command name
* @param aliases Command aliases
* @param description Description for the root literal
* @param meta Command meta
* @return Builder instance
* @since 1.4.0
*/
public Command.@NonNull Builder<C> commandBuilder(
final @NonNull String name,
final @NonNull Collection<String> aliases,
final @NonNull ArgumentDescription description,
final @NonNull CommandMeta meta
) {
return Command.<C>newBuilder(
name,
@ -393,7 +421,7 @@ public abstract class CommandManager<C> {
return Command.<C>newBuilder(
name,
meta,
Description.empty(),
ArgumentDescription.empty(),
aliases.toArray(new String[0])
).manager(this);
}
@ -413,12 +441,41 @@ public abstract class CommandManager<C> {
* @param description Description for the root literal
* @param aliases Command aliases
* @return Builder instance
* @deprecated for removal since 1.4.0. Use {@link #commandBuilder(String, CommandMeta, ArgumentDescription, String...)}
* instead.
*/
@Deprecated
public Command.@NonNull Builder<C> commandBuilder(
final @NonNull String name,
final @NonNull CommandMeta meta,
final @NonNull Description description,
final @NonNull String... aliases
) {
return this.commandBuilder(name, meta, (ArgumentDescription) description, aliases);
}
/**
* Create a new command builder. This will also register the creating manager in the command
* builder using {@link Command.Builder#manager(CommandManager)}, so that the command
* builder is associated with the creating manager. This allows for parser inference based on
* the type, with the help of the {@link ParserRegistry parser registry}
* <p>
* This method will not register the command in the manager. To do that, {@link #command(Command.Builder)}
* or {@link #command(Command)} has to be invoked with either the {@link Command.Builder} instance, or the constructed
* {@link Command command} instance
*
* @param name Command name
* @param meta Command meta
* @param description Description for the root literal
* @param aliases Command aliases
* @return Builder instance
* @since 1.4.0
*/
public Command.@NonNull Builder<C> commandBuilder(
final @NonNull String name,
final @NonNull CommandMeta meta,
final @NonNull ArgumentDescription description,
final @NonNull String... aliases
) {
return Command.<C>newBuilder(
name,
@ -453,7 +510,7 @@ public abstract class CommandManager<C> {
return Command.<C>newBuilder(
name,
meta,
Description.empty(),
ArgumentDescription.empty(),
aliases
).manager(this);
}
@ -476,11 +533,41 @@ public abstract class CommandManager<C> {
* @return Builder instance
* @throws UnsupportedOperationException If the command manager does not support default command meta creation
* @see #createDefaultCommandMeta() Default command meta creation
* @deprecated for removal since 1.4.0. Use {@link #commandBuilder(String, ArgumentDescription, String...)} instead.
*/
@Deprecated
public Command.@NonNull Builder<C> commandBuilder(
final @NonNull String name,
final @NonNull Description description,
final @NonNull String... aliases
) {
return this.commandBuilder(name, (ArgumentDescription) description, aliases);
}
/**
* Create a new command builder using default command meta created by {@link #createDefaultCommandMeta()}.
* <p>
* This will also register the creating manager in the command
* builder using {@link Command.Builder#manager(CommandManager)}, so that the command
* builder is associated with the creating manager. This allows for parser inference based on
* the type, with the help of the {@link ParserRegistry parser registry}
* <p>
* This method will not register the command in the manager. To do that, {@link #command(Command.Builder)}
* or {@link #command(Command)} has to be invoked with either the {@link Command.Builder} instance, or the constructed
* {@link Command command} instance
*
* @param name Command name
* @param description Description for the root literal
* @param aliases Command aliases
* @return Builder instance
* @throws UnsupportedOperationException If the command manager does not support default command meta creation
* @see #createDefaultCommandMeta() Default command meta creation
* @since 1.4.0
*/
public Command.@NonNull Builder<C> commandBuilder(
final @NonNull String name,
final @NonNull ArgumentDescription description,
final @NonNull String... aliases
) {
return Command.<C>newBuilder(
name,
@ -516,7 +603,7 @@ public abstract class CommandManager<C> {
return Command.<C>newBuilder(
name,
this.createDefaultCommandMeta(),
Description.empty(),
ArgumentDescription.empty(),
aliases
).manager(this);
}

View file

@ -28,17 +28,20 @@ import org.checkerframework.checker.nullness.qual.NonNull;
/**
* {@link CommandArgument} description
*
* @deprecated to become package-private since 1.4.0. Use {@link ArgumentDescription} instead.
*/
public final class Description {
@Deprecated
public final class Description implements ArgumentDescription {
/**
* Empty command description
*/
private static final Description EMPTY = Description.of("");
static final Description EMPTY = new Description("");
private final String description;
private Description(final @NonNull String description) {
Description(final @NonNull String description) {
this.description = description;
}
@ -46,7 +49,9 @@ public final class Description {
* Get an empty command description
*
* @return Command description
* @deprecated for removal since 1.4.0. See {@link ArgumentDescription#empty()}
*/
@Deprecated
public static @NonNull Description empty() {
return EMPTY;
}
@ -56,7 +61,9 @@ public final class Description {
*
* @param string Command description
* @return Created command description
* @deprecated for removal since 1.4.0. See {@link ArgumentDescription#of(String)}
*/
@Deprecated
public static @NonNull Description of(final @NonNull String string) {
return new Description(string);
}
@ -66,6 +73,7 @@ public final class Description {
*
* @return Command description
*/
@Override
public @NonNull String getDescription() {
return this.description;
}

View file

@ -23,7 +23,7 @@
//
package cloud.commandframework.arguments.flags;
import cloud.commandframework.Description;
import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.arguments.CommandArgument;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@ -46,14 +46,14 @@ public final class CommandFlag<T> {
private final @NonNull String name;
private final @NonNull String @NonNull [] aliases;
private final @NonNull Description description;
private final @NonNull ArgumentDescription description;
private final @Nullable CommandArgument<?, T> commandArgument;
private CommandFlag(
final @NonNull String name,
final @NonNull String @NonNull [] aliases,
final @NonNull Description description,
final @NonNull ArgumentDescription description,
final @Nullable CommandArgument<?, T> commandArgument
) {
this.name = Objects.requireNonNull(name, "name cannot be null");
@ -95,8 +95,24 @@ public final class CommandFlag<T> {
* <p>
*
* @return Flag description
* @deprecated for removal since 1.4.0. Use {@link #getArgumentDescription()} instead.
*/
public @NonNull Description getDescription() {
@Deprecated
public cloud.commandframework.@NonNull Description getDescription() {
if (this.description instanceof cloud.commandframework.Description) {
return ((cloud.commandframework.Description) this.description);
} else {
return cloud.commandframework.Description.of(this.description.getDescription());
}
}
/**
* Get the flag description.
*
* @return Flag description
* @since 1.4.0
*/
public @NonNull ArgumentDescription getArgumentDescription() {
return this.description;
}
@ -119,16 +135,16 @@ public final class CommandFlag<T> {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
if (o == null || this.getClass() != o.getClass()) {
return false;
}
final CommandFlag<?> that = (CommandFlag<?>) o;
return getName().equals(that.getName());
return this.getName().equals(that.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName());
return Objects.hash(this.getName());
}
@ -136,13 +152,13 @@ public final class CommandFlag<T> {
private final String name;
private final String[] aliases;
private final Description description;
private final ArgumentDescription description;
private final CommandArgument<?, T> commandArgument;
private Builder(
final @NonNull String name,
final @NonNull String[] aliases,
final @NonNull Description description,
final @NonNull ArgumentDescription description,
final @Nullable CommandArgument<?, T> commandArgument
) {
this.name = name;
@ -152,7 +168,7 @@ public final class CommandFlag<T> {
}
private Builder(final @NonNull String name) {
this(name, new String[0], Description.empty(), null);
this(name, new String[0], ArgumentDescription.empty(), null);
}
/**
@ -191,8 +207,21 @@ public final class CommandFlag<T> {
*
* @param description Flag description
* @return New builder instance
* @deprecated for removal since 1.4.0. Use {@link #withDescription(ArgumentDescription)} instead.
*/
public Builder<T> withDescription(final @NonNull Description description) {
@Deprecated
public Builder<T> withDescription(final cloud.commandframework.@NonNull Description description) {
return this.withDescription((ArgumentDescription) description);
}
/**d
* Create a new builder instance using the given flag description
*
* @param description Flag description
* @return New builder instance
* @since 1.4.0
*/
public Builder<T> withDescription(final @NonNull ArgumentDescription description) {
return new Builder<>(this.name, this.aliases, description, this.commandArgument);
}

View file

@ -52,13 +52,13 @@ class CommandHelpHandlerTest {
manager.command(manager.commandBuilder("test", meta1).literal("this").literal("thing").build());
final SimpleCommandMeta meta2 = SimpleCommandMeta.builder().with(CommandMeta.DESCRIPTION, "Command with variables").build();
manager.command(manager.commandBuilder("test", meta2).literal("int").
argument(IntegerArgument.of("int"), Description.of("A number")).build());
argument(IntegerArgument.of("int"), ArgumentDescription.of("A number")).build());
manager.command(manager.commandBuilder("test").argument(StringArgument.of("potato")));
manager.command(manager.commandBuilder("vec")
.meta(CommandMeta.DESCRIPTION, "Takes in a vector")
.argumentPair("vec", Pair.of("x", "y"),
Pair.of(Double.class, Double.class), Description.of("Vector")
Pair.of(Double.class, Double.class), ArgumentDescription.of("Vector")
)
.build());
}
@ -241,7 +241,7 @@ class CommandHelpHandlerTest {
while (iterator.hasNext()) {
final CommandComponent<TestCommandSender> component = iterator.next();
String description = component.getDescription().getDescription();
String description = component.getArgumentDescription().getDescription();
if (!description.isEmpty()) {
description = ": " + description;
}

View file

@ -66,13 +66,13 @@ public class CommandSuggestionsTest {
manager.command(manager.commandBuilder("com")
.argumentPair("com", Pair.of("x", "y"), Pair.of(Integer.class, TestEnum.class),
Description.empty()
ArgumentDescription.empty()
)
.argument(IntegerArgument.of("int")));
manager.command(manager.commandBuilder("com2")
.argumentPair("com", Pair.of("x", "enum"),
Pair.of(Integer.class, TestEnum.class), Description.empty()
Pair.of(Integer.class, TestEnum.class), ArgumentDescription.empty()
));
manager.command(manager.commandBuilder("flags")

View file

@ -236,9 +236,9 @@ class CommandTreeTest {
// Create and register a command
Command<TestCommandSender> command = manager.commandBuilder("component")
.literal("literal", "literalalias")
.literal("detail", Description.of("detaildescription"))
.literal("detail", ArgumentDescription.of("detaildescription"))
.argument(CommandArgument.ofType(int.class, "argument"),
Description.of("argumentdescription"))
ArgumentDescription.of("argumentdescription"))
.build();
manager.command(command);
@ -264,10 +264,10 @@ class CommandTreeTest {
Assertions.assertEquals(TypeToken.get(int.class), arguments.get(3).getValueType());
// Check description is set for all components, is empty when not specified
Assertions.assertEquals("", components.get(0).getDescription().getDescription());
Assertions.assertEquals("", components.get(1).getDescription().getDescription());
Assertions.assertEquals("detaildescription", components.get(2).getDescription().getDescription());
Assertions.assertEquals("argumentdescription", components.get(3).getDescription().getDescription());
Assertions.assertEquals("", components.get(0).getArgumentDescription().getDescription());
Assertions.assertEquals("", components.get(1).getArgumentDescription().getDescription());
Assertions.assertEquals("detaildescription", components.get(2).getArgumentDescription().getDescription());
Assertions.assertEquals("argumentdescription", components.get(3).getArgumentDescription().getDescription());
}
@Test

View file

@ -23,6 +23,7 @@
//
package cloud.commandframework.kotlin
import cloud.commandframework.ArgumentDescription
import cloud.commandframework.Command
import cloud.commandframework.CommandManager
import cloud.commandframework.Description
@ -52,6 +53,8 @@ public class MutableCommandBuilder<C : Any> {
* @param commandManager the command manager which will own this command
* @since 1.3.0
*/
@Suppress("DEPRECATION")
@Deprecated(message = "ArgumentDescription should be used over Description", level = DeprecationLevel.HIDDEN)
public constructor(
name: String,
description: Description = Description.empty(),
@ -62,6 +65,25 @@ public class MutableCommandBuilder<C : Any> {
this.commandBuilder = commandManager.commandBuilder(name, description, *aliases)
}
/**
* Create a new [MutableCommandBuilder]
*
* @param name name for the root command node
* @param description description for the root command node
* @param aliases aliases for the root command node
* @param commandManager the command manager which will own this command
* @since 1.4.0
*/
public constructor(
name: String,
description: ArgumentDescription = ArgumentDescription.empty(),
aliases: Array<String> = emptyArray(),
commandManager: CommandManager<C>
) {
this.commandManager = commandManager
this.commandBuilder = commandManager.commandBuilder(name, description, *aliases)
}
/**
* Create a new [MutableCommandBuilder] and invoke the provided receiver lambda on it
*
@ -72,6 +94,8 @@ public class MutableCommandBuilder<C : Any> {
* @param lambda receiver lambda which will be invoked on the new builder
* @since 1.3.0
*/
@Suppress("DEPRECATION")
@Deprecated(message = "ArgumentDescription should be used over Description", level = DeprecationLevel.HIDDEN)
public constructor(
name: String,
description: Description = Description.empty(),
@ -82,6 +106,26 @@ public class MutableCommandBuilder<C : Any> {
lambda(this)
}
/**
* Create a new [MutableCommandBuilder] and invoke the provided receiver lambda on it
*
* @param name name for the root command node
* @param description description for the root command node
* @param aliases aliases for the root command node
* @param commandManager the command manager which will own this command
* @param lambda receiver lambda which will be invoked on the new builder
* @since 1.4.0
*/
public constructor(
name: String,
description: ArgumentDescription = ArgumentDescription.empty(),
aliases: Array<String> = emptyArray(),
commandManager: CommandManager<C>,
lambda: MutableCommandBuilder<C>.() -> Unit
) : this(name, description, aliases, commandManager) {
lambda(this)
}
private constructor(
commandManager: CommandManager<C>,
commandBuilder: Command.Builder<C>
@ -165,6 +209,8 @@ public class MutableCommandBuilder<C : Any> {
* @return a copy of this mutable builder
* @since 1.3.0
*/
@Suppress("DEPRECATION")
@Deprecated(message = "ArgumentDescription should be used over Description", level = DeprecationLevel.HIDDEN)
public fun copy(
literal: String,
description: Description,
@ -175,6 +221,25 @@ public class MutableCommandBuilder<C : Any> {
lambda(this)
}
/**
* Make a new copy of this [MutableCommandBuilder], append a literal, and invoke the provided receiver lambda on it
*
* @param literal name for the literal
* @param description description for the literal
* @param lambda receiver lambda which will be invoked on the new builder
* @return a copy of this mutable builder
* @since 1.4.0
*/
public fun copy(
literal: String,
description: ArgumentDescription,
lambda: MutableCommandBuilder<C>.() -> Unit
): MutableCommandBuilder<C> =
copy().apply {
literal(literal, description)
lambda(this)
}
/**
* Make a new copy of this [MutableCommandBuilder], append a literal, and invoke the provided receiver lambda on it
*
@ -247,6 +312,8 @@ public class MutableCommandBuilder<C : Any> {
* @see [CommandManager.command]
* @since 1.3.0
*/
@Suppress("DEPRECATION")
@Deprecated(message = "ArgumentDescription should be used over Description", level = DeprecationLevel.HIDDEN)
public fun registerCopy(
literal: String,
description: Description,
@ -254,6 +321,25 @@ public class MutableCommandBuilder<C : Any> {
): MutableCommandBuilder<C> =
copy(literal, description, lambda).register()
/**
* Create a new copy of this mutable builder, append a literal, act on it with a receiver lambda, and then register it with
* the owning
* command manager
*
* @param literal name for the literal
* @param description description for the literal
* @param lambda receiver lambda which will be invoked on the new builder
* @return the new mutable builder
* @see [CommandManager.command]
* @since 1.4.0
*/
public fun registerCopy(
literal: String,
description: ArgumentDescription,
lambda: MutableCommandBuilder<C>.() -> Unit
): MutableCommandBuilder<C> =
copy(literal, description, lambda).register()
/**
* Set the value for a certain [CommandMeta.Key] in the command meta storage for this builder
*
@ -414,12 +500,28 @@ public class MutableCommandBuilder<C : Any> {
* @return this mutable builder
* @since 1.3.0
*/
@Suppress("DEPRECATION")
@Deprecated(message = "ArgumentDescription should be used over Description", level = DeprecationLevel.HIDDEN)
public fun argument(
argument: CommandArgument<C, *>,
description: Description = Description.empty()
): MutableCommandBuilder<C> =
mutate { it.argument(argument, description) }
/**
* Add a new argument to this command
*
* @param argument argument to add
* @param description description of the argument
* @return this mutable builder
* @since 1.4.0
*/
public fun argument(
argument: CommandArgument<C, *>,
description: ArgumentDescription = ArgumentDescription.empty()
): MutableCommandBuilder<C> =
mutate { it.argument(argument, description) }
/**
* Add a new argument to this command
*
@ -428,12 +530,28 @@ public class MutableCommandBuilder<C : Any> {
* @return this mutable builder
* @since 1.3.0
*/
@Suppress("DEPRECATION")
@Deprecated(message = "ArgumentDescription should be used over Description", level = DeprecationLevel.HIDDEN)
public fun argument(
argument: CommandArgument.Builder<C, *>,
description: Description = Description.empty()
): MutableCommandBuilder<C> =
mutate { it.argument(argument, description) }
/**
* Add a new argument to this command
*
* @param argument argument to add
* @param description description of the argument
* @return this mutable builder
* @since 1.4.0
*/
public fun argument(
argument: CommandArgument.Builder<C, *>,
description: ArgumentDescription = ArgumentDescription.empty()
): MutableCommandBuilder<C> =
mutate { it.argument(argument, description) }
/**
* Add a new argument to this command
*
@ -442,12 +560,28 @@ public class MutableCommandBuilder<C : Any> {
* @return this mutable builder
* @since 1.3.0
*/
@Suppress("DEPRECATION")
@Deprecated(message = "ArgumentDescription should be used over Description", level = DeprecationLevel.HIDDEN)
public fun argument(
description: Description = Description.empty(),
argumentSupplier: () -> CommandArgument<C, *>
): MutableCommandBuilder<C> =
mutate { it.argument(argumentSupplier(), description) }
/**
* Add a new argument to this command
*
* @param description description of the argument
* @param argumentSupplier supplier of the argument to add
* @return this mutable builder
* @since 1.4.0
*/
public fun argument(
description: ArgumentDescription = ArgumentDescription.empty(),
argumentSupplier: () -> CommandArgument<C, *>
): MutableCommandBuilder<C> =
mutate { it.argument(argumentSupplier(), description) }
/**
* Add a new literal argument to this command
*
@ -457,6 +591,8 @@ public class MutableCommandBuilder<C : Any> {
* @return this mutable builder
* @since 1.3.0
*/
@Suppress("DEPRECATION")
@Deprecated(message = "ArgumentDescription should be used over Description", level = DeprecationLevel.HIDDEN)
public fun literal(
name: String,
description: Description = Description.empty(),
@ -464,6 +600,22 @@ public class MutableCommandBuilder<C : Any> {
): MutableCommandBuilder<C> =
mutate { it.literal(name, description, *aliases) }
/**
* Add a new literal argument to this command
*
* @param name main argument name
* @param description literal description
* @param aliases argument aliases
* @return this mutable builder
* @since 1.4.0
*/
public fun literal(
name: String,
description: ArgumentDescription = ArgumentDescription.empty(),
vararg aliases: String
): MutableCommandBuilder<C> =
mutate { it.literal(name, description, *aliases) }
/**
* Set the [CommandExecutionHandler] for this builder
*
@ -489,7 +641,7 @@ public class MutableCommandBuilder<C : Any> {
public fun flag(
name: String,
aliases: Array<String> = emptyArray(),
description: Description = Description.empty(),
description: ArgumentDescription = ArgumentDescription.empty(),
argumentSupplier: () -> CommandArgument<C, *>
): MutableCommandBuilder<C> = mutate {
it.flag(
@ -514,7 +666,7 @@ public class MutableCommandBuilder<C : Any> {
public fun flag(
name: String,
aliases: Array<String> = emptyArray(),
description: Description = Description.empty(),
description: ArgumentDescription = ArgumentDescription.empty(),
argument: CommandArgument<C, *>
): MutableCommandBuilder<C> = mutate {
it.flag(
@ -539,7 +691,7 @@ public class MutableCommandBuilder<C : Any> {
public fun flag(
name: String,
aliases: Array<String> = emptyArray(),
description: Description = Description.empty(),
description: ArgumentDescription = ArgumentDescription.empty(),
argumentBuilder: CommandArgument.Builder<C, *>
): MutableCommandBuilder<C> = mutate {
it.flag(
@ -563,7 +715,7 @@ public class MutableCommandBuilder<C : Any> {
public fun flag(
name: String,
aliases: Array<String> = emptyArray(),
description: Description = Description.empty(),
description: ArgumentDescription = ArgumentDescription.empty(),
): MutableCommandBuilder<C> = mutate {
it.flag(
this.commandManager.flagBuilder(name)

View file

@ -23,6 +23,7 @@
//
package cloud.commandframework.kotlin.extension
import cloud.commandframework.ArgumentDescription
import cloud.commandframework.Command
import cloud.commandframework.CommandManager
import cloud.commandframework.Description
@ -38,6 +39,8 @@ import kotlin.reflect.KClass
* @param lambda receiver lambda which will be invoked on the new builder
* @since 1.3.0
*/
@Suppress("DEPRECATION")
@Deprecated(message = "ArgumentDescription should be used over Description", level = DeprecationLevel.HIDDEN)
public fun <C : Any> CommandManager<C>.commandBuilder(
name: String,
description: Description = Description.empty(),
@ -46,6 +49,23 @@ public fun <C : Any> CommandManager<C>.commandBuilder(
): MutableCommandBuilder<C> =
MutableCommandBuilder(name, description, aliases, this, lambda)
/**
* Create a new [MutableCommandBuilder] and invoke the provided receiver lambda on it
*
* @param name name for the root command node
* @param description description for the root command node
* @param aliases aliases for the root command node
* @param lambda receiver lambda which will be invoked on the new builder
* @since 1.4.0
*/
public fun <C : Any> CommandManager<C>.commandBuilder(
name: String,
description: ArgumentDescription = ArgumentDescription.empty(),
aliases: Array<String> = emptyArray(),
lambda: MutableCommandBuilder<C>.() -> Unit
): MutableCommandBuilder<C> =
MutableCommandBuilder(name, description, aliases, this, lambda)
/**
* Create a new [MutableCommandBuilder] which will invoke the provided receiver lambda, and then register itself with the
* owning [CommandManager]
@ -56,6 +76,8 @@ public fun <C : Any> CommandManager<C>.commandBuilder(
* @param lambda receiver lambda which will be invoked on the new builder
* @since 1.3.0
*/
@Suppress("DEPRECATION")
@Deprecated(message = "ArgumentDescription should be used over Description", level = DeprecationLevel.HIDDEN)
public fun <C : Any> CommandManager<C>.buildAndRegister(
name: String,
description: Description = Description.empty(),
@ -64,6 +86,24 @@ public fun <C : Any> CommandManager<C>.buildAndRegister(
): MutableCommandBuilder<C> =
commandBuilder(name, description, aliases, lambda).register()
/**
* Create a new [MutableCommandBuilder] which will invoke the provided receiver lambda, and then register itself with the
* owning [CommandManager]
*
* @param name name for the root command node
* @param description description for the root command node
* @param aliases aliases for the root command node
* @param lambda receiver lambda which will be invoked on the new builder
* @since 1.4.0
*/
public fun <C : Any> CommandManager<C>.buildAndRegister(
name: String,
description: ArgumentDescription = ArgumentDescription.empty(),
aliases: Array<String> = emptyArray(),
lambda: MutableCommandBuilder<C>.() -> Unit
): MutableCommandBuilder<C> =
commandBuilder(name, description, aliases, lambda).register()
/**
* Build the provided [MutableCommandBuilder]s into [Command]s, and then register them with the command manager
*
@ -98,7 +138,24 @@ public fun <C : Any> Command.Builder<C>.senderType(type: KClass<out C>): Command
* @return the description
* @since 1.3.0
*/
@Suppress("DEPRECATION")
@Deprecated(
message = "Use interface variant that allows for rich text",
replaceWith = ReplaceWith("argumentDescription(description)")
)
public fun description(
description: String = ""
): Description =
if (description.isEmpty()) Description.empty() else Description.of(description)
/**
* Get a [ArgumentDescription], defaulting to [ArgumentDescription.empty]
*
* @param description description string
* @return the description
* @since 1.4.0
*/
public fun argumentDescription(
description: String = ""
): ArgumentDescription =
if (description.isEmpty()) ArgumentDescription.empty() else ArgumentDescription.of(description)

View file

@ -27,10 +27,7 @@ import cloud.commandframework.CommandManager
import cloud.commandframework.arguments.standard.StringArgument
import cloud.commandframework.execution.CommandExecutionCoordinator
import cloud.commandframework.internal.CommandRegistrationHandler
import cloud.commandframework.kotlin.extension.buildAndRegister
import cloud.commandframework.kotlin.extension.command
import cloud.commandframework.kotlin.extension.commandBuilder
import cloud.commandframework.kotlin.extension.description
import cloud.commandframework.kotlin.extension.*
import cloud.commandframework.meta.CommandMeta
import cloud.commandframework.meta.SimpleCommandMeta
import org.junit.jupiter.api.Assertions
@ -48,7 +45,7 @@ class CommandBuildingDSLTest {
senderType<SpecificCommandSender>()
literal("dsl")
argument(description("An amazing command argument")) {
argument(argumentDescription("An amazing command argument")) {
StringArgument.of("moment")
}
handler {

View file

@ -1,4 +1,5 @@
dependencies {
api(project(":cloud-core"))
api("net.kyori", "adventure-api", Versions.adventureApi)
api("net.kyori", "adventure-text-serializer-plain", Versions.adventureApi)
}

View file

@ -23,6 +23,7 @@
//
package cloud.commandframework.minecraft.extras;
import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.Command;
import cloud.commandframework.CommandComponent;
import cloud.commandframework.CommandHelpHandler;
@ -488,7 +489,7 @@ public final class MinecraftHelp<C> {
final CommandComponent<C> component = iterator.next();
final CommandArgument<C, ?> argument = component.getArgument();
String syntax = this.commandManager.getCommandSyntaxFormatter()
final String syntax = this.commandManager.getCommandSyntaxFormatter()
.apply(Collections.singletonList(argument), null);
final TextComponent.Builder textComponent = text()
@ -502,10 +503,10 @@ public final class MinecraftHelp<C> {
);
textComponent.append(text(")", this.colors.alternateHighlight));
}
final String description = component.getDescription().getDescription();
final ArgumentDescription description = component.getArgumentDescription();
if (!description.isEmpty()) {
textComponent.append(text(" - ", this.colors.accent));
textComponent.append(this.descriptionDecorator.apply(description).color(this.colors.text));
textComponent.append(this.formatDescription(description).colorIfAbsent(this.colors.text));
}
audience.sendMessage(textComponent);
@ -514,6 +515,14 @@ public final class MinecraftHelp<C> {
audience.sendMessage(this.footer(sender));
}
private Component formatDescription(final ArgumentDescription description) {
if (description instanceof RichDescription) {
return ((RichDescription) description).getContents();
} else {
return this.descriptionDecorator.apply(description.getDescription());
}
}
private @NonNull Component showingResults(
final @NonNull C sender,
final @NonNull String query

View file

@ -0,0 +1,133 @@
//
// MIT License
//
// Copyright (c) 2020 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework.minecraft.extras;
import cloud.commandframework.ArgumentDescription;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
import net.kyori.adventure.translation.GlobalTranslator;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Locale;
import static java.util.Objects.requireNonNull;
/**
* An argument description implementation that uses Adventure components.
*
* @since 1.4.0
*/
public final class RichDescription implements ArgumentDescription {
private static final RichDescription EMPTY = new RichDescription(Component.empty());
private final Component contents;
RichDescription(final Component contents) {
this.contents = contents;
}
/**
* Get an empty description.
*
* @return the empty description
*/
public static @NonNull RichDescription empty() {
return EMPTY;
}
/**
* Create a new rich description from the provided component.
*
* @param contents the rich contents
* @return a new rich description
*/
public static @NonNull RichDescription of(final @NonNull ComponentLike contents) {
final Component componentContents = requireNonNull(contents, "contents").asComponent();
if (Component.empty().equals(componentContents)) {
return EMPTY;
}
return new RichDescription(componentContents);
}
/* Translatable helper methods */
/**
* Create a rich description pointing to a translation key.
*
* @param key the translation key
* @return a new rich description
*/
public static @NonNull RichDescription translatable(final @NonNull String key) {
requireNonNull(key, "key");
return new RichDescription(Component.translatable(key));
}
/**
* Create a rich description pointing to a translation key.
*
* @param key the translation key
* @param args the arguments to use with the translation key
* @return a new rich description
*/
public static @NonNull RichDescription translatable(
final @NonNull String key,
final @NonNull ComponentLike @NonNull... args
) {
requireNonNull(key, "key");
requireNonNull(args, "args");
return new RichDescription(Component.translatable(key, args));
}
/**
* {@inheritDoc}
*
* @deprecated to discourage use. A plain serialization is a somewhat expensive and lossy operation, use
* {@link #getContents()} instead.
*/
@Override
@Deprecated
public @NonNull String getDescription() {
return PlainComponentSerializer.plain().serialize(GlobalTranslator.render(this.contents, Locale.getDefault()));
}
/**
* Get the contents of this description.
*
* @return the component contents of this description
*/
public @NonNull Component getContents() {
return this.contents;
}
@Override
public boolean isEmpty() {
return Component.empty().equals(this.contents);
}
}

View file

@ -23,9 +23,9 @@
//
package cloud.commandframework.examples.bukkit;
import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.Command;
import cloud.commandframework.CommandTree;
import cloud.commandframework.Description;
import cloud.commandframework.minecraft.extras.MinecraftExceptionHandler;
import cloud.commandframework.minecraft.extras.MinecraftHelp;
import cloud.commandframework.annotations.AnnotationParser;
@ -56,6 +56,7 @@ import cloud.commandframework.execution.AsynchronousCommandExecutionCoordinator;
import cloud.commandframework.execution.CommandExecutionCoordinator;
import cloud.commandframework.extra.confirmation.CommandConfirmationManager;
import cloud.commandframework.meta.CommandMeta;
import cloud.commandframework.minecraft.extras.RichDescription;
import cloud.commandframework.minecraft.extras.TextColorArgument;
import cloud.commandframework.paper.PaperCommandManager;
import cloud.commandframework.tasks.TaskConsumer;
@ -63,8 +64,9 @@ import cloud.commandframework.types.tuples.Triplet;
import io.leangen.geantyref.TypeToken;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextDecoration;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@ -87,6 +89,8 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import static net.kyori.adventure.text.Component.text;
/**
* Example plugin class
*/
@ -196,10 +200,10 @@ public final class ExamplePlugin extends JavaPlugin {
.withArgumentParsingHandler()
.withCommandExecutionHandler()
.withDecorator(
component -> Component.text()
.append(Component.text("[", NamedTextColor.DARK_GRAY))
.append(Component.text("Example", NamedTextColor.GOLD))
.append(Component.text("] ", NamedTextColor.DARK_GRAY))
component -> text()
.append(text("[", NamedTextColor.DARK_GRAY))
.append(text("Example", NamedTextColor.GOLD))
.append(text("] ", NamedTextColor.DARK_GRAY))
.append(component).build()
).apply(manager, bukkitAudiences::sender);
//
@ -234,7 +238,7 @@ public final class ExamplePlugin extends JavaPlugin {
.literal("me")
// Require a player sender
.senderType(Player.class)
.argument(worldArgument, Description.of("World name"))
.argument(worldArgument, ArgumentDescription.of("World name"))
.argumentTriplet(
"coords",
TypeToken.get(Vector.class),
@ -243,7 +247,7 @@ public final class ExamplePlugin extends JavaPlugin {
(sender, triplet) -> new Vector(triplet.getFirst(), triplet.getSecond(),
triplet.getThird()
),
Description.of("Coordinates")
ArgumentDescription.of("Coordinates")
)
.handler(context -> manager.taskRecipe().begin(context)
.synchronous(commandContext -> {
@ -258,7 +262,7 @@ public final class ExamplePlugin extends JavaPlugin {
.senderType(Player.class)
.argument(
SingleEntitySelectorArgument.of("entity"),
Description.of("Entity to teleport")
ArgumentDescription.of("Entity to teleport")
)
.literal("here")
.handler(
@ -277,7 +281,7 @@ public final class ExamplePlugin extends JavaPlugin {
))
.command(builder.literal("teleport")
.meta(CommandMeta.DESCRIPTION, "Teleport to a world")
.argument(WorldArgument.of("world"), Description.of("World to teleport to"))
.argument(WorldArgument.of("world"), ArgumentDescription.of("World to teleport to"))
.handler(context -> manager.taskRecipe().begin(context).synchronous(ctx -> {
final Player player = (Player) ctx.getSender();
player.teleport(ctx.<World>get("world").getSpawnLocation());
@ -330,23 +334,23 @@ public final class ExamplePlugin extends JavaPlugin {
.literal("helpcolors")
.argument(
TextColorArgument.of("primary"),
Description.of("The primary color for the color scheme")
RichDescription.of(text("The primary color for the color scheme", Style.style(TextDecoration.ITALIC)))
)
.argument(
TextColorArgument.of("highlight"),
Description.of("The primary color used to highlight commands and queries")
RichDescription.of(text("The primary color used to highlight commands and queries"))
)
.argument(
TextColorArgument.of("alternate_highlight"),
Description.of("The secondary color used to highlight commands and queries")
RichDescription.of(text("The secondary color used to highlight commands and queries"))
)
.argument(
TextColorArgument.of("text"),
Description.of("The color used for description text")
RichDescription.of(text("The color used for description text"))
)
.argument(
TextColorArgument.of("accent"),
Description.of("The color used for accents and symbols")
RichDescription.of(text("The color used for accents and symbols"))
)
.handler(c -> minecraftHelp.setHelpColors(MinecraftHelp.HelpColors.of(
c.get("primary"),
@ -363,7 +367,7 @@ public final class ExamplePlugin extends JavaPlugin {
manager.command(
manager.commandBuilder(
"arraycommand",
Description.of("Bukkit-esque cmmand")
ArgumentDescription.of("Bukkit-esque cmmand")
).argument(
StringArrayArgument.optional(
"args",
@ -375,7 +379,7 @@ public final class ExamplePlugin extends JavaPlugin {
return Collections.emptyList();
}
),
Description.of("Arguments")
ArgumentDescription.of("Arguments")
).handler(context -> {
final String[] args = context.getOrDefault("args", new String[0]);
context.getSender().sendMessage("You wrote: " + StringUtils.join(args, " "));
@ -408,7 +412,7 @@ public final class ExamplePlugin extends JavaPlugin {
private void commandClear(final @NonNull Player player) {
player.getInventory().clear();
this.bukkitAudiences.player(player)
.sendMessage(Identity.nil(), Component.text("Your inventory has been cleared", NamedTextColor.GOLD));
.sendMessage(Identity.nil(), text("Your inventory has been cleared", NamedTextColor.GOLD));
}
@CommandMethod("example give <material> <amount>")
@ -452,8 +456,8 @@ public final class ExamplePlugin extends JavaPlugin {
) {
bukkitAudiences.sender(sender).sendMessage(
Identity.nil(),
Component.text().append(Component.text("You have been given ", NamedTextColor.AQUA))
.append(Component.text(money, NamedTextColor.GOLD))
text().append(text("You have been given ", NamedTextColor.AQUA))
.append(text(money, NamedTextColor.GOLD))
);
}

View file

@ -23,9 +23,9 @@
//
package cloud.commandframework.examples.bungee;
import cloud.commandframework.ArgumentDescription;
import cloud.commandframework.Command;
import cloud.commandframework.CommandTree;
import cloud.commandframework.Description;
import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.bungee.BungeeCommandManager;
import cloud.commandframework.bungee.arguments.PlayerArgument;
@ -35,8 +35,8 @@ import cloud.commandframework.execution.CommandExecutionCoordinator;
import cloud.commandframework.extra.confirmation.CommandConfirmationManager;
import cloud.commandframework.meta.CommandMeta;
import cloud.commandframework.minecraft.extras.MinecraftExceptionHandler;
import cloud.commandframework.minecraft.extras.RichDescription;
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.config.ServerInfo;
@ -46,6 +46,8 @@ import net.md_5.bungee.api.plugin.Plugin;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import static net.kyori.adventure.text.Component.text;
public final class ExamplePlugin extends Plugin {
private BungeeCommandManager<CommandSender> manager;
@ -78,10 +80,10 @@ public final class ExamplePlugin extends Plugin {
30L,
TimeUnit.SECONDS,
context -> bungeeAudiences.sender(context.getCommandContext().getSender()).sendMessage(
Component.text(
text(
"Confirmation required. Confirm using /example confirm.", NamedTextColor.RED)),
sender -> bungeeAudiences.sender(sender).sendMessage(
Component.text("You do not have any pending commands.", NamedTextColor.RED))
text("You do not have any pending commands.", NamedTextColor.RED))
);
this.confirmationManager.registerConfirmationProcessor(manager);
@ -91,10 +93,10 @@ public final class ExamplePlugin extends Plugin {
.withInvalidSenderHandler()
.withNoPermissionHandler()
.withArgumentParsingHandler()
.withDecorator(component -> Component.text()
.append(Component.text("[", NamedTextColor.DARK_GRAY))
.append(Component.text("Example", NamedTextColor.GOLD))
.append(Component.text("] ", NamedTextColor.DARK_GRAY))
.withDecorator(component -> text()
.append(text("[", NamedTextColor.DARK_GRAY))
.append(text("Example", NamedTextColor.GOLD))
.append(text("] ", NamedTextColor.DARK_GRAY))
.append(component).build()
).apply(manager, bungeeAudiences::sender);
this.constructCommands();
@ -121,12 +123,12 @@ public final class ExamplePlugin extends Plugin {
this.manager.command(
manager.commandBuilder("player")
.senderType(ProxiedPlayer.class)
.argument(playerArgument, Description.of("Player name"))
.argument(playerArgument, RichDescription.of(text("Player ").append(text("name", NamedTextColor.GOLD))))
.handler(context -> {
final ProxiedPlayer player = context.get("player");
bungeeAudiences.sender(context.getSender()).sendMessage(
Component.text("Selected ", NamedTextColor.GOLD)
.append(Component.text(player.getDisplayName(), NamedTextColor.AQUA))
text("Selected ", NamedTextColor.GOLD)
.append(text(player.getDisplayName(), NamedTextColor.AQUA))
);
})
);
@ -137,12 +139,12 @@ public final class ExamplePlugin extends Plugin {
this.manager.command(
this.manager.commandBuilder("server")
.senderType(ProxiedPlayer.class)
.argument(serverArgument, Description.of("Server name"))
.argument(serverArgument, ArgumentDescription.of("Server name"))
.handler(context -> {
final ServerInfo server = context.get("server");
bungeeAudiences.sender(context.getSender()).sendMessage(
Component.text("Selected ", NamedTextColor.GOLD)
.append(Component.text(server.getName(), NamedTextColor.AQUA))
text("Selected ", NamedTextColor.GOLD)
.append(text(server.getName(), NamedTextColor.AQUA))
);
})
);