Streamline command help a little bit
This commit is contained in:
@@ -5,6 +5,7 @@ import io.dico.dicore.command.parameter.ArgumentBuffer;
|
||||
import io.dico.dicore.command.predef.PredefinedCommand;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -109,6 +110,23 @@ public interface ICommandAddress {
|
||||
*/
|
||||
boolean isDepthLargerThan(int depth);
|
||||
|
||||
/**
|
||||
* @return true if this address has any children.
|
||||
*/
|
||||
boolean hasChildren();
|
||||
|
||||
/**
|
||||
* @return total number of children, not considering any aliases
|
||||
*/
|
||||
int getNumberOfRealChildren();
|
||||
|
||||
/**
|
||||
* Get an unmodifiable view of all main keys of the children of this address.
|
||||
*
|
||||
* @return the main keys
|
||||
*/
|
||||
Collection<String> getChildrenMainKeys();
|
||||
|
||||
/**
|
||||
* Get an unmodifiable view of the children of this address.
|
||||
* Values might be duplicated for aliases.
|
||||
|
||||
@@ -10,10 +10,13 @@ import java.util.*;
|
||||
|
||||
public abstract class ModifiableCommandAddress implements ICommandAddress {
|
||||
Map<String, ChildCommandAddress> children;
|
||||
Collection<String> childrenMainKeys = Collections.emptyList();
|
||||
|
||||
// the chat controller as configured by the programmer
|
||||
IChatController chatController;
|
||||
// cache for the algorithm that finds the first chat controller going up the tree
|
||||
transient IChatController chatControllerCache;
|
||||
|
||||
ModifiableCommandAddress helpChild;
|
||||
|
||||
public ModifiableCommandAddress() {
|
||||
@@ -110,6 +113,21 @@ public abstract class ModifiableCommandAddress implements ICommandAddress {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasChildren() {
|
||||
return !children.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfRealChildren() {
|
||||
return childrenMainKeys.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getChildrenMainKeys() {
|
||||
return Collections.unmodifiableCollection(childrenMainKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends ModifiableCommandAddress> getChildren() {
|
||||
return Collections.unmodifiableMap(children);
|
||||
@@ -140,7 +158,16 @@ public abstract class ModifiableCommandAddress implements ICommandAddress {
|
||||
}
|
||||
|
||||
Iterator<String> names = mChild.modifiableNamesIterator();
|
||||
children.put(names.next(), mChild);
|
||||
String mainKey = names.next();
|
||||
|
||||
if (!childrenMainKeys.contains(mainKey)) {
|
||||
if (!(childrenMainKeys instanceof ArrayList)) {
|
||||
childrenMainKeys = new ArrayList<>();
|
||||
}
|
||||
childrenMainKeys.add(mainKey);
|
||||
}
|
||||
|
||||
children.put(mainKey, mChild);
|
||||
|
||||
while (names.hasNext()) {
|
||||
String name = names.next();
|
||||
@@ -168,21 +195,31 @@ public abstract class ModifiableCommandAddress implements ICommandAddress {
|
||||
}
|
||||
|
||||
if (removeAliases) {
|
||||
for (Iterator<String> iterator = keyTarget.namesModifiable.iterator(); iterator.hasNext(); ) {
|
||||
Iterator<String> iterator = keyTarget.namesModifiable.iterator();
|
||||
boolean first = true;
|
||||
while (iterator.hasNext()) {
|
||||
String alias = iterator.next();
|
||||
ChildCommandAddress aliasTarget = getChild(key);
|
||||
if (aliasTarget == keyTarget) {
|
||||
if (first) {
|
||||
childrenMainKeys.remove(alias);
|
||||
}
|
||||
children.remove(alias);
|
||||
}
|
||||
iterator.remove();
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
} else {
|
||||
if (key.equals(keyTarget.getMainKey())) {
|
||||
childrenMainKeys.remove(key);
|
||||
}
|
||||
|
||||
children.remove(key);
|
||||
keyTarget.namesModifiable.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasHelpCommand() {
|
||||
return helpChild != null;
|
||||
|
||||
@@ -217,9 +217,14 @@ public class RootCommandAddress extends ModifiableCommandAddress implements ICom
|
||||
|
||||
try {
|
||||
ICommandAddress target = getCommandTarget(context, buffer);
|
||||
List<String> out = target.hasCommand()
|
||||
? target.getCommand().tabComplete(sender, target, location, buffer.getUnaffectingCopy())
|
||||
: Collections.emptyList();
|
||||
|
||||
List<String> out;
|
||||
if (target.hasCommand()) {
|
||||
context.targetAcquired(target, target.getCommand(), buffer);
|
||||
out = target.getCommand().tabCompleteWithContext(context, location);
|
||||
} else {
|
||||
out = Collections.emptyList();
|
||||
}
|
||||
|
||||
int cursor = buffer.getCursor();
|
||||
String input;
|
||||
@@ -230,7 +235,7 @@ public class RootCommandAddress extends ModifiableCommandAddress implements ICom
|
||||
}
|
||||
|
||||
boolean wrapped = false;
|
||||
for (String child : target.getChildren().keySet()) {
|
||||
for (String child : target.getChildrenMainKeys()) {
|
||||
if (child.toLowerCase().startsWith(input)) {
|
||||
if (!wrapped) {
|
||||
out = new ArrayList<>(out);
|
||||
|
||||
@@ -88,7 +88,7 @@ public class AbstractChatController implements IChatController {
|
||||
case DESCRIPTION:
|
||||
return Formatting.GREEN;
|
||||
case SYNTAX:
|
||||
return Formatting.BLUE;
|
||||
return Formatting.AQUA;
|
||||
case HIGHLIGHT:
|
||||
return Formatting.RED;
|
||||
case SUBCOMMAND:
|
||||
|
||||
@@ -82,7 +82,7 @@ public class HelpPages {
|
||||
}
|
||||
|
||||
public @NotNull String getSyntax(Permissible viewer, ExecutionContext context, ICommandAddress address) {
|
||||
List<IHelpComponent> components = syntaxTopic.getComponents(address, viewer, context);
|
||||
List<IHelpComponent> components = syntaxTopic.getComponents(address, viewer, context, false);
|
||||
if (components.isEmpty()) {
|
||||
return getHelpPage(viewer, context, address, 1);
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ public abstract class HelpTopicModifier implements IHelpTopic {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context) {
|
||||
return modify(delegate.getComponents(target, viewer, context), target, viewer, context);
|
||||
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) {
|
||||
return modify(delegate.getComponents(target, viewer, context, true), target, viewer, context);
|
||||
}
|
||||
|
||||
protected abstract List<IHelpComponent> modify(List<IHelpComponent> components, ICommandAddress target, Permissible viewer, ExecutionContext context);
|
||||
|
||||
@@ -14,9 +14,10 @@ public interface IHelpTopic {
|
||||
* @param target The address of the command to provide help about
|
||||
* @param viewer The permissible that the page will be shown to (null -> choose a default set).
|
||||
* @param context Context of the command execution
|
||||
* @param isForPage A boolean indicating if the components are to be used in a page (for help)
|
||||
* @return a mutable list of components to include in the help pages
|
||||
*/
|
||||
List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context);
|
||||
List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public class DefaultPageBuilder implements IPageBuilder {
|
||||
|
||||
List<IHelpComponent> components = new LinkedList<>();
|
||||
for (IHelpTopic topic : helpTopics) {
|
||||
components.addAll(topic.getComponents(target, viewer, context));
|
||||
components.addAll(topic.getComponents(target, viewer, context, true));
|
||||
}
|
||||
|
||||
PageBorders pageBorders = null;
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.List;
|
||||
public class DescriptionHelpTopic implements IHelpTopic {
|
||||
|
||||
@Override
|
||||
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context) {
|
||||
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) {
|
||||
List<IHelpComponent> out = new ArrayList<>();
|
||||
Formatting format = context.getFormat(EMessageType.DESCRIPTION);
|
||||
|
||||
|
||||
@@ -11,29 +11,31 @@ import io.dico.dicore.command.predef.PredefinedCommand;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
public class SubcommandsHelpTopic implements IHelpTopic {
|
||||
|
||||
@Override
|
||||
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context) {
|
||||
List<IHelpComponent> out = new ArrayList<>();
|
||||
Map<String, ? extends ICommandAddress> children = target.getChildren();
|
||||
if (children.isEmpty()) {
|
||||
//System.out.println("No subcommands");
|
||||
return out;
|
||||
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) {
|
||||
Collection<String> mainKeys = target.getChildrenMainKeys();
|
||||
if (mainKeys.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<IHelpComponent> result = new ArrayList<>();
|
||||
|
||||
mainKeys = new ArrayList<>(target.getChildrenMainKeys());
|
||||
((ArrayList<String>) mainKeys).sort(null);
|
||||
|
||||
CommandSender sender = viewer instanceof CommandSender ? (CommandSender) viewer : context.getSender();
|
||||
children.values().stream().distinct().forEach(child -> {
|
||||
if ((!child.hasCommand() || child.getCommand().isVisibleTo(sender)) && !(child instanceof PredefinedCommand)) {
|
||||
out.add(getComponent(child, viewer, context));
|
||||
for (String key : mainKeys) {
|
||||
ICommandAddress child = target.getChild(key);
|
||||
if ((child.hasChildren() || child.hasUserDeclaredCommand()) && child.getCommand().isVisibleTo(sender)) {
|
||||
result.add(getComponent(child, viewer, context));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return out;
|
||||
return result;
|
||||
}
|
||||
|
||||
public IHelpComponent getComponent(ICommandAddress child, Permissible viewer, ExecutionContext context) {
|
||||
|
||||
@@ -19,56 +19,74 @@ import java.util.Map;
|
||||
public class SyntaxHelpTopic implements IHelpTopic {
|
||||
|
||||
@Override
|
||||
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context) {
|
||||
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) {
|
||||
if (!target.hasCommand()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String line = context.getFormat(EMessageType.SYNTAX) + "Syntax: "
|
||||
+ context.getFormat(EMessageType.INSTRUCTION) + target.getAddress()
|
||||
+ ' ' + getShortSyntax(target, context);
|
||||
|
||||
return Collections.singletonList(new SimpleHelpComponent(line));
|
||||
if (target.hasChildren()) {
|
||||
if (!isForPage) {
|
||||
// HelpPages will send help instead of syntax, which might in turn include syntax as well.
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static String getShortSyntax(ICommandAddress target, ExecutionContext ctx) {
|
||||
StringBuilder syntax = new StringBuilder();
|
||||
if (target.hasCommand()) {
|
||||
if (!target.hasUserDeclaredCommand() && !target.getCommand().getParameterList().hasAnyParameters()) {
|
||||
// no point adding syntax at all
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder line = new StringBuilder();
|
||||
if (isForPage)
|
||||
line.append(context.getFormat(EMessageType.SYNTAX))
|
||||
.append("Syntax: ");
|
||||
|
||||
line.append('/')
|
||||
.append(context.getFormat(EMessageType.INSTRUCTION))
|
||||
.append(target.getAddress())
|
||||
.append(' ');
|
||||
|
||||
addShortSyntax(line, target, context);
|
||||
|
||||
return Collections.singletonList(new SimpleHelpComponent(line.toString()));
|
||||
}
|
||||
|
||||
private static void addShortSyntax(StringBuilder builder, ICommandAddress address, ExecutionContext ctx) {
|
||||
if (address.hasCommand()) {
|
||||
Formatting syntaxColor = ctx.getFormat(EMessageType.SYNTAX);
|
||||
Formatting highlight = ctx.getFormat(EMessageType.HIGHLIGHT);
|
||||
syntax.append(syntaxColor);
|
||||
builder.append(syntaxColor);
|
||||
|
||||
Command command = target.getCommand();
|
||||
Command command = address.getCommand();
|
||||
ParameterList list = command.getParameterList();
|
||||
Parameter<?, ?> repeated = list.getRepeatedParameter();
|
||||
|
||||
int requiredCount = list.getRequiredCount();
|
||||
List<Parameter<?, ?>> indexedParameters = list.getIndexedParameters();
|
||||
for (int i = 0, n = indexedParameters.size(); i < n; i++) {
|
||||
syntax.append(i < requiredCount ? " <" : " [");
|
||||
builder.append(i < requiredCount ? " <" : " [");
|
||||
Parameter<?, ?> param = indexedParameters.get(i);
|
||||
syntax.append(param.getName());
|
||||
builder.append(param.getName());
|
||||
if (param == repeated) {
|
||||
syntax.append(highlight).append("...").append(syntaxColor);
|
||||
builder.append(highlight).append("...").append(syntaxColor);
|
||||
}
|
||||
syntax.append(i < requiredCount ? '>' : ']');
|
||||
builder.append(i < requiredCount ? '>' : ']');
|
||||
}
|
||||
|
||||
Map<String, Parameter<?, ?>> parametersByName = list.getParametersByName();
|
||||
for (Parameter<?, ?> param : parametersByName.values()) {
|
||||
if (param.isFlag()) {
|
||||
syntax.append(" [").append(param.getName());
|
||||
builder.append(" [").append(param.getName());
|
||||
if (param.expectsInput()) {
|
||||
syntax.append(" <").append(param.getName()).append(">");
|
||||
builder.append(" <").append(param.getName()).append(">");
|
||||
}
|
||||
syntax.append(']');
|
||||
builder.append(']');
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
syntax.append(' ');
|
||||
builder.append(' ');
|
||||
}
|
||||
return syntax.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class HelpComponentInserter extends HelpTopicModifier {
|
||||
for (int i = insertions.size() - 1; i >= 0; i--) {
|
||||
IInsertion insertion = insertions.get(i);
|
||||
int idx = insertion.insertionIndex(components, target, viewer, context);
|
||||
List<IHelpComponent> inserted = insertion.getComponents(target, viewer, context);
|
||||
List<IHelpComponent> inserted = insertion.getComponents(target, viewer, context, true);
|
||||
components.addAll(idx, inserted);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ public class Insertions {
|
||||
public static IInsertion combine(IHelpTopic topic, IInsertionFunction function) {
|
||||
return new IInsertion() {
|
||||
@Override
|
||||
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context) {
|
||||
return topic.getComponents(target, viewer, context);
|
||||
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) {
|
||||
return topic.getComponents(target, viewer, context, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -60,6 +60,14 @@ public class ParameterList {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean hasAnyParameters() {
|
||||
return !byName.isEmpty();
|
||||
}
|
||||
|
||||
public int getIndexedParameterCount() {
|
||||
return indexedParameters.size();
|
||||
}
|
||||
|
||||
public List<Parameter<?, ?>> getIndexedParameters() {
|
||||
return Collections.unmodifiableList(indexedParameters);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user