Skip to content

Commit

Permalink
Merge pull request #1044 from KyoriPowered/fix/legacy-case-sensitivity
Browse files Browse the repository at this point in the history
fix: Allow for case-insensitivity in legacy serializer, closes #1043
  • Loading branch information
zml2008 authored Feb 27, 2024
2 parents 64a79c4 + 87b7672 commit 7aae30f
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import org.jetbrains.annotations.Unmodifiable;

/**
* A combination of a {@code character} and a {@link TextFormat}.
* A combination of a {@code character}, a {@link TextFormat}, and if the character is {@link #caseInsensitive()}.
*
* @since 4.14.0
*/
Expand All @@ -46,152 +46,165 @@ public interface CharacterAndFormat extends Examinable {
*
* @since 4.14.0
*/
CharacterAndFormat BLACK = characterAndFormat('0', NamedTextColor.BLACK);
CharacterAndFormat BLACK = characterAndFormat('0', NamedTextColor.BLACK, true);
/**
* Character and format pair representing {@link NamedTextColor#DARK_BLUE}.
*
* @since 4.14.0
*/
CharacterAndFormat DARK_BLUE = characterAndFormat('1', NamedTextColor.DARK_BLUE);
CharacterAndFormat DARK_BLUE = characterAndFormat('1', NamedTextColor.DARK_BLUE, true);
/**
* Character and format pair representing {@link NamedTextColor#DARK_GREEN}.
*
* @since 4.14.0
*/
CharacterAndFormat DARK_GREEN = characterAndFormat('2', NamedTextColor.DARK_GREEN);
CharacterAndFormat DARK_GREEN = characterAndFormat('2', NamedTextColor.DARK_GREEN, true);
/**
* Character and format pair representing {@link NamedTextColor#DARK_AQUA}.
*
* @since 4.14.0
*/
CharacterAndFormat DARK_AQUA = characterAndFormat('3', NamedTextColor.DARK_AQUA);
CharacterAndFormat DARK_AQUA = characterAndFormat('3', NamedTextColor.DARK_AQUA, true);
/**
* Character and format pair representing {@link NamedTextColor#DARK_RED}.
*
* @since 4.14.0
*/
CharacterAndFormat DARK_RED = characterAndFormat('4', NamedTextColor.DARK_RED);
CharacterAndFormat DARK_RED = characterAndFormat('4', NamedTextColor.DARK_RED, true);
/**
* Character and format pair representing {@link NamedTextColor#DARK_PURPLE}.
*
* @since 4.14.0
*/
CharacterAndFormat DARK_PURPLE = characterAndFormat('5', NamedTextColor.DARK_PURPLE);
CharacterAndFormat DARK_PURPLE = characterAndFormat('5', NamedTextColor.DARK_PURPLE, true);
/**
* Character and format pair representing {@link NamedTextColor#GOLD}.
*
* @since 4.14.0
*/
CharacterAndFormat GOLD = characterAndFormat('6', NamedTextColor.GOLD);
CharacterAndFormat GOLD = characterAndFormat('6', NamedTextColor.GOLD, true);
/**
* Character and format pair representing {@link NamedTextColor#GRAY}.
*
* @since 4.14.0
*/
CharacterAndFormat GRAY = characterAndFormat('7', NamedTextColor.GRAY);
CharacterAndFormat GRAY = characterAndFormat('7', NamedTextColor.GRAY, true);
/**
* Character and format pair representing {@link NamedTextColor#DARK_GRAY}.
*
* @since 4.14.0
*/
CharacterAndFormat DARK_GRAY = characterAndFormat('8', NamedTextColor.DARK_GRAY);
CharacterAndFormat DARK_GRAY = characterAndFormat('8', NamedTextColor.DARK_GRAY, true);
/**
* Character and format pair representing {@link NamedTextColor#BLUE}.
*
* @since 4.14.0
*/
CharacterAndFormat BLUE = characterAndFormat('9', NamedTextColor.BLUE);
CharacterAndFormat BLUE = characterAndFormat('9', NamedTextColor.BLUE, true);
/**
* Character and format pair representing {@link NamedTextColor#GREEN}.
*
* @since 4.14.0
*/
CharacterAndFormat GREEN = characterAndFormat('a', NamedTextColor.GREEN);
CharacterAndFormat GREEN = characterAndFormat('a', NamedTextColor.GREEN, true);
/**
* Character and format pair representing {@link NamedTextColor#AQUA}.
*
* @since 4.14.0
*/
CharacterAndFormat AQUA = characterAndFormat('b', NamedTextColor.AQUA);
CharacterAndFormat AQUA = characterAndFormat('b', NamedTextColor.AQUA, true);
/**
* Character and format pair representing {@link NamedTextColor#RED}.
*
* @since 4.14.0
*/
CharacterAndFormat RED = characterAndFormat('c', NamedTextColor.RED);
CharacterAndFormat RED = characterAndFormat('c', NamedTextColor.RED, true);
/**
* Character and format pair representing {@link NamedTextColor#LIGHT_PURPLE}.
*
* @since 4.14.0
*/
CharacterAndFormat LIGHT_PURPLE = characterAndFormat('d', NamedTextColor.LIGHT_PURPLE);
CharacterAndFormat LIGHT_PURPLE = characterAndFormat('d', NamedTextColor.LIGHT_PURPLE, true);
/**
* Character and format pair representing {@link NamedTextColor#YELLOW}.
*
* @since 4.14.0
*/
CharacterAndFormat YELLOW = characterAndFormat('e', NamedTextColor.YELLOW);
CharacterAndFormat YELLOW = characterAndFormat('e', NamedTextColor.YELLOW, true);
/**
* Character and format pair representing {@link NamedTextColor#WHITE}.
*
* @since 4.14.0
*/
CharacterAndFormat WHITE = characterAndFormat('f', NamedTextColor.WHITE);
CharacterAndFormat WHITE = characterAndFormat('f', NamedTextColor.WHITE, true);

/**
* Character and format pair representing {@link TextDecoration#OBFUSCATED}.
*
* @since 4.14.0
*/
CharacterAndFormat OBFUSCATED = characterAndFormat('k', TextDecoration.OBFUSCATED);
CharacterAndFormat OBFUSCATED = characterAndFormat('k', TextDecoration.OBFUSCATED, true);
/**
* Character and format pair representing {@link TextDecoration#BOLD}.
*
* @since 4.14.0
*/
CharacterAndFormat BOLD = characterAndFormat('l', TextDecoration.BOLD);
CharacterAndFormat BOLD = characterAndFormat('l', TextDecoration.BOLD, true);
/**
* Character and format pair representing {@link TextDecoration#STRIKETHROUGH}.
*
* @since 4.14.0
*/
CharacterAndFormat STRIKETHROUGH = characterAndFormat('m', TextDecoration.STRIKETHROUGH);
CharacterAndFormat STRIKETHROUGH = characterAndFormat('m', TextDecoration.STRIKETHROUGH, true);
/**
* Character and format pair representing {@link TextDecoration#UNDERLINED}.
*
* @since 4.14.0
*/
CharacterAndFormat UNDERLINED = characterAndFormat('n', TextDecoration.UNDERLINED);
CharacterAndFormat UNDERLINED = characterAndFormat('n', TextDecoration.UNDERLINED, true);
/**
* Character and format pair representing {@link TextDecoration#ITALIC}.
*
* @since 4.14.0
*/
CharacterAndFormat ITALIC = characterAndFormat('o', TextDecoration.ITALIC);
CharacterAndFormat ITALIC = characterAndFormat('o', TextDecoration.ITALIC, true);

/**
* Character and format pair representing {@link Reset#INSTANCE}.
*
* @since 4.14.0
*/
CharacterAndFormat RESET = characterAndFormat('r', Reset.INSTANCE);
CharacterAndFormat RESET = characterAndFormat('r', Reset.INSTANCE, true);

/**
* Creates a new combination of a {@code character} and a {@link TextFormat}.
* Creates a new combination of a case-sensitive {@code character} and a {@link TextFormat}.
*
* @param character the character
* @param format the format
* @return a new character and format pair.
* @return a new character and format instance.
* @since 4.14.0
*/
static @NotNull CharacterAndFormat characterAndFormat(final char character, final @NotNull TextFormat format) {
return new CharacterAndFormatImpl(character, format);
return characterAndFormat(character, format, false);
}

/**
* Gets an unmodifiable list of character and format pairs containing all default vanilla formats.
* Creates a new combination of a {@code character} and a {@link TextFormat}.
*
* @return am unmodifiable list of character and format pairs containing all default vanilla formats
* @param character the character
* @param format the format
* @param caseInsensitive if the character is case-insensitive
* @return a new character and format instance.
* @since 4.17.0
*/
static @NotNull CharacterAndFormat characterAndFormat(final char character, final @NotNull TextFormat format, final boolean caseInsensitive) {
return new CharacterAndFormatImpl(character, format, caseInsensitive);
}

/**
* Gets an unmodifiable list of character and format instances containing all default vanilla formats.
*
* @return an unmodifiable list of character and format instances containing all default vanilla formats
* @since 4.14.0
*/
@Unmodifiable
Expand All @@ -215,11 +228,20 @@ public interface CharacterAndFormat extends Examinable {
*/
@NotNull TextFormat format();

/**
* If the {@link #character()} is case-insensitive.
*
* @return if the character is case-insensitive
* @since 4.17.0
*/
boolean caseInsensitive();

@Override
default @NotNull Stream<? extends ExaminableProperty> examinableProperties() {
return Stream.of(
ExaminableProperty.of("character", this.character()),
ExaminableProperty.of("format", this.format())
ExaminableProperty.of("format", this.format()),
ExaminableProperty.of("caseInsensitive", this.caseInsensitive())
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@
final class CharacterAndFormatImpl implements CharacterAndFormat {
private final char character;
private final TextFormat format;
private final boolean caseInsensitive;

CharacterAndFormatImpl(final char character, final @NotNull TextFormat format) {
CharacterAndFormatImpl(final char character, final @NotNull TextFormat format, final boolean caseInsensitive) {
this.character = character;
this.format = requireNonNull(format, "format");
this.caseInsensitive = caseInsensitive;
}

@Override
Expand All @@ -52,19 +54,26 @@ public char character() {
return this.format;
}

@Override
public boolean caseInsensitive() {
return this.caseInsensitive;
}

@Override
public boolean equals(final @Nullable Object other) {
if (this == other) return true;
if (!(other instanceof CharacterAndFormatImpl)) return false;
final CharacterAndFormatImpl that = (CharacterAndFormatImpl) other;
return this.character == that.character
&& this.format.equals(that.format);
&& this.format.equals(that.format)
&& this.caseInsensitive == that.caseInsensitive;
}

@Override
public int hashCode() {
int result = this.character;
result = 31 * result + this.format.hashCode();
result = 31 * result + Boolean.hashCode(this.caseInsensitive);
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,36 @@ static CharacterAndFormatSet of(final List<CharacterAndFormat> pairs) {
final StringBuilder characters = new StringBuilder(size);
for (int i = 0; i < size; i++) {
final CharacterAndFormat pair = pairs.get(i);
characters.append(pair.character());
final char character = pair.character();
final TextFormat format = pair.format();
final boolean formatIsTextColor = format instanceof TextColor;

// First, add the "standard" character.
characters.append(character);
formats.add(format);
if (format instanceof TextColor) {
if (formatIsTextColor) {
colors.add((TextColor) format);
}

// If the character is case-insensitive, we need to add the other character too.
if (pair.caseInsensitive()) {
boolean added = false;

if (Character.isUpperCase(character)) {
characters.append(Character.toLowerCase(character));
added = true;
} else if (Character.isLowerCase(character)) {
characters.append(Character.toUpperCase(character));
added = true;
}

if (added) {
formats.add(format);
if (formatIsTextColor) {
colors.add((TextColor) format);
}
}
}
}
if (formats.size() != characters.length()) {
throw new IllegalStateException("formats length differs from characters length");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package net.kyori.adventure.text.serializer.legacy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
Expand Down Expand Up @@ -331,4 +332,27 @@ void testNullTextFormat() {
final String serialized = serializer.serialize(strikethough);
assertEquals(serialized, "Hello World");
}

// https://github.com/KyoriPowered/adventure/issues/1043
@Test
void testCaseInsensitivity() {
final Component expected = Component.text("pop4959", NamedTextColor.YELLOW);
final Component lowercaseActual = LegacyComponentSerializer.legacyAmpersand().deserialize("&epop4959");
assertEquals(expected, lowercaseActual);

final Component uppercaseActual = LegacyComponentSerializer.legacyAmpersand().deserialize("&Epop4959");
assertEquals(expected, uppercaseActual);
}

@Test
void testCaseSensitivity() {
final Component expected = Component.text("&Epop4959");
final Component lowercaseActual = LegacyComponentSerializer
.legacyAmpersand()
.toBuilder()
.formats(Collections.singletonList(CharacterAndFormat.characterAndFormat('e', NamedTextColor.YELLOW)))
.build()
.deserialize("&Epop4959");
assertEquals(expected, lowercaseActual);
}
}

0 comments on commit 7aae30f

Please sign in to comment.