Skip to content

Commit

Permalink
Help topic rewrite
Browse files Browse the repository at this point in the history
Revises github.com/JorelAli/CommandAPI/commit/ac8c06086f2e05015416b939028e1301ff95a87b

Notable changes:
- `RegisteredCommand` and `RegisteredCommand.Node` now have generic `<CommandSender>` parameter
  - `RegisteredCommand.Node` includes the `CommandPermission permission` and `Predicate<CommandSender> requirements`, copied from the argument/command the node represents
  - `RegisteredCommand#permission` is now acessibile as the permission of the `Node rootNode`

- Created `CommandAPIHelpTopic` in `dev.jorel.commandapi.help` package
  - Replaced `shortDescription`, `fullDescription`, `usageDescription`, and `Object helpTopic` fields in `ExecutableCommand` and `RegisteredCommand` with `CommandAPIHelpTopic helpTopic`
  - Extended by `EditableHelpTopic`
    - Help builder methods of `ExecutableCommand` are delegated to its `CommandAPIHelpTopic` if it is editable
    - More general API created for #528: short description, full description, and usage can be provided separately to take advantage of the formatting the CommandAPI uses for static Strings
  - Extended by `BukkitHelpTopicWrapper` in `commandapi-bukkit-core`
    - Wraps Bukkit's `HelpTopic` as a `CommandAPIHelpTopic` so full `HelpTopic` customization can still be used

- Created `CustomCommandAPIHelpTopic` in `commandapi-bukkit`
  - Converts a `CommandAPIHelpTopic` into a Bukkit `HelpTopic` for adding to the help map
  - Replaces usage of `NMS#generateHelpTopic`
  - Help formatting code extracted from `CommandAPIBukkit#updateHelpForCommands`
  - Resolves #470: `CommandSender` permissions and requirements are now checked when generating usage

