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:
Aikar
2018-03-21 22:05:19 -04:00
11 changed files with 295 additions and 42 deletions
@@ -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);
}
}
+5 -1
View File
@@ -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() ? "/" : "";
}
}