diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java index a42e7a2a3..8c2bdb46f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java @@ -20,72 +20,388 @@ package com.sk89q.worldedit.internal.util; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.io.Files; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.ApplyBrushCommands; +import com.sk89q.worldedit.command.BiomeCommands; +import com.sk89q.worldedit.command.BiomeCommandsRegistration; +import com.sk89q.worldedit.command.BrushCommands; +import com.sk89q.worldedit.command.BrushCommandsRegistration; +import com.sk89q.worldedit.command.ChunkCommands; +import com.sk89q.worldedit.command.ChunkCommandsRegistration; +import com.sk89q.worldedit.command.ClipboardCommands; +import com.sk89q.worldedit.command.ClipboardCommandsRegistration; +import com.sk89q.worldedit.command.ExpandCommands; +import com.sk89q.worldedit.command.GeneralCommands; +import com.sk89q.worldedit.command.GeneralCommandsRegistration; +import com.sk89q.worldedit.command.GenerationCommands; +import com.sk89q.worldedit.command.GenerationCommandsRegistration; +import com.sk89q.worldedit.command.HistoryCommands; +import com.sk89q.worldedit.command.HistoryCommandsRegistration; +import com.sk89q.worldedit.command.NavigationCommands; +import com.sk89q.worldedit.command.NavigationCommandsRegistration; +import com.sk89q.worldedit.command.PaintBrushCommands; +import com.sk89q.worldedit.command.RegionCommands; +import com.sk89q.worldedit.command.RegionCommandsRegistration; +import com.sk89q.worldedit.command.SchematicCommands; +import com.sk89q.worldedit.command.SchematicCommandsRegistration; +import com.sk89q.worldedit.command.ScriptingCommands; +import com.sk89q.worldedit.command.ScriptingCommandsRegistration; +import com.sk89q.worldedit.command.SelectionCommands; +import com.sk89q.worldedit.command.SelectionCommandsRegistration; +import com.sk89q.worldedit.command.SnapshotCommands; +import com.sk89q.worldedit.command.SnapshotCommandsRegistration; +import com.sk89q.worldedit.command.SnapshotUtilCommands; +import com.sk89q.worldedit.command.SnapshotUtilCommandsRegistration; +import com.sk89q.worldedit.command.SuperPickaxeCommands; +import com.sk89q.worldedit.command.SuperPickaxeCommandsRegistration; +import com.sk89q.worldedit.command.ToolCommands; +import com.sk89q.worldedit.command.ToolCommandsRegistration; +import com.sk89q.worldedit.command.ToolUtilCommands; +import com.sk89q.worldedit.command.ToolUtilCommandsRegistration; +import com.sk89q.worldedit.command.UtilityCommands; +import com.sk89q.worldedit.command.UtilityCommandsRegistration; +import com.sk89q.worldedit.command.WorldEditCommands; +import com.sk89q.worldedit.command.WorldEditCommandsRegistration; import com.sk89q.worldedit.command.util.PermissionCondition; -import com.sk89q.worldedit.extension.platform.PlatformCommandManager; -import com.sk89q.worldedit.extension.platform.PlatformManager; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.formatting.text.serializer.ComponentSerializer; import com.sk89q.worldedit.util.formatting.text.serializer.plain.PlainComponentSerializer; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; import org.enginehub.piston.TextConfig; +import org.enginehub.piston.gen.CommandRegistration; +import org.enginehub.piston.impl.CommandManagerImpl; +import org.enginehub.piston.impl.CommandManagerServiceImpl; import org.enginehub.piston.part.SubCommandPart; +import org.enginehub.piston.util.HelpGenerator; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; import java.util.stream.Stream; public final class DocumentationPrinter { - private DocumentationPrinter() { - } - /** * Generates documentation. * * @param args arguments */ - public static void main(String[] args) { - final PlatformManager platformManager = WorldEdit.getInstance().getPlatformManager(); - PlatformCommandManager mgr = platformManager.getPlatformCommandManager(); - final CommandManager commandManager = mgr.getCommandManager(); - dumpCommands(commandManager); + public static void main(String[] args) throws IOException { + final DocumentationPrinter printer = new DocumentationPrinter(); + + printer.writeAllCommands(); + writeOutput("commands.rst", printer.cmdOutput.toString()); + writeOutput("permissions.rst", printer.permsOutput.toString()); } - private static void dumpCommands(CommandManager commandManager) { - final PlainComponentSerializer serializer = new PlainComponentSerializer(kbc -> "", TranslatableComponent::key); - cmdToUsages(serializer, commandManager.getAllCommands(), TextConfig.getCommandPrefix(), 0); - - cmdsToPerms(commandManager.getAllCommands(), TextConfig.getCommandPrefix()); + private static void writeOutput(String file, String output) throws IOException { + File outfile = new File(file); + Files.write(output, outfile, StandardCharsets.UTF_8); } - private static void cmdsToPerms(Stream cmds, String prefix) { + private final ComponentSerializer serializer + = new PlainComponentSerializer(kb -> "", TranslatableComponent::key); + private final CommandRegistrationHandler registration; + private final CommandManagerServiceImpl commandManagerService; + private final WorldEdit worldEdit = WorldEdit.getInstance(); + private StringBuilder cmdOutput; + private StringBuilder permsOutput; + private Field mgrCmdField; + + private DocumentationPrinter() { + this.cmdOutput = new StringBuilder(); + this.permsOutput = new StringBuilder(); + this.registration = new CommandRegistrationHandler(ImmutableList.of()); + this.commandManagerService = new CommandManagerServiceImpl(); + try { + Field field = CommandManagerImpl.class.getDeclaredField("commands"); + field.setAccessible(true); + this.mgrCmdField = field; + } catch (NoSuchFieldException ignored) { + } + } + + private void registerSubCommands(CommandManager parent, String name, List aliases, String desc, + CommandRegistration registration, CI instance) { + registerSubCommands(parent, name, aliases, desc, registration, instance, m -> {}); + } + + private void registerSubCommands(CommandManager parent, String name, List aliases, String desc, + CommandRegistration registration, CI instance, + Consumer additionalConfig) { + parent.register(name, cmd -> { + cmd.aliases(aliases); + cmd.description(TextComponent.of(desc)); + cmd.action(Command.Action.NULL_ACTION); + + CommandManager manager = createManager(); + this.registration.register( + manager, + registration, + instance + ); + additionalConfig.accept(manager); + + cmd.addPart(SubCommandPart.builder(TranslatableComponent.of("worldedit.argument.action"), + TextComponent.of("Sub-command to run.")) + .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .required() + .build()); + }); + } + + private void writeAllCommands() { + writeHeader(); + + CommandManager manager; + + manager = createManager(); + registerSubCommands( + manager, + "worldedit", + ImmutableList.of("we"), + "WorldEdit commands", + WorldEditCommandsRegistration.builder(), + new WorldEditCommands(worldEdit) + ); + this.registration.register( + manager, + HistoryCommandsRegistration.builder(), + new HistoryCommands(worldEdit) + ); + this.registration.register( + manager, + GeneralCommandsRegistration.builder(), + new GeneralCommands(worldEdit) + ); + dumpSection("General Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + NavigationCommandsRegistration.builder(), + new NavigationCommands(worldEdit) + ); + dumpSection("Navigation Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + SelectionCommandsRegistration.builder(), + new SelectionCommands(worldEdit) + ); + ExpandCommands.register(registration, manager, commandManagerService); + dumpSection("Selection Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + RegionCommandsRegistration.builder(), + new RegionCommands() + ); + dumpSection("Region Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + GenerationCommandsRegistration.builder(), + new GenerationCommands(worldEdit) + ); + dumpSection("Generation Commands", manager); + + manager = createManager(); + registerSubCommands( + manager, + "schematic", + ImmutableList.of("schem", "/schematic", "/schem"), + "Schematic commands for saving/loading areas", + SchematicCommandsRegistration.builder(), + new SchematicCommands(worldEdit) + ); + this.registration.register( + manager, + ClipboardCommandsRegistration.builder(), + new ClipboardCommands() + ); + dumpSection("Schematic and Clipboard Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + ToolCommandsRegistration.builder(), + new ToolCommands(worldEdit) + ); + this.registration.register( + manager, + ToolUtilCommandsRegistration.builder(), + new ToolUtilCommands(worldEdit) + ); + dumpSection("Tool Commands", manager); + + manager = createManager(); + registerSubCommands( + manager, + "superpickaxe", + ImmutableList.of("pickaxe", "sp"), + "Super-pickaxe commands", + SuperPickaxeCommandsRegistration.builder(), + new SuperPickaxeCommands(worldEdit) + ); + dumpSection("Super Pickaxe Commands", manager); + + manager = createManager(); + registerSubCommands( + manager, + "brush", + ImmutableList.of("br", "/brush", "/br"), + "Brushing commands", + BrushCommandsRegistration.builder(), + new BrushCommands(worldEdit), + mgr -> { + PaintBrushCommands.register(commandManagerService, mgr, registration); + ApplyBrushCommands.register(commandManagerService, mgr, registration); + } + ); + dumpSection("Brush Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + BiomeCommandsRegistration.builder(), + new BiomeCommands() + ); + dumpSection("Biome Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + ChunkCommandsRegistration.builder(), + new ChunkCommands(worldEdit) + ); + dumpSection("Chunk Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + SnapshotUtilCommandsRegistration.builder(), + new SnapshotUtilCommands(worldEdit) + ); + registerSubCommands( + manager, + "snapshot", + ImmutableList.of("snap"), + "Snapshot commands for restoring backups", + SnapshotCommandsRegistration.builder(), + new SnapshotCommands(worldEdit) + ); + dumpSection("Snapshot Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + ScriptingCommandsRegistration.builder(), + new ScriptingCommands(worldEdit) + ); + dumpSection("Scripting Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + UtilityCommandsRegistration.builder(), + new UtilityCommands(worldEdit) + ); + dumpSection("Utility Commands", manager); + } + + private void writeHeader() { + cmdOutput.append( + "========\n" + + "Commands\n" + + "========\n" + + "\n" + + ".. contents::\n" + + " :local:\n" + + "\n" + + ".. tip::\n" + + "\n" + + " Arguments enclosed in ``[ ]`` are optional, those enclosed in ``< >`` are required.\n\n"); + } + + private CommandManager createManager() { + final CommandManager commandManager = commandManagerService.newCommandManager(); + if (mgrCmdField != null && commandManager instanceof CommandManagerImpl) { + try { + mgrCmdField.set(commandManager, new LinkedHashMap<>()); + } catch (IllegalAccessException ignored) { + } + } + return commandManager; + } + + private void dumpSection(String title, CommandManager manager) { + cmdOutput.append(title).append("\n").append(Strings.repeat("~", title.length())).append("\n\n"); + + String prefix = TextConfig.getCommandPrefix(); + +// permsOutput.append("\n------------\n\n"); + cmdsToPerms(manager.getAllCommands(), prefix); + + for (Command command : manager.getAllCommands().collect(Collectors.toList())) { + cmdOutput.append("\n------------\n\n"); + writeCommandBlock(command, prefix, Stream.empty()); + command.getParts().stream().filter(p -> p instanceof SubCommandPart) + .flatMap(p -> ((SubCommandPart) p).getCommands().stream()) + .forEach(sc -> { + cmdOutput.append("\n------------\n\n"); + writeCommandBlock(sc, prefix + command.getName() + " ", Stream.of(command)); + }); + } + } + + private void cmdsToPerms(Stream cmds, String prefix) { cmds.forEach(c -> { - System.out.println(" " + cmdToPerm(prefix, c)); + permsOutput.append(" ").append(cmdToPerm(prefix, c)).append("\n"); c.getParts().stream().filter(p -> p instanceof SubCommandPart).map(p -> (SubCommandPart) p) .forEach(scp -> cmdsToPerms(scp.getCommands().stream(), prefix + c.getName() + " ")); }); } - private static String cmdToPerm(String prefix, Command c) { + private String cmdToPerm(String prefix, Command c) { return prefix + c.getName() + ",\"" + (c.getCondition() instanceof PermissionCondition ? String.join(", ", ((PermissionCondition) c.getCondition()).getPermissions()) : "") + "\""; } - private static void cmdToUsages(PlainComponentSerializer serializer, Stream cmds, String prefix, int indent) { - cmds.forEach(c -> { - System.out.println(Strings.repeat("\t", indent) + cmdToString(serializer, prefix, c, indent)); - c.getParts().stream().filter(p -> p instanceof SubCommandPart).map(p -> (SubCommandPart) p) - .forEach(scp -> cmdToUsages(serializer, scp.getCommands().stream(), prefix + c.getName() + " ", indent + 1)); - System.out.println(); - }); + private void writeCommandBlock(Command command, String prefix, Stream parents) { + String name = prefix + command.getName(); + String desc = serializer.serialize(command.getDescription()); + cmdOutput.append(".. csv-table::\n :widths: 8, 15\n\n"); + cmdOutput.append(" ").append(name).append(",\"").append(desc).append("\"\n"); + if (!command.getAliases().isEmpty()) { + cmdOutput.append(" Aliases,\"").append(String.join(", ", + command.getAliases().stream().map(a -> prefix + a).collect(Collectors.toSet()))) + .append("\"\n"); + } + if (command.getCondition() instanceof PermissionCondition) { + cmdOutput.append(" Permissions,\"").append(String.join(", ", ((PermissionCondition) command.getCondition()).getPermissions())).append("\"\n"); + } + cmdOutput.append(" Usage,\"").append(serializer.serialize( + HelpGenerator.create(Stream.concat(parents, Stream.of(command)).collect(Collectors.toList())).getUsage())).append("\"\n"); + command.getParts().stream().filter(part -> !(part instanceof SubCommandPart)).forEach(part -> + cmdOutput.append(" \u2001\u2001").append(serializer.serialize(part.getTextRepresentation())).append(",\"") + .append(serializer.serialize(part.getDescription())).append("\"\n")); + if (command.getFooter().isPresent()) { + cmdOutput.append(" ,\"").append(serializer.serialize(command.getFooter().get()).replace("\n", " ")).append("\"\n"); + } } - - private static String cmdToString(PlainComponentSerializer serializer, String prefix, Command c, int indent) { - return serializer.serialize(TextComponent.of(prefix + c.getName()).append(TextComponent.newline()) - .append(TextComponent.of(c.getCondition() instanceof PermissionCondition - ? "Permissions: " + (String.join(", ", ((PermissionCondition) c.getCondition()).getPermissions())) + "\n" - : "")) - .append(c.getFullHelp())).replace("\n", "\n" + Strings.repeat("\t", indent)); - } - }