From dc380b1fb38bbe128dc1d530fcaeb6cb1d97ef46 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 2 Jun 2019 23:39:01 -0400 Subject: [PATCH 1/7] Ugly but working generator for rst commands. --- .../internal/util/DocumentationPrinter.java | 205 ++++-------------- 1 file changed, 44 insertions(+), 161 deletions(-) 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 4728bc9b8..a42e7a2a3 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 @@ -19,34 +19,21 @@ package com.sk89q.worldedit.internal.util; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.NestedCommand; -import com.sk89q.worldedit.command.BiomeCommands; -import com.sk89q.worldedit.command.ChunkCommands; -import com.sk89q.worldedit.command.ClipboardCommands; -import com.sk89q.worldedit.command.GeneralCommands; -import com.sk89q.worldedit.command.GenerationCommands; -import com.sk89q.worldedit.command.HistoryCommands; -import com.sk89q.worldedit.command.NavigationCommands; -import com.sk89q.worldedit.command.RegionCommands; -import com.sk89q.worldedit.command.ScriptingCommands; -import com.sk89q.worldedit.command.SelectionCommands; -import com.sk89q.worldedit.command.SnapshotUtilCommands; -import com.sk89q.worldedit.command.ToolCommands; -import com.sk89q.worldedit.command.ToolUtilCommands; -import com.sk89q.worldedit.command.UtilityCommands; +import com.google.common.base.Strings; +import com.sk89q.worldedit.WorldEdit; +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.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +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.part.SubCommandPart; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.stream.Stream; -@SuppressWarnings("UseOfSystemOutOrSystemErr") public final class DocumentationPrinter { private DocumentationPrinter() { @@ -56,153 +43,49 @@ public final class DocumentationPrinter { * Generates documentation. * * @param args arguments - * @throws IOException thrown on I/O error */ - public static void main(String[] args) throws IOException { - File commandsDir = new File(args[0]); - - List> commandClasses = getCommandClasses(commandsDir); - - System.out.println("Writing permissions wiki table..."); - writePermissionsWikiTable(commandClasses); - System.out.println("Writing Bukkit plugin.yml..."); - writeBukkitYAML(); - - System.out.println("Done!"); + public static void main(String[] args) { + final PlatformManager platformManager = WorldEdit.getInstance().getPlatformManager(); + PlatformCommandManager mgr = platformManager.getPlatformCommandManager(); + final CommandManager commandManager = mgr.getCommandManager(); + dumpCommands(commandManager); } - private static List> getCommandClasses(File dir) { - List> classes = new ArrayList<>(); + private static void dumpCommands(CommandManager commandManager) { + final PlainComponentSerializer serializer = new PlainComponentSerializer(kbc -> "", TranslatableComponent::key); + cmdToUsages(serializer, commandManager.getAllCommands(), TextConfig.getCommandPrefix(), 0); - classes.add(BiomeCommands.class); - classes.add(ChunkCommands.class); - classes.add(ClipboardCommands.class); - classes.add(GeneralCommands.class); - classes.add(GenerationCommands.class); - classes.add(HistoryCommands.class); - classes.add(NavigationCommands.class); - classes.add(RegionCommands.class); - classes.add(ScriptingCommands.class); - classes.add(SelectionCommands.class); - classes.add(SnapshotUtilCommands.class); - classes.add(ToolUtilCommands.class); - classes.add(ToolCommands.class); - classes.add(UtilityCommands.class); - - /*for (File f : dir.listFiles()) { - if (!f.getName().matches("^.*\\.java$")) { - continue; - } - - String className = "com.sk89q.worldedit.commands." - + f.getName().substring(0, f.getName().lastIndexOf(".")); - - Class cls; - try { - cls = Class.forName(className, true, - Thread.currentThread().getContextClassLoader()); - } catch (ClassNotFoundException e) { - continue; - } - - classes.add(cls); - }*/ - - return classes; + cmdsToPerms(commandManager.getAllCommands(), TextConfig.getCommandPrefix()); } - private static void writePermissionsWikiTable(List> commandClasses) - throws IOException { - try (FileOutputStream stream = new FileOutputStream("wiki_permissions.txt")) { - PrintStream print = new PrintStream(stream); - writePermissionsWikiTable(print, commandClasses, "/"); - } + private static void cmdsToPerms(Stream cmds, String prefix) { + cmds.forEach(c -> { + System.out.println(" " + cmdToPerm(prefix, c)); + c.getParts().stream().filter(p -> p instanceof SubCommandPart).map(p -> (SubCommandPart) p) + .forEach(scp -> cmdsToPerms(scp.getCommands().stream(), prefix + c.getName() + " ")); + }); } - private static void writePermissionsWikiTable(PrintStream stream, - List> commandClasses, String prefix) { - - for (Class cls : commandClasses) { - for (Method method : cls.getMethods()) { - if (!method.isAnnotationPresent(Command.class)) { - continue; - } - - Command cmd = method.getAnnotation(Command.class); - - stream.println("|-"); - stream.print("| " + prefix + cmd.aliases()[0]); - stream.print(" || "); - - if (method.isAnnotationPresent(CommandPermissions.class)) { - CommandPermissions perms = - method.getAnnotation(CommandPermissions.class); - - String[] permKeys = perms.value(); - for (int i = 0; i < permKeys.length; ++i) { - if (i > 0) { - stream.print(", "); - } - stream.print(permKeys[i]); - } - } - - stream.print(" || "); - - boolean firstAlias = true; - if (cmd.aliases().length != 0) { - for (String alias : cmd.aliases()) { - if (!firstAlias) stream.print("
"); - stream.print(prefix + alias); - firstAlias = false; - } - } - - stream.print(" || "); - - if (cmd.flags() != null && !cmd.flags().isEmpty()) { - stream.print(cmd.flags()); - } - - stream.print(" || "); - - if (cmd.desc() != null && !cmd.desc().isEmpty()) { - stream.print(cmd.desc()); - } - - stream.println(); - - if (method.isAnnotationPresent(NestedCommand.class)) { - NestedCommand nested = - method.getAnnotation(NestedCommand.class); - - Class[] nestedClasses = nested.value(); - writePermissionsWikiTable(stream, - Arrays.asList(nestedClasses), - prefix + cmd.aliases()[0] + " "); - } - } - } + private static String cmdToPerm(String prefix, Command c) { + return prefix + c.getName() + ",\"" + (c.getCondition() instanceof PermissionCondition + ? String.join(", ", ((PermissionCondition) c.getCondition()).getPermissions()) : "") + "\""; } - private static void writeBukkitYAML() - throws IOException { - try (FileOutputStream stream = new FileOutputStream("plugin.yml")) { - PrintStream print = new PrintStream(stream); - writeBukkitYAML(print); - } + 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 static void writeBukkitYAML(PrintStream stream) { - stream.println("name: WorldEdit"); - stream.println("main: com.sk89q.worldedit.bukkit.WorldEditPlugin"); - stream.println("version: ${project.version}"); - stream.println("softdepend: [Spout] #hack to fix trove errors"); - - stream.println(); - stream.println(); - stream.println("# Permissions aren't here. Read http://wiki.sk89q.com/wiki/WEPIF/DinnerPerms"); - stream.println("# for how WorldEdit permissions actually work."); + 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)); } } From 34020f7bd26dcd2d3a952c7b02e9c401d3414d9c Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 5 Jun 2019 10:23:41 -0400 Subject: [PATCH 2/7] Less ugly. Makes tables for all commands and subcommands. --- .../internal/util/DocumentationPrinter.java | 384 ++++++++++++++++-- 1 file changed, 350 insertions(+), 34 deletions(-) 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)); - } - } From b7e329bc1b2c5b4516d47e9a3d80a2f42cd68a59 Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 5 Jun 2019 10:39:10 -0400 Subject: [PATCH 3/7] Better spacing for section headers. --- .../com/sk89q/worldedit/internal/util/DocumentationPrinter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8c2bdb46f..f5ac335f2 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 @@ -350,7 +350,7 @@ public final class DocumentationPrinter { } private void dumpSection(String title, CommandManager manager) { - cmdOutput.append(title).append("\n").append(Strings.repeat("~", title.length())).append("\n\n"); + cmdOutput.append("\n").append(title).append("\n").append(Strings.repeat("~", title.length())).append("\n"); String prefix = TextConfig.getCommandPrefix(); From 22157f08644cf0081ec57fb6bd5ba6eb4d018e27 Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 5 Jun 2019 11:27:16 -0400 Subject: [PATCH 4/7] Write entire perms file for easier gen. Also fix some format issues. --- .../internal/util/DocumentationPrinter.java | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) 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 f5ac335f2..8b29bb51f 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 @@ -322,6 +322,8 @@ public final class DocumentationPrinter { new UtilityCommands(worldEdit) ); dumpSection("Utility Commands", manager); + + writeFooter(); } private void writeHeader() { @@ -336,6 +338,42 @@ public final class DocumentationPrinter { ".. tip::\n" + "\n" + " Arguments enclosed in ``[ ]`` are optional, those enclosed in ``< >`` are required.\n\n"); + + permsOutput.append("===========\n" + + "Permissions\n" + + "===========\n" + + "\n" + + "By default, no one can use WorldEdit. In order for yourself, moderators, and players to use WorldEdit, you must provide the proper permissions. One way is to provide op to moderators and administrators (unless disabled in the :doc:`configuration `), but providing the permission nodes on this page (through a permissions plugin) is the more flexible.\n" + + "\n" + + "You can give the ``worldedit.*`` permission to give yourself and other administrators full access to WorldEdit.\n" + + "\n" + + "Commands\n" + + "=========\n" + + "\n" + + "See the :doc:`commands` page for an explanation of some of these commands.\n" + + "\n" + + ".. csv-table::\n" + + " :header: Command, Permission\n" + + " :widths: 15, 25\n\n"); + } + + private void writeFooter() { + permsOutput.append("\nOther Permissions\n" + + "==================\n" + + "\n" + + ".. csv-table::\n" + + " :header: Permission, Explanation\n" + + " :widths: 15, 25\n" + + "\n" + + " worldedit.navigation.jumpto.tool,\"Allows usage of the navigation wand's ``/jumpto`` shortcut (left click).\"\n" + + " worldedit.navigation.thru.tool,\"Allows usage of the navigation wand's ``/thru`` shortcut (right click).\"\n" + + " worldedit.anyblock,\"Allows usage of blocks in the :doc:`disallowed-blocks ` config option.\"\n" + + " worldedit.limit.unrestricted,\"Allows setting the limit via the ``//limit`` :doc:`command ` higher than the maximum in the :doc:`configuration `.\"\n" + + " worldedit.timeout.unrestricted,\"Allows setting the calculation timeout via the ``//timeout`` :doc:`command ` higher than the maximum in the :doc:`configuration `.\"\n" + + " worldedit.inventory.unrestricted,\"Override the ``use-inventory`` option if enabled in the :doc:`configuration `.\"\n" + + " worldedit.override.bedrock,\"Allows breaking of bedrock with the super-pickaxe tool.\"\n" + + " worldedit.setnbt,\"Allows setting `extra data `_ on blocks (such as signs, chests, etc).\"\n" + + " worldedit.report.pastebin,\"Allows uploading report files to pastebin automatically for the ``/worldedit report`` :doc:`command `.\""); } private CommandManager createManager() { @@ -357,8 +395,10 @@ public final class DocumentationPrinter { // permsOutput.append("\n------------\n\n"); cmdsToPerms(manager.getAllCommands(), prefix); + boolean first = true; for (Command command : manager.getAllCommands().collect(Collectors.toList())) { - cmdOutput.append("\n------------\n\n"); + if (!first) cmdOutput.append("\n------------\n\n"); + first = false; writeCommandBlock(command, prefix, Stream.empty()); command.getParts().stream().filter(p -> p instanceof SubCommandPart) .flatMap(p -> ((SubCommandPart) p).getCommands().stream()) From e767dd98881fc75d1bd5ce68a388adf3605cff66 Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 5 Jun 2019 12:31:12 -0400 Subject: [PATCH 5/7] Missing perm. --- .../src/main/java/com/sk89q/worldedit/LocalConfiguration.java | 4 ++-- .../sk89q/worldedit/internal/util/DocumentationPrinter.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java index 08594fcfb..d814bf48b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java @@ -54,7 +54,7 @@ public abstract class LocalConfiguration { public boolean logCommands = false; public String logFile = ""; public String logFormat = LogFormat.DEFAULT_FORMAT; - public boolean registerHelp = true; // what is the point of this, it's not even used + public boolean registerHelp = true; // unused public String wandItem = "minecraft:wooden_axe"; public boolean superPickaxeDrop = true; public boolean superPickaxeManyDrop = true; @@ -70,7 +70,7 @@ public abstract class LocalConfiguration { public Set allowedDataCycleBlocks = new HashSet<>(); public String saveDir = "schematics"; public String scriptsDir = "craftscripts"; - public boolean showHelpInfo = true; + public boolean showHelpInfo = true; // unused public int butcherDefaultRadius = -1; public int butcherMaxRadius = -1; public boolean allowSymlinks = false; 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 8b29bb51f..6352451f9 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 @@ -368,10 +368,11 @@ public final class DocumentationPrinter { " worldedit.navigation.jumpto.tool,\"Allows usage of the navigation wand's ``/jumpto`` shortcut (left click).\"\n" + " worldedit.navigation.thru.tool,\"Allows usage of the navigation wand's ``/thru`` shortcut (right click).\"\n" + " worldedit.anyblock,\"Allows usage of blocks in the :doc:`disallowed-blocks ` config option.\"\n" + - " worldedit.limit.unrestricted,\"Allows setting the limit via the ``//limit`` :doc:`command ` higher than the maximum in the :doc:`configuration `.\"\n" + + " worldedit.limit.unrestricted,\"Allows setting the limit via the ``//limit`` :doc:`command ` higher than the maximum in the :doc:`configuration `, as well as other limit bypasses.\"\n" + " worldedit.timeout.unrestricted,\"Allows setting the calculation timeout via the ``//timeout`` :doc:`command ` higher than the maximum in the :doc:`configuration `.\"\n" + " worldedit.inventory.unrestricted,\"Override the ``use-inventory`` option if enabled in the :doc:`configuration `.\"\n" + " worldedit.override.bedrock,\"Allows breaking of bedrock with the super-pickaxe tool.\"\n" + + " worldedit.override.data-cycler,\"Allows cycling non-whitelisted blocks with the data cycler tool.\"\n" + " worldedit.setnbt,\"Allows setting `extra data `_ on blocks (such as signs, chests, etc).\"\n" + " worldedit.report.pastebin,\"Allows uploading report files to pastebin automatically for the ``/worldedit report`` :doc:`command `.\""); } From e69aedf05964c8e3906a2426260e95423157109e Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 5 Jun 2019 14:57:44 -0400 Subject: [PATCH 6/7] Allow clean shutdown. Rearrange command tables. --- .../internal/util/DocumentationPrinter.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 6352451f9..cd378d57e 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 @@ -103,6 +103,8 @@ public final class DocumentationPrinter { printer.writeAllCommands(); writeOutput("commands.rst", printer.cmdOutput.toString()); writeOutput("permissions.rst", printer.permsOutput.toString()); + + WorldEdit.getInstance().getSessionManager().unload(); } private static void writeOutput(String file, String output) throws IOException { @@ -427,12 +429,14 @@ public final class DocumentationPrinter { 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"); + cmdOutput.append(" ").append(name).append(","); if (!command.getAliases().isEmpty()) { - cmdOutput.append(" Aliases,\"").append(String.join(", ", - command.getAliases().stream().map(a -> prefix + a).collect(Collectors.toSet()))) - .append("\"\n"); + cmdOutput.append("\"(or ").append(String.join(", ", + command.getAliases().stream().map(a -> prefix + a).collect(Collectors.toSet()))) + .append(")\""); } + cmdOutput.append("\n"); + cmdOutput.append(" Description,\"").append(desc).append("\"\n"); if (command.getCondition() instanceof PermissionCondition) { cmdOutput.append(" Permissions,\"").append(String.join(", ", ((PermissionCondition) command.getCondition()).getPermissions())).append("\"\n"); } From d46cd78e14b4ceb3fce423d2a04b589ed9266cd9 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 5 Jun 2019 23:26:57 -0700 Subject: [PATCH 7/7] Port doc printer to Kotlin, heavily improve --- settings.gradle | 2 + worldedit-core/doctools/build.gradle.kts | 19 + .../internal/util/DocumentationPrinter.kt | 320 +++++++++++++ .../internal/util/DocumentationPrinter.java | 452 ------------------ 4 files changed, 341 insertions(+), 452 deletions(-) create mode 100644 worldedit-core/doctools/build.gradle.kts create mode 100644 worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java diff --git a/settings.gradle b/settings.gradle index 84386e427..dec0467a5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,3 +7,5 @@ include 'worldedit-libs' include "worldedit-$it" } include "worldedit-libs:core:ap" + +include "worldedit-core:doctools" diff --git a/worldedit-core/doctools/build.gradle.kts b/worldedit-core/doctools/build.gradle.kts new file mode 100644 index 000000000..002f367bd --- /dev/null +++ b/worldedit-core/doctools/build.gradle.kts @@ -0,0 +1,19 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.3.31" +} + +tasks.withType { + kotlinOptions.jvmTarget = "1.8" +} + +repositories { + jcenter() +} + +dependencies { + "implementation"(project(":worldedit-libs:core:ap")) + "implementation"(project(":worldedit-core")) + "implementation"(kotlin("stdlib-jdk8")) +} diff --git a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt new file mode 100644 index 000000000..167d0cb34 --- /dev/null +++ b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt @@ -0,0 +1,320 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.internal.util + +import com.google.common.base.Strings +import com.sk89q.worldedit.WorldEdit +import com.sk89q.worldedit.command.BiomeCommands +import com.sk89q.worldedit.command.ChunkCommands +import com.sk89q.worldedit.command.ClipboardCommands +import com.sk89q.worldedit.command.ExpandCommands +import com.sk89q.worldedit.command.GeneralCommands +import com.sk89q.worldedit.command.GenerationCommands +import com.sk89q.worldedit.command.HistoryCommands +import com.sk89q.worldedit.command.NavigationCommands +import com.sk89q.worldedit.command.RegionCommands +import com.sk89q.worldedit.command.ScriptingCommands +import com.sk89q.worldedit.command.SelectionCommands +import com.sk89q.worldedit.command.SnapshotUtilCommands +import com.sk89q.worldedit.command.ToolCommands +import com.sk89q.worldedit.command.ToolUtilCommands +import com.sk89q.worldedit.command.UtilityCommands +import com.sk89q.worldedit.command.util.PermissionCondition +import com.sk89q.worldedit.util.formatting.text.TextComponent +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent +import com.sk89q.worldedit.util.formatting.text.serializer.plain.PlainComponentSerializer +import org.enginehub.piston.Command +import org.enginehub.piston.TextConfig +import org.enginehub.piston.part.SubCommandPart +import org.enginehub.piston.util.HelpGenerator +import java.nio.file.Files +import java.nio.file.Paths +import java.util.stream.Stream +import kotlin.streams.toList +import org.enginehub.piston.annotation.Command as CommandAnnotation + +class DocumentationPrinter private constructor() { + + private val serializer = PlainComponentSerializer({ "" }, TranslatableComponent::key) + private val commands = WorldEdit.getInstance().platformManager.platformCommandManager.commandManager.allCommands + .map { it.name to it }.toList().toMap() + private val cmdOutput = StringBuilder() + private val permsOutput = StringBuilder() + + private suspend inline fun SequenceScope.yieldAllCommandsIn() { + for (method in T::class.java.methods) { + val cmdAnno = method.getDeclaredAnnotation(CommandAnnotation::class.java) + if (cmdAnno != null) { + yield(cmdAnno.name) + } + } + } + + private fun writeAllCommands() { + writeHeader() + + dumpSection("General Commands") { + yield("worldedit") + yieldAllCommandsIn() + yieldAllCommandsIn() + } + + dumpSection("Navigation Commands") { + yieldAllCommandsIn() + } + + dumpSection("Selection Commands") { + yieldAllCommandsIn() + yieldAllCommandsIn() + } + + dumpSection("Region Commands") { + yieldAllCommandsIn() + } + + dumpSection("Generation Commands") { + yieldAllCommandsIn() + } + + dumpSection("Schematic and Clipboard Commands") { + yield("schematic") + yieldAllCommandsIn() + } + + dumpSection("Tool Commands") { + yieldAllCommandsIn() + yieldAllCommandsIn() + } + + dumpSection("Super Pickaxe Commands") { + yield("superpickaxe") + } + + dumpSection("Brush Commands") { + yield("brush") + } + + dumpSection("Biome Commands") { + yieldAllCommandsIn() + } + + dumpSection("Chunk Commands") { + yieldAllCommandsIn() + } + + dumpSection("Snapshot Commands") { + yieldAllCommandsIn() + yield("snapshot") + } + + dumpSection("Scripting Commands") { + yieldAllCommandsIn() + } + + dumpSection("Utility Commands") { + yieldAllCommandsIn() + } + + writeFooter() + } + + private fun writeHeader() { + cmdOutput.appendln(""" +======== +Commands +======== + +.. contents:: + :local: + +.. tip:: + + Arguments enclosed in ``[ ]`` are optional, those enclosed in ``< >`` are required. +""".trim()) + + permsOutput.appendln(""" +=========== +Permissions +=========== + +By default, no one can use WorldEdit. In order for yourself, moderators, and players to use WorldEdit, you must provide the proper permissions. One way is to provide op to moderators and administrators (unless disabled in the :doc:`configuration `), but providing the permission nodes on this page (through a permissions plugin) is the more flexible. + +You can give the ``worldedit.*`` permission to give yourself and other administrators full access to WorldEdit. + +Commands +========= + +See the :doc:`commands` page for an explanation of some of these commands. + +.. csv-table:: + :header: Command, Permission + :widths: 15, 25 +""".trim()) + permsOutput.appendln() + } + + private fun writeFooter() { + permsOutput.appendln() + permsOutput.append(""" +Other Permissions +================== + +.. csv-table:: + :header: Permission, Explanation + :widths: 15, 25 + + ``worldedit.navigation.jumpto.tool``,"Allows usage of the navigation wand's ``/jumpto`` shortcut (left click)." + ``worldedit.navigation.thru.tool``,"Allows usage of the navigation wand's ``/thru`` shortcut (right click)." + ``worldedit.anyblock``,"Allows usage of blocks in the :doc:`disallowed-blocks ` config option." + ``worldedit.limit.unrestricted``,"Allows setting the limit via the ``//limit`` :doc:`command ` higher than the maximum in the :doc:`configuration `, as well as other limit bypasses." + ``worldedit.timeout.unrestricted``,"Allows setting the calculation timeout via the ``//timeout`` :doc:`command ` higher than the maximum in the :doc:`configuration `." + ``worldedit.inventory.unrestricted``,"Override the ``use-inventory`` option if enabled in the :doc:`configuration `." + ``worldedit.override.bedrock``,"Allows breaking of bedrock with the super-pickaxe tool." + ``worldedit.override.data-cycler``,"Allows cycling non-whitelisted blocks with the data cycler tool." + ``worldedit.setnbt``,"Allows setting `extra data `_ on blocks (such as signs, chests, etc)." + ``worldedit.report.pastebin``,"Allows uploading report files to pastebin automatically for the ``/worldedit report`` :doc:`command `." +""".trim()) + } + + private fun dumpSection(title: String, addCommandNames: suspend SequenceScope.() -> Unit) { + cmdOutput.append("\n").append(title).append("\n").append(Strings.repeat("~", title.length)).append("\n") + + val prefix = TextConfig.getCommandPrefix() + val commands = sequence(addCommandNames).map { this.commands.getValue(it) }.toList() + + cmdsToPerms(commands, prefix) + + for (command in commands) { + writeCommandBlock(command, prefix, Stream.empty()) + command.parts.stream().filter { p -> p is SubCommandPart } + .flatMap { p -> (p as SubCommandPart).commands.stream() } + .forEach { sc -> + writeCommandBlock(sc, prefix + command.name + " ", Stream.of(command)) + } + } + } + + private fun cmdsToPerms(cmds: List, prefix: String) { + cmds.forEach { c -> + permsOutput.append(" ").append(cmdToPerm(prefix, c)).append("\n") + c.parts.filter { p -> p is SubCommandPart } + .map { p -> p as SubCommandPart } + .forEach { scp -> + cmdsToPerms(scp.commands.sortedBy { it.name }, prefix + c.name + " ") + } + } + } + + private fun cmdToPerm(prefix: String, c: Command): String { + val cond = c.condition + val permissions = when { + cond is PermissionCondition && cond.permissions.isNotEmpty() -> + cond.permissions.joinToString(", ") { "``$it``" } + else -> "" + } + return "``$prefix${c.name}``,\"$permissions\"" + } + + private fun writeCommandBlock(command: Command, prefix: String, parents: Stream) { + val name = prefix + command.name + val entries = commandTableEntries(command, parents) + + cmdOutput.appendln(".. raw:: html") + cmdOutput.appendln() + cmdOutput.appendln(""" """) + cmdOutput.appendln() + cmdOutput.append(".. topic:: ``$name``") + if (!command.aliases.isEmpty()) { + command.aliases.joinTo(cmdOutput, ", ", + prefix = " (or ", + postfix = ")", + transform = { "``$prefix$it``" }) + } + cmdOutput.appendln().appendln() + cmdOutput.appendln(""" + | .. csv-table:: + | :widths: 8, 15 + """.trimMargin()) + cmdOutput.appendln() + for ((k, v) in entries) { + val rstSafe = v.replace("\"", "\\\"").replace("\n", "\n" + " ".repeat(2)) + cmdOutput.append(" ".repeat(2)) + .append(k) + .append(",") + .append('"') + .append(rstSafe) + .append('"').appendln() + } + cmdOutput.appendln() + } + + private fun linkSafe(text: String) = text.replace(" ", "-") + + private fun commandTableEntries(command: Command, parents: Stream): Map { + return sequence { + val desc = command.description.run { + when { + command.footer.isPresent -> append( + TextComponent.builder("\n\n").append(command.footer.get()) + ) + else -> this + } + } + yield("**Description**" to serializer.serialize(desc)) + val cond = command.condition + if (cond is PermissionCondition && cond.permissions.isNotEmpty()) { + val perms = cond.permissions.joinToString(", ") { "``$it``" } + yield("**Permissions**" to perms) + } + val usage = serializer.serialize(HelpGenerator.create(Stream.concat(parents, Stream.of(command)).toList()).usage) + yield("**Usage**" to "``$usage``") + + // Part descriptions + command.parts.filterNot { it is SubCommandPart } + .forEach { + val title = "\u2001\u2001``" + serializer.serialize(it.textRepresentation) + "``" + yield(title to serializer.serialize(it.description)) + } + }.toMap() + } + + companion object { + + /** + * Generates documentation. + */ + @JvmStatic + fun main(args: Array) { + val printer = DocumentationPrinter() + + printer.writeAllCommands() + writeOutput("commands.rst", printer.cmdOutput.toString()) + writeOutput("permissions.rst", printer.permsOutput.toString()) + + WorldEdit.getInstance().sessionManager.unload() + } + + private fun writeOutput(file: String, output: String) { + Files.newBufferedWriter(Paths.get(file)).use { + it.write(output) + } + } + } +} 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 deleted file mode 100644 index cd378d57e..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java +++ /dev/null @@ -1,452 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -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.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 { - - /** - * Generates documentation. - * - * @param args arguments - */ - 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()); - - WorldEdit.getInstance().getSessionManager().unload(); - } - - private static void writeOutput(String file, String output) throws IOException { - File outfile = new File(file); - Files.write(output, outfile, StandardCharsets.UTF_8); - } - - 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); - - writeFooter(); - } - - 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"); - - permsOutput.append("===========\n" + - "Permissions\n" + - "===========\n" + - "\n" + - "By default, no one can use WorldEdit. In order for yourself, moderators, and players to use WorldEdit, you must provide the proper permissions. One way is to provide op to moderators and administrators (unless disabled in the :doc:`configuration `), but providing the permission nodes on this page (through a permissions plugin) is the more flexible.\n" + - "\n" + - "You can give the ``worldedit.*`` permission to give yourself and other administrators full access to WorldEdit.\n" + - "\n" + - "Commands\n" + - "=========\n" + - "\n" + - "See the :doc:`commands` page for an explanation of some of these commands.\n" + - "\n" + - ".. csv-table::\n" + - " :header: Command, Permission\n" + - " :widths: 15, 25\n\n"); - } - - private void writeFooter() { - permsOutput.append("\nOther Permissions\n" + - "==================\n" + - "\n" + - ".. csv-table::\n" + - " :header: Permission, Explanation\n" + - " :widths: 15, 25\n" + - "\n" + - " worldedit.navigation.jumpto.tool,\"Allows usage of the navigation wand's ``/jumpto`` shortcut (left click).\"\n" + - " worldedit.navigation.thru.tool,\"Allows usage of the navigation wand's ``/thru`` shortcut (right click).\"\n" + - " worldedit.anyblock,\"Allows usage of blocks in the :doc:`disallowed-blocks ` config option.\"\n" + - " worldedit.limit.unrestricted,\"Allows setting the limit via the ``//limit`` :doc:`command ` higher than the maximum in the :doc:`configuration `, as well as other limit bypasses.\"\n" + - " worldedit.timeout.unrestricted,\"Allows setting the calculation timeout via the ``//timeout`` :doc:`command ` higher than the maximum in the :doc:`configuration `.\"\n" + - " worldedit.inventory.unrestricted,\"Override the ``use-inventory`` option if enabled in the :doc:`configuration `.\"\n" + - " worldedit.override.bedrock,\"Allows breaking of bedrock with the super-pickaxe tool.\"\n" + - " worldedit.override.data-cycler,\"Allows cycling non-whitelisted blocks with the data cycler tool.\"\n" + - " worldedit.setnbt,\"Allows setting `extra data `_ on blocks (such as signs, chests, etc).\"\n" + - " worldedit.report.pastebin,\"Allows uploading report files to pastebin automatically for the ``/worldedit report`` :doc:`command `.\""); - } - - 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("\n").append(title).append("\n").append(Strings.repeat("~", title.length())).append("\n"); - - String prefix = TextConfig.getCommandPrefix(); - -// permsOutput.append("\n------------\n\n"); - cmdsToPerms(manager.getAllCommands(), prefix); - - boolean first = true; - for (Command command : manager.getAllCommands().collect(Collectors.toList())) { - if (!first) cmdOutput.append("\n------------\n\n"); - first = false; - 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 -> { - 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 String cmdToPerm(String prefix, Command c) { - return prefix + c.getName() + ",\"" + (c.getCondition() instanceof PermissionCondition - ? String.join(", ", ((PermissionCondition) c.getCondition()).getPermissions()) : "") + "\""; - } - - 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(","); - if (!command.getAliases().isEmpty()) { - cmdOutput.append("\"(or ").append(String.join(", ", - command.getAliases().stream().map(a -> prefix + a).collect(Collectors.toSet()))) - .append(")\""); - } - cmdOutput.append("\n"); - cmdOutput.append(" Description,\"").append(desc).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"); - } - } -}