From 16f3355bbbd2170dd8f836885f5c887ff65c5f7d Mon Sep 17 00:00:00 2001 From: Debucquoy Anthony tonitch Date: Tue, 25 Oct 2022 13:42:04 +0200 Subject: rework of the color code with & and standard codes (#5416) * adding build* to gitignore and tags for ctags * Notation Changes * Adding & Parser * Avoid crash when & as first character * Looking for @ in the rest of the project * Formating style * Modifying test to reflect new behaviours * Adding a check for the first part * fixup! Adding & Parser style changes * Update APIDesk.lua * Update src/CompositeChat.cpp Co-authored-by: x12xx12x <44411062+12xx12@users.noreply.github.com> * explaination on the antishlash with ampersand * adding old deprecated formating * Update src/CompositeChat.cpp Co-authored-by: x12xx12x <44411062+12xx12@users.noreply.github.com> * Update src/CompositeChat.cpp * Update src/CompositeChat.cpp Co-authored-by: Debucquoy Co-authored-by: x12xx12x <44411062+12xx12@users.noreply.github.com> --- .gitignore | 4 + Server/Plugins/APIDump/APIDesc.lua | 19 +-- src/Bindings/ManualBindings.cpp | 2 +- src/CompositeChat.cpp | 191 +++++++++++------------------- src/CompositeChat.h | 27 ++--- tests/CompositeChat/CompositeChatTest.cpp | 18 +-- 6 files changed, 105 insertions(+), 156 deletions(-) diff --git a/.gitignore b/.gitignore index e271cc019..170ef3697 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build/ +build*/ nbproject/ ipch/ Win32/ @@ -122,3 +123,6 @@ build-cuberite # clang-tidy tidy-build run-clang-tidy.py + +# ctags output +tags diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua index 03fb31990..f920a8f5b 100644 --- a/Server/Plugins/APIDump/APIDesc.lua +++ b/Server/Plugins/APIDump/APIDesc.lua @@ -2228,18 +2228,21 @@ end Chaining example below for details.

Each part of the composite chat message takes a "Style" parameter, this is a string that describes - the formatting. It uses the following strings, concatenated together: + the formatting. It uses the "standard" minecraft format code without the '&' symbole, concatenated + together: - - - - - - + + + + + + +
StringStyle
bBold text
iItalic text
uUnderlined text
sStrikethrough text
oObfuscated text
@Xcolor [0–9a–f], same as dye meta
lBold text
oItalic text
nUnderlined text
mStrikethrough text
kObfuscated text
rReset Style
[0-9a-f]colors
+ You can escape the '&' character with an antislash in front of it. as follow: `I love Choco\&chips` The following picture, taken from the Minecraft Wiki, illustrates the color codes:

- + ]], Functions = { diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index f5517dc84..40ab0467b 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -3949,7 +3949,7 @@ static int tolua_cCompositeChat_AddRunCommandPart(lua_State * tolua_S) } // Add the part: - AString Text, Command, Style = "u@a"; + AString Text, Command, Style = "na"; L.GetStackValue(2, Text); L.GetStackValue(3, Command); L.GetStackValue(4, Style); diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp index 46712a0f5..94ed78197 100644 --- a/src/CompositeChat.cpp +++ b/src/CompositeChat.cpp @@ -96,50 +96,52 @@ void cCompositeChat::AddShowAchievementPart(const AString & a_PlayerName, const - +/** +* Parse the input message to add colors or link then add it to the object. +* +* It detects every & of the message and the next character for it to colorize. +* It detect : in the text to detect link structures. +* +* @param a_ParseText The input text to parse +*/ void cCompositeChat::ParseText(const AString & a_ParseText) { size_t len = a_ParseText.length(); - size_t first = 0; // First character of the currently parsed block + size_t cursor = 0; AString CurrentStyle; AString CurrentText; + for (size_t i = 0; i < len; i++) { switch (a_ParseText[i]) { - case '@': + case '&': //< Color code { - // Color code - i++; - if (i >= len) + if ((i != 0) && (a_ParseText[i-1] == '\\')) { - // Not enough following text - break; + CurrentText.append(a_ParseText, cursor, i - cursor - 1).append("&"); + AddTextPart(CurrentText, CurrentStyle); + CurrentText.clear(); + cursor = ++i; + continue; } - if (a_ParseText[i] == '@') + + if (cursor < i) { - // "@@" escape, just put a "@" into the current text and keep parsing as text - if (i > first + 1) - { - CurrentText.append(a_ParseText.c_str() + first, i - first - 1); - } - first = i + 1; - continue; + CurrentText.append(a_ParseText, cursor, i - cursor); + AddTextPart(CurrentText, CurrentStyle); + CurrentText.clear(); + } + i++; + cursor = i + 1; + + if (a_ParseText[i] == 'r') + { + CurrentStyle = ""; } else { - // True color code. Create a part for the CurrentText and start parsing anew: - if (i >= first) - { - CurrentText.append(a_ParseText.c_str() + first, i - first - 1); - first = i + 1; - } - if (!CurrentText.empty()) - { - AddTextPart(CurrentText, CurrentStyle); - CurrentText.clear(); - } - AddStyle(CurrentStyle, a_ParseText.substr(i - 1, 2)); + CurrentStyle.push_back(a_ParseText[i]); } break; } @@ -157,15 +159,15 @@ void cCompositeChat::ParseText(const AString & a_ParseText) { size_t PrefixLen = Prefix.size(); if ( - (i >= first + PrefixLen) && // There is enough space in front of the colon for the prefix + (i >= cursor + PrefixLen) && // There is enough space in front of the colon for the prefix (std::string_view(a_ParseText).substr(i - PrefixLen, PrefixLen) == Prefix) // the prefix matches ) { // Add everything before this as a text part: - if (i > first + PrefixLen) + if (i > cursor+ PrefixLen) { - CurrentText.append(a_ParseText.c_str() + first, i - first - PrefixLen); - first = i - PrefixLen; + CurrentText.append(a_ParseText.c_str() + cursor, i - cursor - PrefixLen); + cursor= i - PrefixLen; } if (!CurrentText.empty()) { @@ -181,8 +183,8 @@ void cCompositeChat::ParseText(const AString & a_ParseText) break; } } - AddUrlPart(a_ParseText.substr(first, i - first), a_ParseText.substr(first, i - first), CurrentStyle); - first = i; + AddUrlPart(a_ParseText.substr(cursor, i - cursor), a_ParseText.substr(cursor, i - cursor), CurrentStyle); + cursor = i; break; } } // for Prefix - LinkPrefix[] @@ -190,9 +192,11 @@ void cCompositeChat::ParseText(const AString & a_ParseText) } // case ':' } // switch (a_ParseText[i]) } // for i - a_ParseText[] - if (first < len) + if (cursor < len) { - AddTextPart(a_ParseText.substr(first, len - first), CurrentStyle); + CurrentText.clear(); + CurrentText.append(a_ParseText, cursor, len - cursor); + AddTextPart(CurrentText, CurrentStyle); } } @@ -218,7 +222,7 @@ void cCompositeChat::UnderlineUrls(void) { [](TextPart & a_Part) { }, [](ClientTranslatedPart & a_Part) { }, - [](UrlPart & a_Part) { a_Part.Style += 'u'; }, + [](UrlPart & a_Part) { a_Part.Style += 'n'; }, [](RunCommandPart & a_Part) { }, [](SuggestCommandPart & a_Part) { }, [](ShowAchievementPart & a_Part) { }, @@ -276,29 +280,6 @@ eLogLevel cCompositeChat::MessageTypeToLogLevel(eMessageType a_MessageType) -void cCompositeChat::AddStyle(AString & a_Style, const AString & a_AddStyle) -{ - if (a_AddStyle.empty()) - { - return; - } - if (a_AddStyle[0] == '@') - { - size_t idx = a_Style.find('@'); - if ((idx != AString::npos) && (idx != a_Style.length())) - { - a_Style.erase(idx, 2); - } - a_Style.append(a_AddStyle); - return; - } - a_Style.append(a_AddStyle); -} - - - - - AString cCompositeChat::CreateJsonString(bool a_ShouldUseChatPrefixes) const { Json::Value Message; @@ -404,70 +385,34 @@ void cCompositeChat::AddChatPartStyle(Json::Value & a_Value, const AString & a_P { switch (a_PartStyle[i]) { - case 'b': - { - // bold - a_Value["bold"] = Json::Value(true); - break; - } - - case 'i': - { - // italic - a_Value["italic"] = Json::Value(true); - break; - } - - case 'u': - { - // Underlined - a_Value["underlined"] = Json::Value(true); - break; - } + case 'k': a_Value["obfuscated"] = Json::Value(true); break; + case 'l': a_Value["bold"] = Json::Value(true); break; + case 's': // Deprecated + LOGERROR("Value s in AddChatPartStyle() is deprecated"); + case 'm': a_Value["strikethrough"] = Json::Value(true); break; + case 'u': // Deprecated + LOGERROR("Value u in AddChatPartStyle() is deprecated"); + case 'n': a_Value["underlined"] = Json::Value(true); break; + case 'i': // Deprecated + LOGERROR("Value i in AddChatPartStyle() is deprecated"); + case 'o': a_Value["italic"] = Json::Value(true); break; + case '0': a_Value["color"] = Json::Value("black"); break; + case '1': a_Value["color"] = Json::Value("dark_blue"); break; + case '2': a_Value["color"] = Json::Value("dark_green"); break; + case '3': a_Value["color"] = Json::Value("dark_aqua"); break; + case '4': a_Value["color"] = Json::Value("dark_red"); break; + case '5': a_Value["color"] = Json::Value("dark_purple"); break; + case '6': a_Value["color"] = Json::Value("gold"); break; + case '7': a_Value["color"] = Json::Value("gray"); break; + case '8': a_Value["color"] = Json::Value("dark_gray"); break; + case '9': a_Value["color"] = Json::Value("blue"); break; + case 'a': a_Value["color"] = Json::Value("green"); break; + case 'b': a_Value["color"] = Json::Value("aqua"); break; + case 'c': a_Value["color"] = Json::Value("red"); break; + case 'd': a_Value["color"] = Json::Value("light_purple"); break; + case 'e': a_Value["color"] = Json::Value("yellow"); break; + case 'f': a_Value["color"] = Json::Value("white"); break; - case 's': - { - // strikethrough - a_Value["strikethrough"] = Json::Value(true); - break; - } - - case 'o': - { - // obfuscated - a_Value["obfuscated"] = Json::Value(true); - break; - } - - case '@': - { - // Color, specified by the next char: - i++; - if (i >= len) - { - // String too short, didn't contain a color - break; - } - switch (a_PartStyle[i]) - { - case '0': a_Value["color"] = Json::Value("black"); break; - case '1': a_Value["color"] = Json::Value("dark_blue"); break; - case '2': a_Value["color"] = Json::Value("dark_green"); break; - case '3': a_Value["color"] = Json::Value("dark_aqua"); break; - case '4': a_Value["color"] = Json::Value("dark_red"); break; - case '5': a_Value["color"] = Json::Value("dark_purple"); break; - case '6': a_Value["color"] = Json::Value("gold"); break; - case '7': a_Value["color"] = Json::Value("gray"); break; - case '8': a_Value["color"] = Json::Value("dark_gray"); break; - case '9': a_Value["color"] = Json::Value("blue"); break; - case 'a': a_Value["color"] = Json::Value("green"); break; - case 'b': a_Value["color"] = Json::Value("aqua"); break; - case 'c': a_Value["color"] = Json::Value("red"); break; - case 'd': a_Value["color"] = Json::Value("light_purple"); break; - case 'e': a_Value["color"] = Json::Value("yellow"); break; - case 'f': a_Value["color"] = Json::Value("white"); break; - } // switch (color) - } // case '@' } // switch (Style[i]) } // for i - a_PartStyle[] } diff --git a/src/CompositeChat.h b/src/CompositeChat.h index 78c8e0c9b..4150bccc4 100644 --- a/src/CompositeChat.h +++ b/src/CompositeChat.h @@ -21,12 +21,13 @@ Each part corresponds roughly to the behavior supported by the client messaging: - clickable commands (suggest) Each part has a text assigned to it that can be styled. The style is specified using a string, each character / character combination in the string specifies the style to use: - - b = bold - - i = italic - - u = underlined - - s = strikethrough - - o = obfuscated - - @X = color X (X is 0 - 9 or a - f, same as dye meta + - (char from 0 - 9 or a - f) = color X + - k = obfuscated + - l = bold + - m = strikethrough + - n = underlined + - o = italic + - r = reset If the protocol version doesn't support all the features, it degrades gracefully. */ class cCompositeChat @@ -102,7 +103,7 @@ public: cCompositeChat(void); /** Creates a new chat message and parses the text into parts. - Recognizes "http:" and "https:" links and @color-codes. + Recognizes "http:" and "https:" links and &format-character. Uses ParseText() for the actual parsing. Exported manually due to ToLua++ generating extra output parameter. */ cCompositeChat(const AString & a_ParseText, eMessageType a_MessageType = mtCustom); @@ -121,15 +122,15 @@ public: /** Adds a part that opens an URL when clicked. The default style is underlined light blue text. */ - void AddUrlPart(const AString & a_Text, const AString & a_Url, const AString & a_Style = "u@c"); + void AddUrlPart(const AString & a_Text, const AString & a_Url, const AString & a_Style = "nc"); /** Adds a part that runs a command when clicked. The default style is underlined light green text. */ - void AddRunCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style = "u@a"); + void AddRunCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style = "na"); /** Adds a part that suggests a command (enters it into the chat message area, but doesn't send) when clicked. The default style is underlined yellow text. */ - void AddSuggestCommandPart(const AString & a_Text, const AString & a_SuggestedCommand, const AString & a_Style = "u@b"); + void AddSuggestCommandPart(const AString & a_Text, const AString & a_SuggestedCommand, const AString & a_Style = "nb"); /** Adds a part that fully formats a specified achievement using client translatable strings Takes achievement name and player awarded to. Displays as {player} has earned the achievement {achievement_name}. @@ -137,7 +138,7 @@ public: void AddShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style = ""); /** Parses text into various parts, adds those. - Recognizes "http:" and "https:" URLs and @color-codes. */ + Recognizes "http:" and "https:" URLs and &color-codes. */ void ParseText(const AString & a_ParseText); /** Adds the "underline" style to each part that is an URL. */ @@ -185,8 +186,4 @@ protected: /** Additional data pertaining to message type, for example, the name of a mtPrivateMsg sender */ AString m_AdditionalMessageTypeData; - - /** Adds a_AddStyle to a_Style; overwrites the existing style if appropriate. - If the style already contains something that a_AddStyle overrides, it is erased first. */ - void AddStyle(AString & a_Style, const AString & a_AddStyle); } ; // tolua_export diff --git a/tests/CompositeChat/CompositeChatTest.cpp b/tests/CompositeChat/CompositeChatTest.cpp index 636a5c95a..ca05e79a2 100644 --- a/tests/CompositeChat/CompositeChatTest.cpp +++ b/tests/CompositeChat/CompositeChatTest.cpp @@ -14,7 +14,7 @@ static void TestParser1(void) { cCompositeChat Msg; - Msg.ParseText("Testing @2color codes and http://links parser"); + Msg.ParseText("Testing &2color codes and http://links parser"); const auto & Parts = Msg.GetParts(); TEST_EQUAL(Parts.size(), 4); @@ -22,13 +22,13 @@ static void TestParser1(void) TEST_EQUAL(std::get(Parts[0]).Style, ""); TEST_TRUE(std::holds_alternative(Parts[1])); - TEST_EQUAL(std::get(Parts[1]).Style, "@2"); + TEST_EQUAL(std::get(Parts[1]).Style, "2"); TEST_TRUE(std::holds_alternative(Parts[2])); - TEST_EQUAL(std::get(Parts[2]).Style, "@2"); + TEST_EQUAL(std::get(Parts[2]).Style, "2"); TEST_TRUE(std::holds_alternative(Parts[3])); - TEST_EQUAL(std::get(Parts[3]).Style, "@2"); + TEST_EQUAL(std::get(Parts[3]).Style, "2"); } @@ -38,21 +38,21 @@ static void TestParser1(void) static void TestParser2(void) { cCompositeChat Msg; - Msg.ParseText("@3Advanced stuff: @5overriding color codes and http://links.with/@4color-in-them handling"); + Msg.ParseText("&3Advanced stuff: &5overriding color codes and http://links.with/&4color-in-them handling"); const auto & Parts = Msg.GetParts(); TEST_EQUAL(Parts.size(), 4); TEST_TRUE(std::holds_alternative(Parts[0])); - TEST_EQUAL(std::get(Parts[0]).Style, "@3"); + TEST_EQUAL(std::get(Parts[0]).Style, "3"); TEST_TRUE(std::holds_alternative(Parts[1])); - TEST_EQUAL(std::get(Parts[1]).Style, "@5"); + TEST_EQUAL(std::get(Parts[1]).Style, "35"); TEST_TRUE(std::holds_alternative(Parts[2])); - TEST_EQUAL(std::get(Parts[2]).Style, "@5"); + TEST_EQUAL(std::get(Parts[2]).Style, "35"); TEST_TRUE(std::holds_alternative(Parts[3])); - TEST_EQUAL(std::get(Parts[3]).Style, "@5"); + TEST_EQUAL(std::get(Parts[3]).Style, "35"); } -- cgit v1.2.3