package net.minecraft.client; import com.google.common.collect.Lists; import java.util.List; import java.util.ListIterator; import java.util.Optional; import java.util.function.BiConsumer; import java.util.stream.Collectors; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.network.chat.FormattedText; import net.minecraft.network.chat.Style; import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.FormattedCharSink; import net.minecraft.util.StringDecomposer; import org.apache.commons.lang3.mutable.MutableFloat; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.mutable.MutableObject; import org.jetbrains.annotations.Nullable; @Environment(EnvType.CLIENT) public class StringSplitter { final StringSplitter.WidthProvider widthProvider; public StringSplitter(StringSplitter.WidthProvider widthProvider) { this.widthProvider = widthProvider; } public float stringWidth(@Nullable String content) { if (content == null) { return 0.0F; } else { MutableFloat mutableFloat = new MutableFloat(); StringDecomposer.iterateFormatted(content, Style.EMPTY, (i, style, j) -> { mutableFloat.add(this.widthProvider.getWidth(j, style)); return true; }); return mutableFloat.floatValue(); } } public float stringWidth(FormattedText content) { MutableFloat mutableFloat = new MutableFloat(); StringDecomposer.iterateFormatted(content, Style.EMPTY, (i, style, j) -> { mutableFloat.add(this.widthProvider.getWidth(j, style)); return true; }); return mutableFloat.floatValue(); } public float stringWidth(FormattedCharSequence content) { MutableFloat mutableFloat = new MutableFloat(); content.accept((i, style, j) -> { mutableFloat.add(this.widthProvider.getWidth(j, style)); return true; }); return mutableFloat.floatValue(); } public int plainIndexAtWidth(String content, int maxWidth, Style style) { StringSplitter.WidthLimitedCharSink widthLimitedCharSink = new StringSplitter.WidthLimitedCharSink(maxWidth); StringDecomposer.iterate(content, style, widthLimitedCharSink); return widthLimitedCharSink.getPosition(); } public String plainHeadByWidth(String content, int maxWidth, Style style) { return content.substring(0, this.plainIndexAtWidth(content, maxWidth, style)); } public String plainTailByWidth(String content, int maxWidth, Style style) { MutableFloat mutableFloat = new MutableFloat(); MutableInt mutableInt = new MutableInt(content.length()); StringDecomposer.iterateBackwards(content, style, (j, stylex, k) -> { float f = mutableFloat.addAndGet(this.widthProvider.getWidth(k, stylex)); if (f > maxWidth) { return false; } else { mutableInt.setValue(j); return true; } }); return content.substring(mutableInt.intValue()); } public int formattedIndexByWidth(String content, int maxWidth, Style style) { StringSplitter.WidthLimitedCharSink widthLimitedCharSink = new StringSplitter.WidthLimitedCharSink(maxWidth); StringDecomposer.iterateFormatted(content, style, widthLimitedCharSink); return widthLimitedCharSink.getPosition(); } @Nullable public Style componentStyleAtWidth(FormattedText content, int maxWidth) { StringSplitter.WidthLimitedCharSink widthLimitedCharSink = new StringSplitter.WidthLimitedCharSink(maxWidth); return (Style)content.visit( (style, string) -> StringDecomposer.iterateFormatted(string, style, widthLimitedCharSink) ? Optional.empty() : Optional.of(style), Style.EMPTY ) .orElse(null); } @Nullable public Style componentStyleAtWidth(FormattedCharSequence content, int maxWidth) { StringSplitter.WidthLimitedCharSink widthLimitedCharSink = new StringSplitter.WidthLimitedCharSink(maxWidth); MutableObject