- Changed the treatement of namespaced help topics (#546). Namespaced help topics are now created. In the case where the same command name is registered with different namespaces, this allows the user to see the unmerged help using `/help namespace:commandName` (see `CommandHelpTests#testRegisterMergeNamespaces`).

- Updated tests to fully cover changes

TODO: Update and write documentation
  • Loading branch information
willkroboth committed May 14, 2024
1 parent cd1eecb commit c2f4766
Show file tree
Hide file tree
Showing 60 changed files with 1,670 additions and 590 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public void setArguments(List<AbstractArgumentTree<?, Argument, CommandSender>>
* @param <Source> The Brigadier Source object for running commands.
*/
public <Source> void buildBrigadierNode(
NodeInformation<Source> previousNodeInformation,
NodeInformation<CommandSender, Source> previousNodeInformation,
List<Argument> previousArguments, List<String> previousArgumentNames
) {
CommandAPIHandler<Argument, CommandSender, Source> handler = CommandAPIHandler.getInstance();
Expand All @@ -115,12 +115,12 @@ public <Source> void buildBrigadierNode(
executor.hasAnyExecutors() ? args -> handler.generateBrigadierCommand(args, executor) : null);

// Collect children into our own list
List<RegisteredCommand.Node> childrenNodeInformation = new ArrayList<>();
List<RegisteredCommand.Node<CommandSender>> childrenNodeInformation = new ArrayList<>();

// Add our branches as children to the node
for (AbstractArgumentTree<?, Argument, CommandSender> child : arguments) {
// Collect children into our own list
NodeInformation<Source> newPreviousNodeInformation = new NodeInformation<>(
NodeInformation<CommandSender, Source> newPreviousNodeInformation = new NodeInformation<>(
previousNodeInformation.lastCommandNodes(),
children -> childrenNodeInformation.addAll(children)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,14 +238,14 @@ protected boolean isRootExecutable() {
}

@Override
protected <Source> List<RegisteredCommand.Node> createArgumentNodes(LiteralCommandNode<Source> rootNode) {
protected <Source> List<RegisteredCommand.Node<CommandSender>> createArgumentNodes(LiteralCommandNode<Source> rootNode) {
CommandAPIHandler<Argument, CommandSender, Source> handler = CommandAPIHandler.getInstance();

List<RegisteredCommand.Node> childrenNodes = new ArrayList<>();
List<RegisteredCommand.Node<CommandSender>> childrenNodes = new ArrayList<>();

// Create arguments
if (hasAnyArguments()) {
NodeInformation<Source> previousNodeInformation = new NodeInformation<>(List.of(rootNode), children -> childrenNodes.addAll(children));
NodeInformation<CommandSender, Source> previousNodeInformation = new NodeInformation<>(List.of(rootNode), children -> childrenNodes.addAll(children));
List<Argument> previousArguments = new ArrayList<>();
List<String> previousArgumentNames = new ArrayList<>();

Expand Down Expand Up @@ -279,12 +279,12 @@ protected <Source> List<RegisteredCommand.Node> createArgumentNodes(LiteralComma

// Add subcommands
for (Impl subCommand : subcommands) {
CommandInformation<Source> nodes = subCommand.createCommandInformation("");
CommandInformation<CommandSender, Source> nodes = subCommand.createCommandInformation("");

// Add root node
rootNode.addChild(nodes.rootNode());

RegisteredCommand.Node rootNodeInformation = nodes.command().rootNode();
RegisteredCommand.Node<CommandSender> rootNodeInformation = nodes.command().rootNode();
childrenNodes.add(rootNodeInformation);

// Add aliases
Expand All @@ -294,9 +294,10 @@ protected <Source> List<RegisteredCommand.Node> createArgumentNodes(LiteralComma
// Create node information for the alias
String aliasName = aliasNode.getLiteral();
childrenNodes.add(
new RegisteredCommand.Node(
new RegisteredCommand.Node<>(
aliasName, rootNodeInformation.className(), aliasName,
rootNodeInformation.executable(), rootNodeInformation.children()
rootNodeInformation.executable(), rootNodeInformation.permission(), rootNodeInformation.requirements(),
rootNodeInformation.children()
)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ protected boolean isRootExecutable() {
}

@Override
protected <Source> List<RegisteredCommand.Node> createArgumentNodes(LiteralCommandNode<Source> rootNode) {
protected <Source> List<RegisteredCommand.Node<CommandSender>> createArgumentNodes(LiteralCommandNode<Source> rootNode) {
CommandAPIHandler<Argument, CommandSender, Source> handler = CommandAPIHandler.getInstance();

List<RegisteredCommand.Node> childrenNodes = new ArrayList<>();
List<RegisteredCommand.Node<CommandSender>> childrenNodes = new ArrayList<>();

// The previous arguments include an unlisted MultiLiteral representing the command name and aliases
// This doesn't affect how the command acts, but it helps represent the command path in exceptions
Expand All @@ -103,7 +103,7 @@ protected <Source> List<RegisteredCommand.Node> createArgumentNodes(LiteralComma
// Build branches
for (AbstractArgumentTree<?, Argument, CommandSender> argument : arguments) {
// We need new previousArguments lists for each branch so they don't interfere
NodeInformation<Source> previousNodeInformation = new NodeInformation<>(List.of(rootNode), children -> childrenNodes.addAll(children));
NodeInformation<CommandSender, Source> previousNodeInformation = new NodeInformation<>(List.of(rootNode), children -> childrenNodes.addAll(children));
List<Argument> previousArguments = new ArrayList<>();
List<String> previousArgumentNames = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,8 @@ public static void registerCommand(Class<?> commandClass) {
* @return A list of all {@link RegisteredCommand}{@code s} that have been
* registered by the CommandAPI so far. The returned list is immutable.
*/
public static List<RegisteredCommand> getRegisteredCommands() {
return Collections.unmodifiableList(new ArrayList<>(CommandAPIHandler.getInstance().registeredCommands.values()));
public static <CommandSender> List<RegisteredCommand<CommandSender>> getRegisteredCommands() {
CommandAPIHandler<?, CommandSender, ?> handler = CommandAPIHandler.getInstance();
return Collections.unmodifiableList(new ArrayList<>(handler.registeredCommands.values()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public class CommandAPIHandler<Argument
}

final CommandAPIPlatform<Argument, CommandSender, Source> platform;
final Map<String, RegisteredCommand> registeredCommands; // Keep track of what has been registered for type checking
final Map<String, RegisteredCommand<CommandSender>> registeredCommands; // Keep track of what has been registered for type checking
static final Pattern NAMESPACE_PATTERN = Pattern.compile("[0-9a-z_.-]+");

private static CommandAPIHandler<?, ?, ?> instance;
Expand Down Expand Up @@ -171,11 +171,11 @@ public void registerCommand(ExecutableCommand<?, CommandSender> command, String
platform.preCommandRegistration(command.getName());

// Generate command information
ExecutableCommand.CommandInformation<Source> commandInformation = command.createCommandInformation(namespace);
ExecutableCommand.CommandInformation<CommandSender, Source> commandInformation = command.createCommandInformation(namespace);

LiteralCommandNode<Source> resultantNode = commandInformation.rootNode();
List<LiteralCommandNode<Source>> aliasNodes = commandInformation.aliasNodes();
RegisteredCommand registeredCommand = commandInformation.command();
RegisteredCommand<CommandSender> registeredCommand = commandInformation.command();

// Log the commands being registered
for (List<String> argsAsStr : registeredCommand.rootNode().argsAsStr()) {
Expand Down Expand Up @@ -209,7 +209,8 @@ public void registerCommand(ExecutableCommand<?, CommandSender> command, String
writeDispatcherToFile();

// Merge RegisteredCommand into map
BiFunction<String, RegisteredCommand, RegisteredCommand> mergeRegisteredCommands = (key, value) -> value == null ? registeredCommand : value.mergeCommandInformation(registeredCommand);
BiFunction<String, RegisteredCommand<CommandSender>, RegisteredCommand<CommandSender>> mergeRegisteredCommands =
(key, value) -> value == null ? registeredCommand : value.mergeCommandInformation(registeredCommand);

if (registeredCommand.namespace().isEmpty()) {
registeredCommands.compute(registeredCommand.commandName(), mergeRegisteredCommands);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public interface CommandAPIPlatform<Argument
* @param resultantNode The node that was registered
* @param aliasNodes Any alias nodes that were also registered as a part of this registration process
*/
public abstract void postCommandRegistration(RegisteredCommand registeredCommand, LiteralCommandNode<Source> resultantNode, List<LiteralCommandNode<Source>> aliasNodes);
public abstract void postCommandRegistration(RegisteredCommand<CommandSender> registeredCommand, LiteralCommandNode<Source> resultantNode, List<LiteralCommandNode<Source>> aliasNodes);

/**
* Builds and registers a Brigadier command node.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,14 @@ PermissionNode getPermissionNode() {
return this.permissionNode;
}

CommandPermission negate() {
/**
* Sets this permission to be negated.
* You can also achieve this using {@link ExecutableCommand#withoutPermission(CommandPermission)}.
*
* @return This permission object
*/
public CommandPermission negate() {
this.negated = true;
return this;
}

}
Loading

0 comments on commit c2f4766

Please sign in to comment.