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:
String | Style |
- b | Bold text |
- i | Italic text |
- u | Underlined text |
- s | Strikethrough text |
- o | Obfuscated text |
- @X | color [0–9a–f], same as dye meta |
+ l | Bold text |
+ o | Italic text |
+ n | Underlined text |
+ m | Strikethrough text |
+ k | Obfuscated text |
+ r | Reset 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