Portál AbcLinuxu, 5. května 2025 10:32
Řešení dotazu:
C++ má přesně k takovým účelům (udržování kontextu a návrat do původního stavu) své standardní mechanismy. Předchozí barva se dá jednoduše ukládat na zásobník a pak nechat obnovit destruktorem.
Uvedený příklad není (kvůli statické proměnné) thread-safe, nicméně to by nemuselo vadit, protože terminál bývá jeden.
Taky to podporuje jenom 256 barev místo 24-bitových, ale to se dá celkem triviálně doplnit.
#include <cstdint> #include <ios> #include <iostream> #include <string> #include <string_view> #include <utility> using std::uint8_t; using std::size_t; class Color { class Value { const std::string code_; public: Value(std::string_view code); // C++20: constexpr std::ostream& operator ()(std::ostream &out) const; }; Color(std::ostream *out, const Value &previous, const Value &value, bool value_owned); std::ostream& operator ()(std::ostream &out); static const Value *_current; std::ostream *out_; const Value &previous_; const Value &value_; const bool value_owned_; friend std::ostream& operator <<(std::ostream& out, Color &&color); public: Color(Value &&value); Color(const Value &value); Color(std::ostream &out, Value &&value); Color(std::ostream &out, const Value &value); static Value custom(uint8_t color); // C++20: constexpr ~Color(); static const Value THICK; // C++20: constexpr static const Value RESET; // C++20: constexpr static const Value BLACK; // C++20: constexpr static const Value RED; // C++20: constexpr static const Value GREEN; // C++20: constexpr static const Value YELLOW; // C++20: constexpr static const Value BLUE; // C++20: constexpr static const Value MAGENTA; // C++20: constexpr static const Value CYAN; // C++20: constexpr static const Value WHITE; // C++20: constexpr }; Color::Value::Value(std::string_view code) : code_{code} {} std::ostream& Color::Value::operator ()(std::ostream &out) const { return out << code_; } Color::Color(std::ostream *out, const Value &previous, const Value &value, bool value_owned) : out_{out}, previous_{previous}, value_{value}, value_owned_(value_owned) {} std::ostream& Color::operator ()(std::ostream& out) { out_ = &out; _current = &value_; return value_(out); } Color::Color(Value &&value) : Color{nullptr, *_current, *new Value{std::move(value)}, true} {} Color::Color(const Value &value) : Color{nullptr, *_current, value, false} {} Color::Color(std::ostream &out, Value &&value) : Color{&out, *_current, *new Value{std::move(value)}, true} { _current = &value_; value(out); } Color::Color(std::ostream& out, const Value& value) : Color{&out, *_current, value, false} { _current = &value_; value(out); } Color::Value Color::custom(uint8_t color) { return Value("\u001B[38;5;" + std::to_string(color) + 'm'); } Color::~Color() { if (out_) previous_(*out_); _current = &previous_; if (value_owned_) delete &value_; } std::ostream& operator <<(std::ostream& out, Color &&color) { return color(out); } const Color::Value Color::RESET{"\u001B[0m"}; const Color::Value Color::THICK{"\u001B[0;1m"}; const Color::Value Color::BLACK{"\u001B[30;1m"}; const Color::Value Color::RED{"\u001B[31;1m"}; const Color::Value Color::GREEN{"\u001B[32;1m"}; const Color::Value Color::YELLOW{"\u001B[33;1m"}; const Color::Value Color::BLUE{"\u001B[34;1m"}; const Color::Value Color::MAGENTA{"\u001B[35;1m"}; const Color::Value Color::CYAN{"\u001B[36;1m"}; const Color::Value Color::WHITE{"\u001B[37;1m"}; const Color::Value *Color::_current = &Color::RESET; void recursion(size_t base, size_t shift) { if (shift < 16) { Color next{std::cout, Color::custom(base + shift)}; // overflow intended std::cout << shift; recursion(base, shift + 1); std::cout << shift; } else { std::cout << " █ "; std::cout << Color{Color::BLACK} << 'K' << Color{Color::RED} << 'R' << Color{Color::GREEN} << 'G' << Color{Color::YELLOW} << 'Y' << Color{Color::BLUE} << 'B' << Color{Color::MAGENTA} << 'M' << Color{Color::CYAN} << 'C' << Color{Color::WHITE} << 'W'; std::cout << " █ "; } } int main() { std::cout << std::hex << '\n'; std::cout << Color{Color::THICK} << '>' << Color{Color::BLACK} << "black" << Color{Color::THICK} << '<' << Color{Color::RED} << " red" << Color{Color::GREEN} << " green" << Color{Color::YELLOW} << " yellow" << Color{Color::BLUE} << " blue" << Color{Color::MAGENTA} << " magenta" << Color{Color::CYAN} << " cyan" << Color{Color::WHITE} << " white"; std::cout << "\n\n"; std::cout << "This is the default.\n"; { Color red{std::cout, Color::RED}; std::cout << "This is red.\n"; { Color green{std::cout, Color::GREEN}; std::cout << "This is green.\n"; { Color blue{std::cout, Color::BLUE}; std::cout << "This is blue.\n"; std::cout << Color{Color::YELLOW} << "This is yellow.\n"; std::cout << "This is blue.\n"; } std::cout << "This is green.\n"; } std::cout << "This is red.\n"; } std::cout << "This is the default.\n\n"; for (size_t color = 0; color < 256; ++color) { recursion(color, 0); std::cout << '\n'; } std::cout << '\n'; { Color thick{std::cout, Color::THICK}; std::cout << "This is fucking thick!!!\n"; std::cout << Color{Color::custom(77)} << "And this is almost green.\n"; std::cout << "Thick again.\n"; Color orange{std::cout, Color::custom(208)}; std::cout << "This is an arbitrary orange color.\n"; } std::cout << "And this is the default again!\n\n"; }
Tiskni
Sdílej:
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.