b8edb0e130
Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 6b34da8f SPIGOT-7467: Add getAddress to RemoteConsoleCommandSender CraftBukkit Changes: db4ba2897 SPIGOT-7467: Add getAddress to RemoteConsoleCommandSender 4f7ff4dec PR-1246: Add missing AbstractTestingBase to tests which need them f70a7b68d SPIGOT-7465, MC-264979: Fresh installations print NoSuchFileException for server.properties 8ef7afef6 PR-1240: Call BlockGrowEvent for vines that are growing on additional sides of an existing vine block Spigot Changes: d2eba2c8 Rebuild patches
296 Zeilen
14 KiB
Diff
296 Zeilen
14 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
|
Date: Tue, 30 Mar 2021 16:06:08 -0700
|
|
Subject: [PATCH] Enhance console tab completions for brigadier commands
|
|
|
|
|
|
diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
|
|
index a4070b59e261f0f1ac4beec47b11492f4724bf27..c5d5648f4ca603ef2b1df723b58f9caf4dd3c722 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java
|
|
@@ -16,11 +16,15 @@ public final class PaperConsole extends SimpleTerminalConsole {
|
|
|
|
@Override
|
|
protected LineReader buildReader(LineReaderBuilder builder) {
|
|
- return super.buildReader(builder
|
|
+ builder
|
|
.appName("Paper")
|
|
.variable(LineReader.HISTORY_FILE, java.nio.file.Paths.get(".console_history"))
|
|
.completer(new ConsoleCommandCompleter(this.server))
|
|
- );
|
|
+ .option(LineReader.Option.COMPLETE_IN_WORD, true);
|
|
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().console.enableBrigadierHighlighting) {
|
|
+ builder.highlighter(new io.papermc.paper.console.BrigadierCommandHighlighter(this.server));
|
|
+ }
|
|
+ return super.buildReader(builder);
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java b/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..7a4f4c0a0fdcabd2bc4aa26dc9d76fc150b8435c
|
|
--- /dev/null
|
|
+++ b/src/main/java/io/papermc/paper/console/BrigadierCommandCompleter.java
|
|
@@ -0,0 +1,99 @@
|
|
+package io.papermc.paper.console;
|
|
+
|
|
+import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion;
|
|
+import com.google.common.base.Suppliers;
|
|
+import com.mojang.brigadier.CommandDispatcher;
|
|
+import com.mojang.brigadier.ParseResults;
|
|
+import com.mojang.brigadier.StringReader;
|
|
+import com.mojang.brigadier.suggestion.Suggestion;
|
|
+import io.papermc.paper.adventure.PaperAdventure;
|
|
+import java.util.ArrayList;
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.function.Supplier;
|
|
+import net.minecraft.commands.CommandSourceStack;
|
|
+import net.minecraft.network.chat.ComponentUtils;
|
|
+import net.minecraft.server.dedicated.DedicatedServer;
|
|
+import org.checkerframework.checker.nullness.qual.NonNull;
|
|
+import org.jline.reader.Candidate;
|
|
+import org.jline.reader.LineReader;
|
|
+import org.jline.reader.ParsedLine;
|
|
+
|
|
+import static com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion.completion;
|
|
+
|
|
+public final class BrigadierCommandCompleter {
|
|
+ private final Supplier<CommandSourceStack> commandSourceStack;
|
|
+ private final DedicatedServer server;
|
|
+
|
|
+ public BrigadierCommandCompleter(final @NonNull DedicatedServer server) {
|
|
+ this.server = server;
|
|
+ this.commandSourceStack = Suppliers.memoize(this.server::createCommandSourceStack);
|
|
+ }
|
|
+
|
|
+ public void complete(final @NonNull LineReader reader, final @NonNull ParsedLine line, final @NonNull List<Candidate> candidates, final @NonNull List<Completion> existing) {
|
|
+ //noinspection ConstantConditions
|
|
+ if (this.server.overworld() == null) { // check if overworld is null, as worlds haven't been loaded yet
|
|
+ return;
|
|
+ } else if (!io.papermc.paper.configuration.GlobalConfiguration.get().console.enableBrigadierCompletions) {
|
|
+ this.addCandidates(candidates, Collections.emptyList(), existing);
|
|
+ return;
|
|
+ }
|
|
+ final CommandDispatcher<CommandSourceStack> dispatcher = this.server.getCommands().getDispatcher();
|
|
+ final ParseResults<CommandSourceStack> results = dispatcher.parse(prepareStringReader(line.line()), this.commandSourceStack.get());
|
|
+ this.addCandidates(
|
|
+ candidates,
|
|
+ dispatcher.getCompletionSuggestions(results, line.cursor()).join().getList(),
|
|
+ existing
|
|
+ );
|
|
+ }
|
|
+
|
|
+ private void addCandidates(
|
|
+ final @NonNull List<Candidate> candidates,
|
|
+ final @NonNull List<Suggestion> brigSuggestions,
|
|
+ final @NonNull List<Completion> existing
|
|
+ ) {
|
|
+ final List<Completion> completions = new ArrayList<>();
|
|
+ brigSuggestions.forEach(it -> completions.add(toCompletion(it)));
|
|
+ for (final Completion completion : existing) {
|
|
+ if (completion.suggestion().isEmpty() || brigSuggestions.stream().anyMatch(it -> it.getText().equals(completion.suggestion()))) {
|
|
+ continue;
|
|
+ }
|
|
+ completions.add(completion);
|
|
+ }
|
|
+ for (final Completion completion : completions) {
|
|
+ if (completion.suggestion().isEmpty()) {
|
|
+ continue;
|
|
+ }
|
|
+ candidates.add(toCandidate(completion));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static @NonNull Candidate toCandidate(final @NonNull Completion completion) {
|
|
+ final String suggestionText = completion.suggestion();
|
|
+ final String suggestionTooltip = PaperAdventure.ANSI_SERIALIZER.serializeOr(completion.tooltip(), null);
|
|
+ return new Candidate(
|
|
+ suggestionText,
|
|
+ suggestionText,
|
|
+ null,
|
|
+ suggestionTooltip,
|
|
+ null,
|
|
+ null,
|
|
+ false
|
|
+ );
|
|
+ }
|
|
+
|
|
+ private static @NonNull Completion toCompletion(final @NonNull Suggestion suggestion) {
|
|
+ if (suggestion.getTooltip() == null) {
|
|
+ return completion(suggestion.getText());
|
|
+ }
|
|
+ return completion(suggestion.getText(), PaperAdventure.asAdventure(ComponentUtils.fromMessage(suggestion.getTooltip())));
|
|
+ }
|
|
+
|
|
+ static @NonNull StringReader prepareStringReader(final @NonNull String line) {
|
|
+ final StringReader stringReader = new StringReader(line);
|
|
+ if (stringReader.canRead() && stringReader.peek() == '/') {
|
|
+ stringReader.skip();
|
|
+ }
|
|
+ return stringReader;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java b/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..dd9d77d7c7f1a5a130a1f4c15e5b1e68ae3753e1
|
|
--- /dev/null
|
|
+++ b/src/main/java/io/papermc/paper/console/BrigadierCommandHighlighter.java
|
|
@@ -0,0 +1,70 @@
|
|
+package io.papermc.paper.console;
|
|
+
|
|
+import com.google.common.base.Suppliers;
|
|
+import com.mojang.brigadier.ParseResults;
|
|
+import com.mojang.brigadier.context.ParsedCommandNode;
|
|
+import com.mojang.brigadier.tree.LiteralCommandNode;
|
|
+import java.util.function.Supplier;
|
|
+import java.util.regex.Pattern;
|
|
+import net.minecraft.commands.CommandSourceStack;
|
|
+import net.minecraft.server.dedicated.DedicatedServer;
|
|
+import org.checkerframework.checker.nullness.qual.NonNull;
|
|
+import org.jline.reader.Highlighter;
|
|
+import org.jline.reader.LineReader;
|
|
+import org.jline.utils.AttributedString;
|
|
+import org.jline.utils.AttributedStringBuilder;
|
|
+import org.jline.utils.AttributedStyle;
|
|
+
|
|
+public final class BrigadierCommandHighlighter implements Highlighter {
|
|
+ private static final int[] COLORS = {AttributedStyle.CYAN, AttributedStyle.YELLOW, AttributedStyle.GREEN, AttributedStyle.MAGENTA, /* Client uses GOLD here, not BLUE, however there is no GOLD AttributedStyle. */ AttributedStyle.BLUE};
|
|
+ private final Supplier<CommandSourceStack> commandSourceStack;
|
|
+ private final DedicatedServer server;
|
|
+
|
|
+ public BrigadierCommandHighlighter(final @NonNull DedicatedServer server) {
|
|
+ this.server = server;
|
|
+ this.commandSourceStack = Suppliers.memoize(this.server::createCommandSourceStack);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public AttributedString highlight(final @NonNull LineReader reader, final @NonNull String buffer) {
|
|
+ //noinspection ConstantConditions
|
|
+ if (this.server.overworld() == null) { // check if overworld is null, as worlds haven't been loaded yet
|
|
+ return new AttributedString(buffer, AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
|
|
+ }
|
|
+ final AttributedStringBuilder builder = new AttributedStringBuilder();
|
|
+ final ParseResults<CommandSourceStack> results = this.server.getCommands().getDispatcher().parse(BrigadierCommandCompleter.prepareStringReader(buffer), this.commandSourceStack.get());
|
|
+ int pos = 0;
|
|
+ if (buffer.startsWith("/")) {
|
|
+ builder.append("/", AttributedStyle.DEFAULT);
|
|
+ pos = 1;
|
|
+ }
|
|
+ int component = -1;
|
|
+ for (final ParsedCommandNode<CommandSourceStack> node : results.getContext().getLastChild().getNodes()) {
|
|
+ if (node.getRange().getStart() >= buffer.length()) {
|
|
+ break;
|
|
+ }
|
|
+ final int start = node.getRange().getStart();
|
|
+ final int end = Math.min(node.getRange().getEnd(), buffer.length());
|
|
+ builder.append(buffer.substring(pos, start), AttributedStyle.DEFAULT);
|
|
+ if (node.getNode() instanceof LiteralCommandNode) {
|
|
+ builder.append(buffer.substring(start, end), AttributedStyle.DEFAULT);
|
|
+ } else {
|
|
+ if (++component >= COLORS.length) {
|
|
+ component = 0;
|
|
+ }
|
|
+ builder.append(buffer.substring(start, end), AttributedStyle.DEFAULT.foreground(COLORS[component]));
|
|
+ }
|
|
+ pos = end;
|
|
+ }
|
|
+ if (pos < buffer.length()) {
|
|
+ builder.append((buffer.substring(pos)), AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
|
|
+ }
|
|
+ return builder.toAttributedString();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void setErrorPattern(final Pattern errorPattern) {}
|
|
+
|
|
+ @Override
|
|
+ public void setErrorIndex(final int errorIndex) {}
|
|
+}
|
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
index 89b6cbc3721cdd8000ae34c33dec1d4458cf55d3..3acdac903ec7afb034f86d725ca0dc949babd1fc 100644
|
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
@@ -173,7 +173,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
|
|
thread.setDaemon(true);
|
|
thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(DedicatedServer.LOGGER));
|
|
- thread.start();
|
|
+ // thread.start(); // Paper - moved down
|
|
DedicatedServer.LOGGER.info("Starting minecraft server version {}", SharedConstants.getCurrentVersion().getName());
|
|
if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) {
|
|
DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\"");
|
|
@@ -205,6 +205,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
this.getPlayerList().loadAndSaveFiles(); // Must be after convertNames
|
|
// Paper end - moved up
|
|
org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash);
|
|
+ thread.start(); // Paper - start console thread after MinecraftServer.console & PaperConfig are initialized
|
|
io.papermc.paper.command.PaperCommands.registerCommands(this);
|
|
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics();
|
|
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
|
index 14cd8ae69d9b25dc5edad4ff96ff4a9acb1f22cb..cd4ad8261e56365850068db1d83d6a8454026737 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
|
@@ -18,9 +18,11 @@ import org.bukkit.event.server.TabCompleteEvent;
|
|
|
|
public class ConsoleCommandCompleter implements Completer {
|
|
private final DedicatedServer server; // Paper - CraftServer -> DedicatedServer
|
|
+ private final io.papermc.paper.console.BrigadierCommandCompleter brigadierCompleter; // Paper
|
|
|
|
public ConsoleCommandCompleter(DedicatedServer server) { // Paper - CraftServer -> DedicatedServer
|
|
this.server = server;
|
|
+ this.brigadierCompleter = new io.papermc.paper.console.BrigadierCommandCompleter(this.server); // Paper
|
|
}
|
|
|
|
// Paper start - Change method signature for JLine update
|
|
@@ -64,7 +66,7 @@ public class ConsoleCommandCompleter implements Completer {
|
|
}
|
|
}
|
|
|
|
- if (!completions.isEmpty()) {
|
|
+ if (false && !completions.isEmpty()) {
|
|
for (final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion completion : completions) {
|
|
if (completion.suggestion().isEmpty()) {
|
|
continue;
|
|
@@ -80,6 +82,7 @@ public class ConsoleCommandCompleter implements Completer {
|
|
));
|
|
}
|
|
}
|
|
+ this.addCompletions(reader, line, candidates, completions);
|
|
return;
|
|
}
|
|
|
|
@@ -99,10 +102,12 @@ public class ConsoleCommandCompleter implements Completer {
|
|
try {
|
|
List<String> offers = waitable.get();
|
|
if (offers == null) {
|
|
+ this.addCompletions(reader, line, candidates, Collections.emptyList()); // Paper
|
|
return; // Paper - Method returns void
|
|
}
|
|
|
|
// Paper start - JLine update
|
|
+ /*
|
|
for (String completion : offers) {
|
|
if (completion.isEmpty()) {
|
|
continue;
|
|
@@ -110,6 +115,8 @@ public class ConsoleCommandCompleter implements Completer {
|
|
|
|
candidates.add(new Candidate(completion));
|
|
}
|
|
+ */
|
|
+ this.addCompletions(reader, line, candidates, offers.stream().map(com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion::completion).collect(java.util.stream.Collectors.toList()));
|
|
// Paper end
|
|
|
|
// Paper start - JLine handles cursor now
|
|
@@ -138,5 +145,9 @@ public class ConsoleCommandCompleter implements Completer {
|
|
}
|
|
return false;
|
|
}
|
|
+
|
|
+ private void addCompletions(final LineReader reader, final ParsedLine line, final List<Candidate> candidates, final List<com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion> existing) {
|
|
+ this.brigadierCompleter.complete(reader, line, candidates, existing);
|
|
+ }
|
|
// Paper end
|
|
}
|