From 9de94d91ac5323e515838f2e0155a3dc945d37ac Mon Sep 17 00:00:00 2001 From: sciwhiz12 Date: Mon, 16 Sep 2024 06:05:14 +0800 Subject: [PATCH 1/2] Truncate tags command clipboard text to 1000 entries Fixes #1543 --- .../neoforge/server/command/TagsCommand.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/server/command/TagsCommand.java b/src/main/java/net/neoforged/neoforge/server/command/TagsCommand.java index 7586efd3e4..167514f56f 100644 --- a/src/main/java/net/neoforged/neoforge/server/command/TagsCommand.java +++ b/src/main/java/net/neoforged/neoforge/server/command/TagsCommand.java @@ -52,6 +52,10 @@ * */ class TagsCommand { + // The limit of how many elements can be in the clipboard text at once + // Roughly equal to how many 32-characters-long elements can fit into a 32,767-long string + // (which is the default limit for UTF-8 strings in FriendlyByteBuf + private static final long CLIPBOARD_TEXT_ELEMENTS_LIMIT = 1000; private static final long PAGE_SIZE = 8; private static final ResourceKey>> ROOT_REGISTRY_KEY = ResourceKey.createRegistryKey(ResourceLocation.withDefaultNamespace("root")); @@ -172,16 +176,26 @@ private static MutableComponent createMessage(final MutableComponent header, final long currentPage, final ChatFormatting elementColor, final Supplier> names) { - final String allElementNames = names.get().sorted().collect(Collectors.joining("\n")); final long totalPages = (count - 1) / PAGE_SIZE + 1; final long actualPage = (long) Mth.clamp(currentPage, 1, totalPages); MutableComponent containsComponent = Component.translatable(containsText, count); if (count > 0) // Highlight the count text, make it clickable, and append page counters { + final String clipboardText; + final String clipboardElements = names.get().sorted().limit(CLIPBOARD_TEXT_ELEMENTS_LIMIT).collect(Collectors.joining("\n")); + if (count > CLIPBOARD_TEXT_ELEMENTS_LIMIT) { + // Over the limit; add additional info to clipboard text + clipboardText = "(Too many entries to fit in clipboard, showing only first " + CLIPBOARD_TEXT_ELEMENTS_LIMIT + " entries...)" + '\n' + + clipboardElements + '\n' + + "(..." + (count - CLIPBOARD_TEXT_ELEMENTS_LIMIT) + " more entries not shown)"; + } else { + clipboardText = clipboardElements; + } + containsComponent = ComponentUtils.wrapInSquareBrackets(containsComponent.withStyle(s -> s .withColor(ChatFormatting.GREEN) - .withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, allElementNames)) + .withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, clipboardText)) .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.translatable(copyHoverText))))); containsComponent = Component.translatable("commands.neoforge.tags.page_info", From 297c5cee1c93bb61f93d067837d7c1a1eaf49ede Mon Sep 17 00:00:00 2001 From: sciwhiz12 Date: Mon, 18 Nov 2024 17:41:03 +0800 Subject: [PATCH 2/2] Change truncation strategy to fit as much text This may be less elegant to look at and read, but it fits more into the 32.6k limit we (artificially) set for the clipboard text by actually measuring the text as we go add more elements, until no more can fit within the limit. --- .../neoforge/server/command/TagsCommand.java | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/server/command/TagsCommand.java b/src/main/java/net/neoforged/neoforge/server/command/TagsCommand.java index 1350dca3d2..8645cc8733 100644 --- a/src/main/java/net/neoforged/neoforge/server/command/TagsCommand.java +++ b/src/main/java/net/neoforged/neoforge/server/command/TagsCommand.java @@ -11,9 +11,9 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import java.util.Iterator; import java.util.Optional; import java.util.function.Supplier; -import java.util.stream.Collectors; import java.util.stream.Stream; import net.minecraft.ChatFormatting; import net.minecraft.commands.CommandSourceStack; @@ -51,10 +51,10 @@ * */ class TagsCommand { - // The limit of how many elements can be in the clipboard text at once - // Roughly equal to how many 32-characters-long elements can fit into a 32,767-long string - // (which is the default limit for UTF-8 strings in FriendlyByteBuf - private static final long CLIPBOARD_TEXT_ELEMENTS_LIMIT = 1000; + // The limit of how long the clipboard text can be; no more elements are added to the text if they would push it over this limit + // This is roughly below 32767, the default limit for UTF-8 strings in FriendlyByteBuf. When adjusting this, make sure to leave + // ample room for the explanatory text (see #createMessage() below). + private static final long CLIPBOARD_TEXT_LIMIT = 32600; private static final long PAGE_SIZE = 8; private static final ResourceKey>> ROOT_REGISTRY_KEY = ResourceKey.createRegistryKey(ResourceLocation.withDefaultNamespace("root")); @@ -182,14 +182,33 @@ private static MutableComponent createMessage(final MutableComponent header, if (count > 0) // Highlight the count text, make it clickable, and append page counters { final String clipboardText; - final String clipboardElements = names.get().sorted().limit(CLIPBOARD_TEXT_ELEMENTS_LIMIT).collect(Collectors.joining("\n")); - if (count > CLIPBOARD_TEXT_ELEMENTS_LIMIT) { - // Over the limit; add additional info to clipboard text - clipboardText = "(Too many entries to fit in clipboard, showing only first " + CLIPBOARD_TEXT_ELEMENTS_LIMIT + " entries...)" + '\n' - + clipboardElements + '\n' - + "(..." + (count - CLIPBOARD_TEXT_ELEMENTS_LIMIT) + " more entries not shown)"; + final StringBuilder clipboardTextBuilder = new StringBuilder(); + boolean reachedLimit = false; + int countedLines = 0; + + Iterator iterator = names.get().sorted().iterator(); + while (iterator.hasNext()) { + final String line = iterator.next(); + if (clipboardTextBuilder.length() + line.length() > CLIPBOARD_TEXT_LIMIT) { + // The to-be-added line puts us over the limit, so stop adding lines + reachedLimit = true; + break; + } + clipboardTextBuilder.append(line).append('\n'); + countedLines++; + } + // Remove the trailing newline if present + if (!clipboardTextBuilder.isEmpty()) { + clipboardTextBuilder.deleteCharAt(clipboardTextBuilder.length() - 1); + } + + if (reachedLimit) { + // Almost went over the limit; add additional info to clipboard text + clipboardText = "(Too many entries to fit in clipboard, showing only first " + countedLines + " entries...)" + '\n' + + clipboardTextBuilder + '\n' + + "(..." + (count - countedLines) + " more entries not shown)"; } else { - clipboardText = clipboardElements; + clipboardText = clipboardTextBuilder.toString(); } containsComponent = ComponentUtils.wrapInSquareBrackets(containsComponent.withStyle(s -> s