mirror of
https://github.com/aikar/commands.git
synced 2026-05-31 06:11:55 +00:00
Merge branch 'MiniDigger-help-improvements'
* MiniDigger-help-improvements: Improvements to help formatter start with abstracting help messages out make sure to only treat a type as sender if its not annotated with "other" help improvements
This commit is contained in:
@@ -353,4 +353,9 @@ public class BukkitCommandManager extends CommandManager<
|
||||
this.autoDetectFromClient = autoDetectFromClient;
|
||||
return old;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandPrefix(CommandIssuer issuer) {
|
||||
return issuer.isPlayer() ? "/" : "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,4 +207,10 @@ public class BungeeCommandManager extends CommandManager<
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getCommandPrefix(CommandIssuer issuer) {
|
||||
return issuer.isPlayer() ? "/" : "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,6 +236,15 @@ public class CommandContexts <R extends CommandExecutionContext<?, ? extends Com
|
||||
if (perPage != null) {
|
||||
commandHelp.setPerPage(perPage);
|
||||
}
|
||||
|
||||
// check if we have an exact match and should display the help page for that sub command instead
|
||||
if(search != null){
|
||||
String cmd = String.join(" ", search);
|
||||
if(commandHelp.isExactMatch(cmd)){
|
||||
return commandHelp;
|
||||
}
|
||||
}
|
||||
|
||||
commandHelp.setSearch(search);
|
||||
return commandHelp;
|
||||
});
|
||||
|
||||
@@ -40,20 +40,23 @@ public class CommandHelp {
|
||||
private final CommandManager manager;
|
||||
private final CommandIssuer issuer;
|
||||
private final List<HelpEntry> helpEntries = new ArrayList<>();
|
||||
private final String commandName;
|
||||
private int page;
|
||||
private int perPage;
|
||||
private List<String> search;
|
||||
private HelpEntry selectedEntry;
|
||||
|
||||
public CommandHelp(CommandManager manager, RootCommand rootCommand, CommandIssuer issuer) {
|
||||
this.manager = manager;
|
||||
this.issuer = issuer;
|
||||
this.perPage = manager.defaultHelpPerPage;
|
||||
this.commandName = manager.getCommandPrefix(issuer) + rootCommand.getCommandName();
|
||||
|
||||
SetMultimap<String, RegisteredCommand> subCommands = rootCommand.getSubCommands();
|
||||
Set<RegisteredCommand> seen = new HashSet<>();
|
||||
subCommands.entries().forEach(e -> {
|
||||
String key = e.getKey();
|
||||
if (key.equals(BaseCommand.DEFAULT) || key.equals(BaseCommand.CATCHUNKNOWN)){
|
||||
if (key.equals(BaseCommand.DEFAULT) || key.equals(BaseCommand.CATCHUNKNOWN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,15 +106,26 @@ public class CommandHelp {
|
||||
return manager;
|
||||
}
|
||||
|
||||
public boolean isExactMatch(String command) {
|
||||
for (HelpEntry helpEntry : helpEntries) {
|
||||
if (helpEntry.getCommand().endsWith(" " + command)) {
|
||||
selectedEntry = helpEntry;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void showHelp() {
|
||||
showHelp(issuer, MessageKeys.HELP_FORMAT);
|
||||
showHelp(issuer);
|
||||
}
|
||||
|
||||
public void showHelp(CommandIssuer issuer) {
|
||||
showHelp(issuer, MessageKeys.HELP_FORMAT);
|
||||
}
|
||||
if (selectedEntry != null) {
|
||||
showDetailedHelp(selectedEntry, issuer);
|
||||
return;
|
||||
}
|
||||
|
||||
public void showHelp(CommandIssuer issuer, MessageKeyProvider format) {
|
||||
List<HelpEntry> helpEntries = getHelpEntries();
|
||||
Iterator<HelpEntry> results = helpEntries.stream()
|
||||
.filter(HelpEntry::shouldShow)
|
||||
@@ -122,14 +136,21 @@ public class CommandHelp {
|
||||
results = helpEntries.iterator();
|
||||
}
|
||||
int totalResults = helpEntries.size();
|
||||
int min = (this.page-1) * this.perPage; // TODO: per page configurable?
|
||||
int min = (this.page - 1) * this.perPage; // TODO: per page configurable?
|
||||
int max = min + this.perPage;
|
||||
int totalPages = (int) Math.ceil((float) totalResults / (float) this.perPage);
|
||||
int i = 0;
|
||||
if (min >= totalResults) {
|
||||
issuer.sendMessage(MessageType.HELP, MessageKeys.HELP_NO_RESULTS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (search == null) {
|
||||
manager.getHelpFormatter().printHelpHeader(issuer, commandName, page, totalPages, totalResults);
|
||||
} else {
|
||||
manager.getHelpFormatter().printSearchHeader(issuer, commandName, page, totalPages, totalResults, search);
|
||||
}
|
||||
|
||||
while (results.hasNext()) {
|
||||
HelpEntry e = results.next();
|
||||
if (i >= max) {
|
||||
@@ -139,34 +160,39 @@ public class CommandHelp {
|
||||
continue;
|
||||
}
|
||||
|
||||
String formatted = this.manager.formatMessage(issuer, MessageType.HELP, format, getFormatReplacements(e));
|
||||
for (String msg : ACFPatterns.NEWLINE.split(formatted)) {
|
||||
issuer.sendMessageInternal(ACFUtil.rtrim(msg));
|
||||
if (search == null) {
|
||||
manager.getHelpFormatter().printHelpLine(issuer, commandName, e);
|
||||
} else {
|
||||
manager.getHelpFormatter().printSearchLine(issuer, commandName, e, e.getSearchScore());
|
||||
}
|
||||
}
|
||||
if (min > 0 || results.hasNext()) {
|
||||
issuer.sendMessage(MessageType.HELP, MessageKeys.HELP_PAGE_INFORMATION,
|
||||
"{page}", "" + this.page,
|
||||
"{totalpages}", ""+ (int)Math.ceil((float)totalResults / (float)this.perPage),
|
||||
"{results}", "" + totalResults
|
||||
);
|
||||
|
||||
boolean lastPage = !(min > 0 || results.hasNext());
|
||||
if (search == null) {
|
||||
manager.getHelpFormatter().printHelpFooter(issuer, commandName, page, totalPages, totalResults, lastPage);
|
||||
} else {
|
||||
manager.getHelpFormatter().printSearchFooter(issuer, commandName, page, totalPages, totalResults, search, lastPage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this to control replacements
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
@NotNull
|
||||
public String[] getFormatReplacements(HelpEntry e) {
|
||||
//{command} {parameters} {separator} {description}
|
||||
return new String[] {
|
||||
"{command}", e.getCommand(),
|
||||
"{parameters}", e.getParameterSyntax(),
|
||||
"{separator}", e.getDescription().isEmpty() ? "" : "-",
|
||||
"{description}", e.getDescription()
|
||||
};
|
||||
public void showDetailedHelp(HelpEntry entry, CommandIssuer issuer) {
|
||||
// header
|
||||
CommandHelpFormatter formatter = manager.getHelpFormatter();
|
||||
formatter.printDetailedHelpHeader(issuer, commandName, entry);
|
||||
|
||||
// normal help line
|
||||
formatter.printHelpLine(issuer, commandName, entry);
|
||||
|
||||
// additionally detailed help for params
|
||||
for (CommandParameter param : entry.getParameters()) {
|
||||
String description = param.getDescription();
|
||||
if (description != null && !description.isEmpty()) {
|
||||
formatter.printDetailedHelpLine(issuer, commandName, entry, param.getName(), description);
|
||||
}
|
||||
}
|
||||
|
||||
// footer
|
||||
formatter.printDetailedHelpFooter(issuer, commandName, entry);
|
||||
}
|
||||
|
||||
public List<HelpEntry> getHelpEntries() {
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2018 Daniel Ennis (Aikar) - MIT License
|
||||
*
|
||||
* 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 co.aikar.commands;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CommandHelpFormatter {
|
||||
|
||||
private final CommandManager manager;
|
||||
|
||||
public CommandHelpFormatter(CommandManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
// ########
|
||||
// # help #
|
||||
// ########
|
||||
|
||||
public void printHelpHeader(CommandIssuer issuer, String command, int page, int totalPages, int totalResults) {
|
||||
issuer.sendMessage(MessageType.HELP, MessageKeys.HELP_HEADER,
|
||||
"{page}", "" + page,
|
||||
"{totalpages}", "" + totalPages,
|
||||
"{results}", "" + totalResults,
|
||||
"{command}", "" + command
|
||||
);
|
||||
}
|
||||
|
||||
public void printHelpLine(CommandIssuer issuer, String command, HelpEntry page) {
|
||||
String formatted = this.manager.formatMessage(issuer, MessageType.HELP, MessageKeys.HELP_FORMAT, getFormatReplacements(page, command));
|
||||
for (String msg : ACFPatterns.NEWLINE.split(formatted)) {
|
||||
issuer.sendMessageInternal(ACFUtil.rtrim(msg));
|
||||
}
|
||||
}
|
||||
|
||||
public void printHelpFooter(CommandIssuer issuer, String command, int page, int totalPages, int totalResults, boolean lastPage) {
|
||||
if (lastPage) {
|
||||
return;
|
||||
}
|
||||
issuer.sendMessage(MessageType.HELP, MessageKeys.HELP_PAGE_INFORMATION,
|
||||
"{page}", "" + page,
|
||||
"{totalpages}", "" + totalPages,
|
||||
"{results}", "" + totalResults,
|
||||
"{command}", "" + command
|
||||
);
|
||||
}
|
||||
|
||||
// ##########
|
||||
// # search #
|
||||
// ##########
|
||||
|
||||
public void printSearchHeader(CommandIssuer issuer, String command, int page, int totalPages, int totalResults, List<String> search) {
|
||||
issuer.sendMessage(MessageType.HELP, MessageKeys.HELP_SEARCH_HEADER, getPaginationFormatReplacements(command, page, totalPages, totalResults, search));
|
||||
}
|
||||
|
||||
public void printSearchLine(CommandIssuer issuer, String command, HelpEntry page, int score) {
|
||||
String formatted = this.manager.formatMessage(issuer, MessageType.HELP, MessageKeys.HELP_FORMAT, getFormatReplacements(page, command));
|
||||
for (String msg : ACFPatterns.NEWLINE.split(formatted)) {
|
||||
issuer.sendMessageInternal(ACFUtil.rtrim(msg));
|
||||
}
|
||||
}
|
||||
|
||||
public void printSearchFooter(CommandIssuer issuer, String command, int page, int totalPages, int totalResults, List<String> search, boolean lastPage) {
|
||||
if (lastPage) {
|
||||
return;
|
||||
}
|
||||
issuer.sendMessage(MessageType.HELP, MessageKeys.HELP_PAGE_INFORMATION, getPaginationFormatReplacements(command, page, totalPages, totalResults, search)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// ############
|
||||
// # detailed #
|
||||
// ############
|
||||
|
||||
public void printDetailedHelpHeader(CommandIssuer issuer, String command, HelpEntry entry) {
|
||||
issuer.sendMessage(MessageType.HELP, MessageKeys.HELP_DETAILED_HEADER,
|
||||
"{command}", entry.getCommand(),
|
||||
"{command}", command
|
||||
);
|
||||
}
|
||||
|
||||
public void printDetailedHelpLine(CommandIssuer issuer, String rootCommand, HelpEntry entry, String subCommand, String paramDescription) {
|
||||
String formattedMsg = this.manager.formatMessage(issuer, MessageType.HELP, MessageKeys.HELP_DETAILED_FORMAT, getDetailedFormatReplacements(subCommand, paramDescription, entry, rootCommand));
|
||||
for (String msg : ACFPatterns.NEWLINE.split(formattedMsg)) {
|
||||
issuer.sendMessageInternal(ACFUtil.rtrim(msg));
|
||||
}
|
||||
}
|
||||
|
||||
public void printDetailedHelpFooter(CommandIssuer issuer, String command, HelpEntry page) {
|
||||
// default doesn't have a footer
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String[] getPaginationFormatReplacements(String command, int page, int totalPages, int totalResults, List<String> search) {
|
||||
return new String[]{
|
||||
"{search}", String.join(" ", search),
|
||||
"{command}", command,
|
||||
"{rootcommand}", command,
|
||||
"{page}", "" + page,
|
||||
"{totalpages}", "" + totalPages,
|
||||
"{results}", "" + totalResults
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this to control replacements
|
||||
*
|
||||
* @param e
|
||||
* @param command
|
||||
* @return
|
||||
*/
|
||||
public String[] getFormatReplacements(HelpEntry e, String command) {
|
||||
//{command} {parameters} {separator} {description}
|
||||
return new String[]{
|
||||
"{command}", e.getCommand(),
|
||||
"{rootcommand}", command,
|
||||
"{parameters}", e.getParameterSyntax(),
|
||||
"{separator}", e.getDescription().isEmpty() ? "" : "-",
|
||||
"{description}", e.getDescription()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this to control replacements
|
||||
*
|
||||
* @param name
|
||||
* @param description
|
||||
* @param page
|
||||
* @param rootCommand
|
||||
* @return
|
||||
*/
|
||||
@NotNull
|
||||
public String[] getDetailedFormatReplacements(String name, String description, HelpEntry page, String rootCommand) {
|
||||
//{name} {description}
|
||||
return new String[]{
|
||||
"{name}", name,
|
||||
"{command}", page.getCommand(),
|
||||
"{rootcommand}", rootCommand,
|
||||
"{description}", description
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,7 @@ public abstract class CommandManager <
|
||||
protected final CommandConditions<I, CEC, CC> conditions = new CommandConditions<>(this);
|
||||
protected ExceptionHandler defaultExceptionHandler = null;
|
||||
protected Table<Class<?>, String, Object> dependencies = HashBasedTable.create();
|
||||
protected CommandHelpFormatter helpFormatter = new CommandHelpFormatter(this);
|
||||
|
||||
protected boolean usePerIssuerLocale = false;
|
||||
protected List<IssuerLocaleChangedCallback<I>> localeChangedCallbacks = Lists.newArrayList();
|
||||
@@ -188,6 +189,15 @@ public abstract class CommandManager <
|
||||
verifyUnstableAPI("help");
|
||||
this.defaultHelpPerPage = defaultHelpPerPage;
|
||||
}
|
||||
/** @deprecated Unstable API */ @Deprecated @UnstableAPI
|
||||
public void setHelpFormatter(CommandHelpFormatter helpFormatter) {
|
||||
this.helpFormatter = helpFormatter;
|
||||
}
|
||||
|
||||
/** @deprecated Unstable API */ @Deprecated @UnstableAPI
|
||||
public CommandHelpFormatter getHelpFormatter() {
|
||||
return helpFormatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a command with ACF
|
||||
@@ -494,4 +504,8 @@ public abstract class CommandManager <
|
||||
Annotations getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
public String getCommandPrefix(CommandIssuer issuer) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
|
||||
package co.aikar.commands;
|
||||
|
||||
import co.aikar.commands.annotation.HelpSearchTags;
|
||||
|
||||
public class HelpEntry {
|
||||
|
||||
private final RegisteredCommand command;
|
||||
@@ -38,7 +36,6 @@ public class HelpEntry {
|
||||
return this.command;
|
||||
}
|
||||
|
||||
|
||||
public String getCommand(){
|
||||
return "/" + this.command.command;
|
||||
}
|
||||
@@ -66,4 +63,8 @@ public class HelpEntry {
|
||||
public String getSearchTags() {
|
||||
return command.helpSearchTags;
|
||||
}
|
||||
|
||||
public CommandParameter[] getParameters() {
|
||||
return command.parameters;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,10 +46,14 @@ public enum MessageKeys implements MessageKeyProvider {
|
||||
PLEASE_SPECIFY_AT_MOST,
|
||||
NOT_ALLOWED_ON_CONSOLE,
|
||||
COULD_NOT_FIND_PLAYER,
|
||||
HELP_FORMAT,
|
||||
NO_COMMAND_MATCHED_SEARCH,
|
||||
HELP_PAGE_INFORMATION,
|
||||
HELP_NO_RESULTS
|
||||
HELP_NO_RESULTS,
|
||||
HELP_HEADER,
|
||||
HELP_FORMAT,
|
||||
HELP_DETAILED_HEADER,
|
||||
HELP_DETAILED_FORMAT,
|
||||
HELP_SEARCH_HEADER,
|
||||
;
|
||||
|
||||
private final MessageKey key = MessageKey.of("acf-core." + this.name().toLowerCase());
|
||||
|
||||
@@ -220,13 +220,7 @@ public class JDACommandManager extends CommandManager<
|
||||
Message message = event.getMessage();
|
||||
String msg = message.getContentDisplay();
|
||||
|
||||
CommandConfig config = this.defaultConfig;
|
||||
if (this.configProvider != null) {
|
||||
CommandConfig provided = this.configProvider.provide(event);
|
||||
if (provided != null) {
|
||||
config = provided;
|
||||
}
|
||||
}
|
||||
CommandConfig config = getCommandConfig(event);
|
||||
|
||||
String prefixFound = null;
|
||||
for (String prefix : config.getCommandPrefixes()) {
|
||||
@@ -255,4 +249,24 @@ public class JDACommandManager extends CommandManager<
|
||||
}
|
||||
rootCommand.execute(this.getCommandIssuer(event), cmd, args);
|
||||
}
|
||||
|
||||
private CommandConfig getCommandConfig(MessageReceivedEvent event) {
|
||||
CommandConfig config = this.defaultConfig;
|
||||
if (this.configProvider != null) {
|
||||
CommandConfig provided = this.configProvider.provide(event);
|
||||
if (provided != null) {
|
||||
config = provided;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getCommandPrefix(CommandIssuer issuer) {
|
||||
MessageReceivedEvent event = ((JDACommandEvent) issuer).getEvent();
|
||||
CommandConfig commandConfig = getCommandConfig(event);
|
||||
List<String> prefixes = commandConfig.getCommandPrefixes();
|
||||
return prefixes.isEmpty() ? "" : prefixes.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,11 @@ acf-core.please_specify_at_most = Error: Please specify a value at most {max}.
|
||||
acf-core.please_specify_at_least = Error: Please specify a value at least {min}.
|
||||
acf-core.not_allowed_on_console = Error: Console may not execute this command.
|
||||
acf-core.could_not_find_player = Error: Could not find a player by the name: <c2>{search}</c2>
|
||||
acf-core.help_format = <c1>{command}</c1> <c2>{parameters}</c2> <c3>{separator} {description}</c3>
|
||||
acf-core.no_command_matched_search = No command matched <c2>{search}</c2>.
|
||||
acf-core.help_page_information = - Showing page <c2>{page}</c2> of <c2>{totalpages}</c2> (<c3>{results}</c3> results).
|
||||
acf-core.help_no_results = Error: No more results.
|
||||
acf-core.help_header = <c3>=== </c3><c1>Showing help for </c1><c2>{command}</c2><c3> ===</c3>
|
||||
acf-core.help_format = <c1>{command}</c1> <c2>{parameters}</c2> <c3>{separator} {description}</c3>
|
||||
acf-core.help_detailed_header = <c3>=== </c3><c1>Showing detailed help for </c1><c2>{command}</c2><c3> ===</c3>
|
||||
acf-core.help_detailed_format = <c2>{name}</c2>: <c3>{description}</c3>
|
||||
acf-core.help_search_header = <c3>=== </c3><c1>Showing help for </c1><c2>{command}</c2> <c1>{search}</c1><c3> ===</c3>
|
||||
|
||||
@@ -197,4 +197,9 @@ public class SpongeCommandManager extends CommandManager<
|
||||
public SpongeConditionContext createConditionContext(CommandIssuer issuer, String config) {
|
||||
return new SpongeConditionContext((SpongeCommandIssuer) issuer, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandPrefix(CommandIssuer issuer) {
|
||||
return issuer.isPlayer() ? "/" : "";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user