Allow for Component suggestion tooltips in AsyncTabCompleteEvent (#5504)
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Thu, 1 Apr 2021 00:34:02 -0700
|
||||
Subject: [PATCH] Allow for Component suggestion tooltips in
|
||||
AsyncTabCompleteEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/PlayerConnection.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java
|
||||
@@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn {
|
||||
|
||||
// Paper start - async tab completion
|
||||
com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event;
|
||||
- java.util.List<String> completions = new java.util.ArrayList<>();
|
||||
String buffer = packetplayintabcomplete.c();
|
||||
- event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(this.getPlayer(), completions,
|
||||
+ event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(this.getPlayer(),
|
||||
buffer, true, null);
|
||||
event.callEvent();
|
||||
- completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.getCompletions();
|
||||
+ java.util.List<com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion> completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.completions();
|
||||
// If the event isn't handled, we can assume that we have no completions, and so we'll ask the server
|
||||
if (!event.isHandled()) {
|
||||
if (!event.isCancelled()) {
|
||||
@@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn {
|
||||
});
|
||||
}
|
||||
} else if (!completions.isEmpty()) {
|
||||
- com.mojang.brigadier.suggestion.SuggestionsBuilder builder = new com.mojang.brigadier.suggestion.SuggestionsBuilder(packetplayintabcomplete.c(), stringreader.getTotalLength());
|
||||
+ com.mojang.brigadier.suggestion.SuggestionsBuilder builder0 = new com.mojang.brigadier.suggestion.SuggestionsBuilder(packetplayintabcomplete.c(), stringreader.getTotalLength());
|
||||
|
||||
- builder = builder.createOffset(builder.getInput().lastIndexOf(' ') + 1);
|
||||
- completions.forEach(builder::suggest);
|
||||
+ final com.mojang.brigadier.suggestion.SuggestionsBuilder builder = builder0.createOffset(builder0.getInput().lastIndexOf(' ') + 1);
|
||||
+ completions.forEach(completion -> {
|
||||
+ if (completion.tooltip() == null) {
|
||||
+ builder.suggest(completion.suggestion());
|
||||
+ } else {
|
||||
+ builder.suggest(completion.suggestion(), PaperAdventure.asVanilla(completion.tooltip()));
|
||||
+ }
|
||||
+ });
|
||||
com.mojang.brigadier.suggestion.Suggestions suggestions = builder.buildFuture().join();
|
||||
com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getPlayer(), suggestions, buffer);
|
||||
suggestEvent.setCancelled(suggestions.isEmpty());
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
||||
@@ -0,0 +0,0 @@ public class ConsoleCommandCompleter implements Completer {
|
||||
final CraftServer server = this.server.server;
|
||||
final String buffer = line.line();
|
||||
// Async Tab Complete
|
||||
- com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event;
|
||||
- java.util.List<String> completions = new java.util.ArrayList<>();
|
||||
- event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(server.getConsoleSender(), completions,
|
||||
- buffer, true, null);
|
||||
+ final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event =
|
||||
+ new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(server.getConsoleSender(), buffer, true, null);
|
||||
event.callEvent();
|
||||
- completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.getCompletions();
|
||||
+ final List<com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion> completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.completions();
|
||||
|
||||
if (event.isCancelled() || event.isHandled()) {
|
||||
// Still fire sync event with the provided completions, if someone is listening
|
||||
if (!event.isCancelled() && TabCompleteEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
- List<String> finalCompletions = completions;
|
||||
+ List<com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion> finalCompletions = new java.util.ArrayList<>(completions);
|
||||
Waitable<List<String>> syncCompletions = new Waitable<List<String>>() {
|
||||
@Override
|
||||
protected List<String> evaluate() {
|
||||
- org.bukkit.event.server.TabCompleteEvent syncEvent = new org.bukkit.event.server.TabCompleteEvent(server.getConsoleSender(), buffer, finalCompletions);
|
||||
+ org.bukkit.event.server.TabCompleteEvent syncEvent = new org.bukkit.event.server.TabCompleteEvent(server.getConsoleSender(), buffer,
|
||||
+ finalCompletions.stream()
|
||||
+ .map(com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion::suggestion)
|
||||
+ .collect(java.util.stream.Collectors.toList()));
|
||||
return syncEvent.callEvent() ? syncEvent.getCompletions() : com.google.common.collect.ImmutableList.of();
|
||||
}
|
||||
};
|
||||
server.getServer().processQueue.add(syncCompletions);
|
||||
try {
|
||||
- completions = syncCompletions.get();
|
||||
+ final List<String> legacyCompletions = syncCompletions.get();
|
||||
+ completions.removeIf(it -> !legacyCompletions.contains(it.suggestion())); // remove any suggestions that were removed
|
||||
+ // add any new suggestions
|
||||
+ for (final String completion : legacyCompletions) {
|
||||
+ if (notNewSuggestion(completions, completion)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ completions.add(com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion.completion(completion));
|
||||
+ }
|
||||
} catch (InterruptedException | ExecutionException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (!completions.isEmpty()) {
|
||||
- candidates.addAll(completions.stream().map(Candidate::new).collect(java.util.stream.Collectors.toList()));
|
||||
+ for (final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion completion : completions) {
|
||||
+ if (completion.suggestion().isEmpty()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ candidates.add(new Candidate(
|
||||
+ completion.suggestion(),
|
||||
+ completion.suggestion(),
|
||||
+ null,
|
||||
+ io.papermc.paper.adventure.PaperAdventure.PLAIN.serializeOr(completion.tooltip(), null),
|
||||
+ null,
|
||||
+ null,
|
||||
+ false
|
||||
+ ));
|
||||
+ }
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ConsoleCommandCompleter implements Completer {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ private boolean notNewSuggestion(final List<com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion> completions, final String completion) {
|
||||
+ for (final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion it : completions) {
|
||||
+ if (it.suggestion().equals(completion)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
@@ -58,17 +58,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
@@ -0,0 +0,0 @@
|
||||
+package io.papermc.paper.console;
|
||||
+
|
||||
+import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion;
|
||||
+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 net.kyori.adventure.text.Component;
|
||||
+import net.minecraft.commands.CommandListenerWrapper;
|
||||
+import net.minecraft.network.chat.ChatComponentUtils;
|
||||
+import net.minecraft.server.dedicated.DedicatedServer;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.jline.reader.Candidate;
|
||||
+import org.jline.reader.LineReader;
|
||||
+import org.jline.reader.ParsedLine;
|
||||
@@ -77,6 +76,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+import java.util.Collections;
|
||||
+import java.util.List;
|
||||
+
|
||||
+import static com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion.completion;
|
||||
+
|
||||
+public final class BrigadierCommandCompleter {
|
||||
+ private final CommandListenerWrapper commandSourceStack;
|
||||
+ private final DedicatedServer server;
|
||||
@@ -86,9 +87,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ this.commandSourceStack = commandSourceStack;
|
||||
+ }
|
||||
+
|
||||
+ public void complete(final @NonNull LineReader reader, final @NonNull ParsedLine line, final @NonNull List<Candidate> candidates, final @NonNull List<String> stringCompletions) {
|
||||
+ public void complete(final @NonNull LineReader reader, final @NonNull ParsedLine line, final @NonNull List<Candidate> candidates, final @NonNull List<Completion> existing) {
|
||||
+ if (!com.destroystokyo.paper.PaperConfig.enableBrigadierConsoleCompletions) {
|
||||
+ this.addCandidates(candidates, Collections.emptyList(), stringCompletions);
|
||||
+ this.addCandidates(candidates, Collections.emptyList(), existing);
|
||||
+ return;
|
||||
+ }
|
||||
+ final CommandDispatcher<CommandListenerWrapper> dispatcher = this.server.getCommandDispatcher().dispatcher();
|
||||
@@ -96,25 +97,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ this.addCandidates(
|
||||
+ candidates,
|
||||
+ dispatcher.getCompletionSuggestions(results, line.cursor()).join().getList(),
|
||||
+ stringCompletions
|
||||
+ existing
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ private void addCandidates(
|
||||
+ final @NonNull List<Candidate> candidates,
|
||||
+ final @NonNull List<Suggestion> brigSuggestions,
|
||||
+ final @NonNull List<String> stringSuggestions
|
||||
+ final @NonNull List<Completion> existing
|
||||
+ ) {
|
||||
+ final List<Completion> completions = new ArrayList<>();
|
||||
+ brigSuggestions.forEach(it -> completions.add(toCompletion(it)));
|
||||
+ for (final String string : stringSuggestions) {
|
||||
+ if (string.isEmpty() || brigSuggestions.stream().anyMatch(it -> it.getText().equals(string))) {
|
||||
+ for (final Completion completion : existing) {
|
||||
+ if (completion.suggestion().isEmpty() || brigSuggestions.stream().anyMatch(it -> it.getText().equals(completion.suggestion()))) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ completions.add(completion(string));
|
||||
+ completions.add(completion);
|
||||
+ }
|
||||
+ for (final Completion completion : completions) {
|
||||
+ if (completion.completion().isEmpty()) {
|
||||
+ if (completion.suggestion().isEmpty()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ candidates.add(toCandidate(completion));
|
||||
@@ -122,7 +123,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ }
|
||||
+
|
||||
+ private static @NonNull Candidate toCandidate(final @NonNull Completion completion) {
|
||||
+ final String suggestionText = completion.completion();
|
||||
+ final String suggestionText = completion.suggestion();
|
||||
+ final String suggestionTooltip = PaperAdventure.PLAIN.serializeOr(completion.tooltip(), null);
|
||||
+ return new Candidate(
|
||||
+ suggestionText,
|
||||
@@ -149,32 +150,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
+ }
|
||||
+ return stringReader;
|
||||
+ }
|
||||
+
|
||||
+ static final class Completion {
|
||||
+ private final String completion;
|
||||
+ private final Component tooltip;
|
||||
+
|
||||
+ Completion(final @NonNull String completion, final @Nullable Component tooltip) {
|
||||
+ this.completion = completion;
|
||||
+ this.tooltip = tooltip;
|
||||
+ }
|
||||
+
|
||||
+ @NonNull String completion() {
|
||||
+ return this.completion;
|
||||
+ }
|
||||
+
|
||||
+ @Nullable Component tooltip() {
|
||||
+ return this.tooltip;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ static @NonNull Completion completion(final @NonNull String completion) {
|
||||
+ return new Completion(completion, null);
|
||||
+ }
|
||||
+
|
||||
+ static @NonNull Completion completion(final @NonNull String completion, final @Nullable Component tooltip) {
|
||||
+ return new Completion(completion, tooltip);
|
||||
+ }
|
||||
+}
|
||||
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
|
||||
@@ -296,7 +271,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
|
||||
- if (!completions.isEmpty()) {
|
||||
+ if (false && !completions.isEmpty()) {
|
||||
candidates.addAll(completions.stream().map(Candidate::new).collect(java.util.stream.Collectors.toList()));
|
||||
for (final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent.Completion completion : completions) {
|
||||
if (completion.suggestion().isEmpty()) {
|
||||
continue;
|
||||
@@ -0,0 +0,0 @@ public class ConsoleCommandCompleter implements Completer {
|
||||
));
|
||||
}
|
||||
}
|
||||
+ this.addCompletions(reader, line, candidates, completions);
|
||||
return;
|
||||
@@ -320,18 +300,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
candidates.add(new Candidate(completion));
|
||||
}
|
||||
+ */
|
||||
+ this.addCompletions(reader, line, candidates, offers);
|
||||
+ 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
|
||||
@@ -0,0 +0,0 @@ public class ConsoleCommandCompleter implements Completer {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ private void addCompletions(final LineReader reader, final ParsedLine line, final List<Candidate> candidates, final List<String> stringCompletions) {
|
||||
+ this.brigadierCompleter.complete(reader, line, candidates, stringCompletions);
|
||||
+ 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
|
||||
// Paper end
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user