mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-01 04:31:58 +01:00
2873869bb1
Signs no longer have a specific isEdiable state, the entire API in this regard needs updating/deprecation. The boolean field is completely gone, replaced by a uuid (which will need a new setEditingPlayer(UUID) method on the Sign interface), and the current upstream implementation of setEdiable simply flips the is_waxed state. This patch is hence not needed as it neither allows editing (which will be redone in a later patch) nor is required to copy the is_waxed boolean flag as it lives in the signs compound tag and is covered by applyTo.
295 lines
14 KiB
Diff
295 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..0627c98cae0b5ebdd71a849ae1299d7d3d581850
|
|
--- /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.PLAIN.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 01e67001435dfa74062fda386072c552b39f2377..6c159945384586e9dbed871d180ae55f1e83e56a 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
|
|
}
|