From 92c33c191ae0604278f3e858ff447c72d739f864 Mon Sep 17 00:00:00 2001 From: DolceTriade Date: Sun, 28 Jul 2024 16:44:28 -0700 Subject: [PATCH] color: Add the ability to selectively preserve colors This adds back the "DECOLOR" functionality that was removed as part of https://github.com/Unvanquished/Unvanquished/commit/d61c9d2237ddf2df04799f33e91f9477a3bc79d3. No motivation was given for the removal, and the DECOLOR functionality is important for external tools that parse game logs to display player colors leading to a richer experience. --- src/common/Color.cpp | 50 ++++++++++++++++++++++++++++++++++++++-- src/common/Color.h | 4 ++++ src/common/ColorTest.cpp | 12 +++++++++- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/common/Color.cpp b/src/common/Color.cpp index c28965156f..3148aa855c 100644 --- a/src/common/Color.cpp +++ b/src/common/Color.cpp @@ -86,9 +86,30 @@ int StrlenNocolor( const char *string ) void StripColors( const char *in, char *out, size_t len ) { + bool preserveColor = false; + for ( const auto& token : Parser( in ) ) { - Str::StringView text = token.PlainText(); + if ( token.Type() == Token::TokenType::CONTROL ) + { + if ( token.RawToken().size() != 1 ) + { + Log::Warn( "Invalid control token of length %d", token.RawToken().size() ); + continue; + } + switch ( token.RawToken()[0] ) + { + case Constants::DECOLOR_ON: + preserveColor = false; + break; + case Constants::DECOLOR_OFF: + preserveColor = true; + break; + } + continue; + } + Str::StringView text = ( preserveColor && token.Type() == Token::TokenType::COLOR ) ? + token.RawToken() : token.PlainText(); if ( text.size() >= len ) { break; @@ -106,9 +127,30 @@ std::string StripColors( Str::StringRef input ) std::string output; output.reserve( input.size() ); + bool preserveColor = false; + for ( const auto& token : Parser( input.c_str() ) ) { - Str::StringView text = token.PlainText(); + if ( token.Type() == Token::TokenType::CONTROL ) + { + if ( token.RawToken().size() != 1 ) + { + Log::Warn( "Invalid control token of length %d", token.RawToken().size() ); + continue; + } + switch ( token.RawToken()[0] ) + { + case Constants::DECOLOR_ON: + preserveColor = false; + break; + case Constants::DECOLOR_OFF: + preserveColor = true; + break; + } + continue; + } + Str::StringView text = ( preserveColor && token.Type() == Token::TokenType::COLOR ) ? + token.RawToken() : token.PlainText(); output.append( text.begin(), text.end() ); } @@ -210,6 +252,10 @@ TokenIterator::value_type TokenIterator::NextToken(const char* input) } } } + else if ( input[0] == Constants::DECOLOR_ON || input[0] == Constants::DECOLOR_OFF ) + { + return value_type( input, input + 1, value_type::TokenType::CONTROL ); + } return value_type( input, input + Q_UTF8_Width( input ), value_type::TokenType::CHARACTER ); } diff --git a/src/common/Color.h b/src/common/Color.h index 8c98ebc74c..64ca9092f3 100644 --- a/src/common/Color.h +++ b/src/common/Color.h @@ -344,6 +344,9 @@ namespace Constants { enum { ESCAPE = '^', NULL_COLOR = '*', + // Magic chars to preserve colors between DECOLOR_OFF and DECOLOR_ON when calling StripColors. + DECOLOR_OFF = '\16', + DECOLOR_ON = '\17', }; // enum } // namespace Constants @@ -371,6 +374,7 @@ class Token CHARACTER, // A character ESCAPE, // Color escape COLOR, // Color code + CONTROL, // Control character (basically controlling decolor behavior.) }; /* diff --git a/src/common/ColorTest.cpp b/src/common/ColorTest.cpp index c52c891066..5d2fd0a474 100644 --- a/src/common/ColorTest.cpp +++ b/src/common/ColorTest.cpp @@ -42,6 +42,11 @@ TEST(StripColorTest, ReturningString) std::string onlyColors = "^xF1A^1^0^O^9^a^;^*^xeE2^#123Aa5^#3903ff"; EXPECT_EQ("", StripColors(onlyColors)); + + // Decolor + std::string decolor = Str::Format("%c^1wtf^#aabbccbad%c^1a^2c^^^3c", Constants::DECOLOR_ON, Constants::DECOLOR_OFF); + EXPECT_EQ("wtfbad^1a^2c^^3c", StripColors(decolor)); + } TEST(StripColorTest, ToBuffer) @@ -57,8 +62,13 @@ TEST(StripColorTest, ToBuffer) char justright[7]; StripColors("dretc^#123456h", justright, sizeof(justright)); EXPECT_EQ("dretch", std::string(justright)); + + // Decolor + char decolorjustright[9]; + StripColors(Str::Format("%c^1dretc%c^#123456h", Constants::DECOLOR_OFF, Constants::DECOLOR_ON).c_str(), decolorjustright, sizeof(decolorjustright)); + EXPECT_EQ("^1dretch", std::string(decolorjustright)); + } } // namespace } // namespace Color -