Skip to content

Commit

Permalink
Extract logic for generating the SuggestionsProvider for an Argument …
Browse files Browse the repository at this point in the history
…into CommandAPIHandler
  • Loading branch information
willkroboth committed Apr 19, 2024
1 parent 4de226b commit 44157be
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.tree.LiteralCommandNode;
import dev.jorel.commandapi.arguments.AbstractArgument;
import dev.jorel.commandapi.arguments.ArgumentSuggestions;
import dev.jorel.commandapi.arguments.PreviewInfo;
import dev.jorel.commandapi.arguments.Previewable;
import dev.jorel.commandapi.arguments.*;
import dev.jorel.commandapi.commandsenders.AbstractCommandSender;
import dev.jorel.commandapi.executors.CommandArguments;
import dev.jorel.commandapi.executors.ExecutionInfo;
import dev.jorel.commandapi.preprocessor.RequireField;
import dev.jorel.commandapi.wrappers.PreviewableFunction;

import java.util.concurrent.CompletableFuture;

/**
* The "brains" behind the CommandAPI.
* Handles command registration
Expand Down Expand Up @@ -301,6 +301,61 @@ public CommandArguments args() {
};
}

/**
* Generates a Brigadier {@link SuggestionProvider} using the given CommandAPI objects.
*
* @param previousArguments A list of Arguments that came before the argument using these suggestions. These arguments
* will be available in the {@link SuggestionInfo} when providing suggestions.
* @param argument The argument to give suggestions for.
* @return A Brigadier SuggestionProvider object that generates suggestions for the given argument with the previous
* arguments as input, or null if there are no suggestions for the given argument.
*/
public SuggestionProvider<Source> generateBrigadierSuggestions(List<Argument> previousArguments, Argument argument) {
// Overriding suggestions take precedence
Optional<ArgumentSuggestions<CommandSender>> overriddenSuggestions = argument.getOverriddenSuggestions();
if (overriddenSuggestions.isPresent()) {
return generateBrigadierSuggestions(previousArguments, overriddenSuggestions.get());
}

// Included suggestions add on to whatever "default" suggestions exist
Optional<ArgumentSuggestions<CommandSender>> includedSuggestions = argument.getIncludedSuggestions();
if (includedSuggestions.isPresent()) {
// Insert additional defined suggestions
SuggestionProvider<Source> defaultSuggestions;
if (argument instanceof CustomProvidedArgument cPA) {
defaultSuggestions = platform.getSuggestionProvider(cPA.getSuggestionProvider());
} else {
defaultSuggestions = argument.getRawType()::listSuggestions;
}

SuggestionProvider<Source> suggestionsToAdd = generateBrigadierSuggestions(previousArguments, includedSuggestions.get());

return (cmdCtx, builder) -> {
// Heavily inspired by CommandDispatcher#getCompletionSuggestions, with combining
// multiple CompletableFuture<Suggestions> into one.
CompletableFuture<Suggestions> defaultSuggestionsFuture = defaultSuggestions.getSuggestions(cmdCtx, builder);
CompletableFuture<Suggestions> includedSuggestionsFuture = suggestionsToAdd.getSuggestions(cmdCtx, builder);

CompletableFuture<Suggestions> result = new CompletableFuture<>();
CompletableFuture.allOf(defaultSuggestionsFuture, includedSuggestionsFuture).thenRun(() -> {
List<Suggestions> suggestions = new ArrayList<>();
suggestions.add(defaultSuggestionsFuture.join());
suggestions.add(includedSuggestionsFuture.join());
result.complete(Suggestions.merge(cmdCtx.getInput(), suggestions));
});
return result;
};
}

// Custom provided arguments
if (argument instanceof CustomProvidedArgument cPA) {
return platform.getSuggestionProvider(cPA.getSuggestionProvider());
}

// Calling `RequiredArgumentBuilder.suggests(null)` makes it so no custom suggestions are given, so this makes sense
return null;
}

/**
* Generates a Brigadier {@link SuggestionProvider} using the given CommandAPI objects.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.tree.CommandNode;
import dev.jorel.commandapi.AbstractArgumentTree;
import dev.jorel.commandapi.CommandAPIExecutor;
Expand All @@ -40,7 +38,6 @@
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;

/**
Expand Down Expand Up @@ -429,39 +426,7 @@ public void checkPreconditions(List<Argument> previousArguments, List<String> pr
RequiredArgumentBuilder<Source, ?> rootBuilder = RequiredArgumentBuilder.argument(nodeName, rawType);

// Add suggestions
if (replaceSuggestions != null) {
// Overridden suggestions take precedence
rootBuilder.suggests(handler.generateBrigadierSuggestions(previousArguments, replaceSuggestions));
} else if (includedSuggestions != null) {
// Insert additional defined suggestions
SuggestionProvider<Source> defaultSuggestions;
if (this instanceof CustomProvidedArgument cPA) {
defaultSuggestions = handler.getPlatform().getSuggestionProvider(cPA.getSuggestionProvider());
} else {
defaultSuggestions = rawType::listSuggestions;
}

SuggestionProvider<Source> includedSuggestions = handler.generateBrigadierSuggestions(previousArguments, this.includedSuggestions);

rootBuilder.suggests((cmdCtx, builder) -> {
// Heavily inspired by CommandDispatcher#getCompletionSuggestions, with combining
// multiple CompletableFuture<Suggestions> into one.
CompletableFuture<Suggestions> defaultSuggestionsFuture = defaultSuggestions.getSuggestions(cmdCtx, builder);
CompletableFuture<Suggestions> includedSuggestionsFuture = includedSuggestions.getSuggestions(cmdCtx, builder);

CompletableFuture<Suggestions> result = new CompletableFuture<>();
CompletableFuture.allOf(defaultSuggestionsFuture, includedSuggestionsFuture).thenRun(() -> {
List<Suggestions> suggestions = new ArrayList<>();
suggestions.add(defaultSuggestionsFuture.join());
suggestions.add(includedSuggestionsFuture.join());
result.complete(Suggestions.merge(cmdCtx.getInput(), suggestions));
});
return result;
});
} else if (this instanceof CustomProvidedArgument cPA) {
// Handle arguments with built-in suggestion providers
rootBuilder.suggests(handler.getPlatform().getSuggestionProvider(cPA.getSuggestionProvider()));
}
rootBuilder.suggests(handler.generateBrigadierSuggestions(previousArguments, (Argument) this));

// Add argument to previousArgument lists
// Note: this argument should not be in the previous arguments list when doing suggestions,
Expand Down

0 comments on commit 44157be

Please sign in to comment.