Archived
0

Streamline command help a little bit

This commit is contained in:
Dico
2018-09-27 07:53:58 +01:00
parent 842e52bd92
commit f28e4393db
14 changed files with 148 additions and 59 deletions

View File

@@ -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.

View File

@@ -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;

View File

@@ -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);

View File

@@ -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:

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}