mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-01 08:20:51 +01:00
de04cbced5
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: f29cb801 Separate checkstyle-suppressions file is not required 86f99bbe SPIGOT-7540, PR-946: Add ServerTickManager API d4119585 SPIGOT-6903, PR-945: Add BlockData#getMapColor b7a2ed41 SPIGOT-7530, PR-947: Add Player#removeResourcePack 9dd56255 SPIGOT-7527, PR-944: Add WindCharge#explode() 994a6163 Attempt upgrade of resolver libraries CraftBukkit Changes: b3b43a6ad Add Checkstyle check for unused imports 13fb3358e SPIGOT-7544: Scoreboard#getEntries() doesn't get entries but class names 3dda99c06 SPIGOT-7540, PR-1312: Add ServerTickManager API 2ab4508c0 SPIGOT-6903, PR-1311: Add BlockData#getMapColor 1dbdbbed4 PR-1238: Remove unnecessary sign ticking 659728d2a MC-264285, SPIGOT-7439, PR-1237: Fix unbreakable flint and steel is completely consumed while igniting creeper e37e29ce0 Increase outdated build delay c00438b39 SPIGOT-7530, PR-1313: Add Player#removeResourcePack 492dd80ce SPIGOT-7527, PR-1310: Add WindCharge#explode() e11fbb9d7 Upgrade MySQL driver 9f3a0bd2a Attempt upgrade of resolver libraries 60d16d7ca PR-1306: Centralize Bukkit and Minecraft entity conversion Spigot Changes: 06d602e7 Rebuild patches
296 lines
14 KiB
Diff
296 lines
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 e92708f60fec876c62e720420f133a9b28c6f66f..3cacbbc03a3207656b71a1a05d95dbb750815bab 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 8f82041f0482df22a6a9ea38d50d56228131775d..12eeabafbad9da8796dc6fc383b732cf75bb7ddb 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
|
|
}
|