mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-09-19 13:58:22 +00:00
234 lines
12 KiB
Java
234 lines
12 KiB
Java
|
package com.sk89q.worldedit.command;
|
||
|
|
||
|
import com.boydti.fawe.config.BBC;
|
||
|
import com.boydti.fawe.util.StringMan;
|
||
|
import com.google.common.base.Joiner;
|
||
|
import com.sk89q.minecraft.util.commands.Command;
|
||
|
import com.sk89q.minecraft.util.commands.CommandContext;
|
||
|
import com.sk89q.worldedit.WorldEdit;
|
||
|
import com.sk89q.worldedit.extension.platform.CommandManager;
|
||
|
import com.sk89q.worldedit.util.command.*;
|
||
|
import com.sk89q.worldedit.util.command.parametric.AParametricCallable;
|
||
|
|
||
|
import java.util.*;
|
||
|
|
||
|
public abstract class HelpBuilder implements Runnable {
|
||
|
private final CommandCallable callable;
|
||
|
private final CommandContext args;
|
||
|
private final String prefix;
|
||
|
private final int perPage;
|
||
|
|
||
|
public HelpBuilder(CommandCallable callable, CommandContext args, final String prefix, int perPage) {
|
||
|
if (callable == null) {
|
||
|
callable = WorldEdit.getInstance().getPlatformManager().getCommandManager().getDispatcher();
|
||
|
}
|
||
|
this.callable = callable;
|
||
|
this.args = args;
|
||
|
this.prefix = prefix;
|
||
|
this.perPage = perPage;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void run() {
|
||
|
try {
|
||
|
CommandCallable callable = this.callable;
|
||
|
int page = -1;
|
||
|
String category = null;
|
||
|
int effectiveLength = args.argsLength();
|
||
|
|
||
|
// Detect page from args
|
||
|
try {
|
||
|
if (effectiveLength > 0) {
|
||
|
page = args.getInteger(args.argsLength() - 1);
|
||
|
if (page <= 0) {
|
||
|
page = 1;
|
||
|
} else {
|
||
|
page--;
|
||
|
}
|
||
|
effectiveLength--;
|
||
|
}
|
||
|
} catch (Exception ignored) {
|
||
|
}
|
||
|
|
||
|
boolean isRootLevel = true;
|
||
|
List<String> visited = new ArrayList<String>();
|
||
|
|
||
|
// Create the message
|
||
|
if (callable instanceof Dispatcher) {
|
||
|
Dispatcher dispatcher = (Dispatcher) callable;
|
||
|
|
||
|
// Get a list of aliases
|
||
|
List<CommandMapping> aliases = new ArrayList<CommandMapping>(dispatcher.getCommands());
|
||
|
List<String> prefixes = Collections.nCopies(aliases.size(), "");
|
||
|
// Group by callable
|
||
|
|
||
|
if (page == -1 || effectiveLength > 0) {
|
||
|
Map<String, Map<CommandMapping, String>> grouped = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||
|
for (CommandMapping mapping : aliases) {
|
||
|
CommandCallable c = mapping.getCallable();
|
||
|
String group;
|
||
|
if (c instanceof DelegateCallable) {
|
||
|
c = ((DelegateCallable) c).getParent();
|
||
|
}
|
||
|
if (c instanceof AParametricCallable) {
|
||
|
Command command = ((AParametricCallable) c).getCommand();
|
||
|
if (command != null && command.aliases().length != 0) {
|
||
|
group = command.aliases()[0];
|
||
|
} else {
|
||
|
group = ((AParametricCallable) c).getGroup();
|
||
|
}
|
||
|
} else if (c instanceof Dispatcher) {
|
||
|
group = mapping.getPrimaryAlias();
|
||
|
} else {
|
||
|
group = "Unsorted";
|
||
|
}
|
||
|
group = group.replace("/", "");
|
||
|
group = StringMan.toProperCase(group);
|
||
|
Map<CommandMapping, String> queue = grouped.get(group);
|
||
|
if (queue == null) {
|
||
|
queue = new LinkedHashMap<>();
|
||
|
grouped.put(group, queue);
|
||
|
}
|
||
|
if (c instanceof Dispatcher) {
|
||
|
for (CommandMapping m : ((Dispatcher) c).getCommands()) {
|
||
|
queue.put(m, mapping.getPrimaryAlias() + " ");
|
||
|
}
|
||
|
} else {
|
||
|
// Sub commands get priority
|
||
|
queue.putIfAbsent(mapping, "");
|
||
|
}
|
||
|
}
|
||
|
if (effectiveLength > 0) {
|
||
|
String cat = args.getString(0);
|
||
|
Map<CommandMapping, String> mappings = effectiveLength == 1 ? grouped.get(cat) : null;
|
||
|
if (mappings == null) {
|
||
|
// Drill down to the command
|
||
|
for (int i = 0; i < effectiveLength; i++) {
|
||
|
String command = args.getString(i);
|
||
|
|
||
|
if (callable instanceof Dispatcher) {
|
||
|
// Chop off the beginning / if we're are the root level
|
||
|
if (isRootLevel && command.length() > 1 && command.charAt(0) == '/') {
|
||
|
command = command.substring(1);
|
||
|
}
|
||
|
|
||
|
CommandMapping mapping = UtilityCommands.detectCommand((Dispatcher) callable, command, isRootLevel);
|
||
|
if (mapping != null) {
|
||
|
callable = mapping.getCallable();
|
||
|
} else {
|
||
|
if (isRootLevel) {
|
||
|
Set<String> found = new HashSet<>();
|
||
|
String arg = args.getString(i).toLowerCase();
|
||
|
String closest = null;
|
||
|
int distance = Integer.MAX_VALUE;
|
||
|
for (CommandMapping map : aliases) {
|
||
|
String desc = map.getDescription().getDescription();
|
||
|
if (desc == null) desc = map.getDescription().getHelp();
|
||
|
if (desc == null) desc = "";
|
||
|
String[] descSplit = desc.replaceAll("[^A-Za-z0-9]", "").toLowerCase().split(" ");
|
||
|
for (String alias : map.getAllAliases()) {
|
||
|
if (alias.equals(arg)) {
|
||
|
closest = map.getPrimaryAlias();
|
||
|
distance = 0;
|
||
|
found.add(map.getPrimaryAlias());
|
||
|
} else if (alias.contains(arg)) {
|
||
|
closest = map.getPrimaryAlias();
|
||
|
distance = 1;
|
||
|
found.add(map.getPrimaryAlias());
|
||
|
} else if (StringMan.isEqualIgnoreCaseToAny(arg, descSplit)) {
|
||
|
closest = map.getPrimaryAlias();
|
||
|
distance = 1;
|
||
|
found.add(map.getPrimaryAlias());
|
||
|
} else {
|
||
|
int currentDist = StringMan.getLevenshteinDistance(alias, arg);
|
||
|
if (currentDist < distance) {
|
||
|
distance = currentDist;
|
||
|
closest = map.getPrimaryAlias();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
found.add(closest);
|
||
|
displayFailure(BBC.HELP_SUGGEST.f(arg, StringMan.join(found, ", ")));
|
||
|
return;
|
||
|
} else {
|
||
|
String msg = String.format("The sub-command '%s' under '%s' could not be found.",
|
||
|
command, Joiner.on(" ").join(visited));
|
||
|
displayFailure(msg);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
visited.add(args.getString(i));
|
||
|
isRootLevel = false;
|
||
|
} else {
|
||
|
String msg = String.format("'%s' has no sub-commands. (Maybe '%s' is for a parameter?)",
|
||
|
Joiner.on(" ").join(visited), command);
|
||
|
displayFailure(msg);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
if (!(callable instanceof Dispatcher)) {
|
||
|
// TODO interactive box
|
||
|
String cmd = (WorldEdit.getInstance().getConfiguration().noDoubleSlash ? "" : "/") + Joiner.on(" ").join(visited);
|
||
|
displayUsage(callable, cmd);
|
||
|
return;
|
||
|
}
|
||
|
dispatcher = (Dispatcher) callable;
|
||
|
aliases = new ArrayList<CommandMapping>(dispatcher.getCommands());
|
||
|
prefixes = Collections.nCopies(aliases.size(), "");
|
||
|
} else {
|
||
|
aliases = new ArrayList<>();
|
||
|
prefixes = new ArrayList<>();
|
||
|
for (Map.Entry<CommandMapping, String> entry : mappings.entrySet()) {
|
||
|
aliases.add(entry.getKey());
|
||
|
prefixes.add(entry.getValue());
|
||
|
}
|
||
|
}
|
||
|
page = Math.max(0, page);
|
||
|
} else if (grouped.size() > 1) {
|
||
|
displayCategories(grouped);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
// else
|
||
|
{
|
||
|
Collections.sort(aliases, new PrimaryAliasComparator(CommandManager.COMMAND_CLEAN_PATTERN));
|
||
|
|
||
|
// Calculate pagination
|
||
|
int offset = perPage * Math.max(0, page);
|
||
|
int pageTotal = (int) Math.ceil(aliases.size() / (double) perPage);
|
||
|
|
||
|
// Box
|
||
|
if (offset >= aliases.size()) {
|
||
|
displayFailure(String.format("There is no page %d (total number of pages is %d).", page + 1, pageTotal));
|
||
|
} else {
|
||
|
int end = Math.min(offset + perPage, aliases.size());
|
||
|
List<CommandMapping> subAliases = aliases.subList(offset, end);
|
||
|
List<String> subPrefixes = prefixes.subList(offset, end);
|
||
|
Map<CommandMapping, String> commandMap = new LinkedHashMap<>();
|
||
|
for (int i = 0; i < subAliases.size(); i++) {
|
||
|
commandMap.put(subAliases.get(i), subPrefixes.get(i));
|
||
|
}
|
||
|
String visitedString = Joiner.on(" ").join(visited);
|
||
|
displayCommands(commandMap, visitedString, page, pageTotal, effectiveLength);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
String cmd = (WorldEdit.getInstance().getConfiguration().noDoubleSlash ? "" : "/") + Joiner.on(" ").join(visited);
|
||
|
displayUsage(callable, cmd);
|
||
|
}
|
||
|
} catch (Throwable e) {
|
||
|
e.printStackTrace();
|
||
|
throw new RuntimeException(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public abstract void displayFailure(String message);
|
||
|
|
||
|
public abstract void displayUsage(CommandCallable callable, String command);
|
||
|
|
||
|
public abstract void displayCategories(Map<String, Map<CommandMapping, String>> categories);
|
||
|
|
||
|
public abstract void displayCommands(Map<CommandMapping, String> commandMap, String visited, int page, int pageTotal, int effectiveLength);
|
||
|
}
|