From cd0225006590a7ccb9739b17c33755bee6398854 Mon Sep 17 00:00:00 2001 From: md_5 Date: Sat, 6 Jul 2013 09:40:00 +1000 Subject: [PATCH] Did someone say console command completion? These commits were authored by @quickwango and come from Bukkit/Bukkit#868 and Bukkit/CraftBukkit#1151 --- .../0012-Console-Command-Completion.patch | 78 ++++++++++++++++ .../0066-Console-Command-Completion.patch | 89 +++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 Bukkit-Patches/0012-Console-Command-Completion.patch create mode 100644 CraftBukkit-Patches/0066-Console-Command-Completion.patch diff --git a/Bukkit-Patches/0012-Console-Command-Completion.patch b/Bukkit-Patches/0012-Console-Command-Completion.patch new file mode 100644 index 000000000..c71f884e4 --- /dev/null +++ b/Bukkit-Patches/0012-Console-Command-Completion.patch @@ -0,0 +1,78 @@ +From e0673d1050250f5e32ac173a12b3c65cab315b40 Mon Sep 17 00:00:00 2001 +From: Phillip Schichtel +Date: Mon, 29 Apr 2013 23:07:42 +0200 +Subject: [PATCH] Console Command Completion + +Implement command tab completion in the console. Adds BUKKIT-4168 + +To accomplish this 2 changes to Bukkit were required: +- the player check in Command.tabComplete() had to be removed +- the SimpleCommandMap prepends the / only for players + +diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java +index 5416c71..2f189ca 100644 +--- a/src/main/java/org/bukkit/command/Command.java ++++ b/src/main/java/org/bukkit/command/Command.java +@@ -78,18 +78,13 @@ public abstract class Command { + Validate.notNull(args, "Arguments cannot be null"); + Validate.notNull(alias, "Alias cannot be null"); + +- if (!(sender instanceof Player) || args.length == 0) { +- return ImmutableList.of(); +- } +- + String lastWord = args[args.length - 1]; + +- Player senderPlayer = (Player) sender; +- + ArrayList matchedPlayers = new ArrayList(); ++ final boolean noPlayer = !(sender instanceof Player); + for (Player player : sender.getServer().getOnlinePlayers()) { + String name = player.getName(); +- if (senderPlayer.canSee(player) && StringUtil.startsWithIgnoreCase(name, lastWord)) { ++ if (noPlayer || ((Player) sender).canSee(player) && StringUtil.startsWithIgnoreCase(name, lastWord)) { + matchedPlayers.add(name); + } + } +diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java +index df5f6ef..4c3e421 100644 +--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java ++++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java +@@ -16,6 +16,7 @@ import java.util.regex.Pattern; + import org.apache.commons.lang.Validate; + import org.bukkit.Server; + import org.bukkit.command.defaults.*; ++import org.bukkit.entity.Player; + import org.bukkit.util.StringUtil; + + public class SimpleCommandMap implements CommandMap { +@@ -224,6 +225,8 @@ public class SimpleCommandMap implements CommandMap { + ArrayList completions = new ArrayList(); + Map knownCommands = this.knownCommands; + ++ final String prefix = (sender instanceof Player ? "/" : ""); ++ + for (VanillaCommand command : fallbackCommands) { + String name = command.getName(); + +@@ -239,7 +242,7 @@ public class SimpleCommandMap implements CommandMap { + continue; + } + +- completions.add('/' + name); ++ completions.add(prefix + name); + } + + for (Map.Entry commandEntry : knownCommands.entrySet()) { +@@ -252,7 +255,7 @@ public class SimpleCommandMap implements CommandMap { + String name = commandEntry.getKey(); // Use the alias, not command name + + if (StringUtil.startsWithIgnoreCase(name, cmdLine)) { +- completions.add('/' + name); ++ completions.add(prefix + name); + } + } + +-- +1.8.1.2 + diff --git a/CraftBukkit-Patches/0066-Console-Command-Completion.patch b/CraftBukkit-Patches/0066-Console-Command-Completion.patch new file mode 100644 index 000000000..0a7ac7238 --- /dev/null +++ b/CraftBukkit-Patches/0066-Console-Command-Completion.patch @@ -0,0 +1,89 @@ +From ebda44887d817a442cb4073d3ba3aaaf1fc22ae2 Mon Sep 17 00:00:00 2001 +From: Phillip Schichtel +Date: Fri, 5 Jul 2013 21:55:00 +1000 +Subject: [PATCH] Console Command Completion + +changed exception handling +wrapped the tab completion in a waitable to sync it with the main thread +Implement command tab completion in the console. Adds BUKKIT-4168 + +Even though JLine provides an API for tab completion, there was still now tab +completion for console commands. +This commit implements tab completion in the console by providing the +ConsoleReader with a Completer implementation. + +diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java +index f33fdc1..2354ed2 100644 +--- a/src/main/java/net/minecraft/server/PlayerList.java ++++ b/src/main/java/net/minecraft/server/PlayerList.java +@@ -16,6 +16,7 @@ import java.util.Map.Entry; + import org.bukkit.craftbukkit.CraftServer; + import org.bukkit.craftbukkit.CraftWorld; + import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor; ++import org.bukkit.craftbukkit.command.ConsoleCommandCompleter; + + import org.bukkit.Bukkit; + import org.bukkit.Location; +@@ -54,6 +55,7 @@ public abstract class PlayerList { + public PlayerList(MinecraftServer minecraftserver) { + minecraftserver.server = new CraftServer(minecraftserver, this); + minecraftserver.console = org.bukkit.craftbukkit.command.ColouredConsoleSender.getInstance(); ++ minecraftserver.reader.addCompleter(new ConsoleCommandCompleter(minecraftserver.server)); + this.cserver = minecraftserver.server; + // CraftBukkit end + +diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java +new file mode 100644 +index 0000000..b108bd1 +--- /dev/null ++++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java +@@ -0,0 +1,46 @@ ++package org.bukkit.craftbukkit.command; ++ ++import jline.console.completer.Completer; ++import org.bukkit.craftbukkit.CraftServer; ++import org.bukkit.craftbukkit.util.Waitable; ++ ++import java.util.List; ++import java.util.concurrent.ExecutionException; ++import java.util.logging.Level; ++ ++public class ConsoleCommandCompleter implements Completer { ++ private final CraftServer server; ++ ++ public ConsoleCommandCompleter(CraftServer server) { ++ this.server = server; ++ } ++ ++ public int complete(final String buffer, final int cursor, final List candidates) { ++ Waitable waitable = new Waitable() { ++ @Override ++ protected Integer evaluate() { ++ List offers = server.getCommandMap().tabComplete(server.getConsoleSender(), buffer); ++ if (offers == null) { ++ return cursor; ++ } ++ candidates.addAll(offers); ++ ++ final int lastSpace = buffer.lastIndexOf(' '); ++ if (lastSpace == -1) { ++ return cursor - buffer.length(); ++ } else { ++ return cursor - (buffer.length() - lastSpace - 1); ++ } ++ } ++ }; ++ this.server.getServer().processQueue.add(waitable); ++ try { ++ return waitable.get(); ++ } catch (ExecutionException e) { ++ this.server.getLogger().log(Level.WARNING, "Unhandled exception when tab completing", e); ++ } catch (InterruptedException e) { ++ Thread.currentThread().interrupt(); ++ } ++ return cursor; ++ } ++} +-- +1.8.1.2 +