Portál AbcLinuxu, 5. května 2025 10:32

Dotaz: [C++] ANSI Colors a reset

hermes avatar 4.11.2021 19:34 hermes | skóre: 6 | blog: Elektro | BA
[C++] ANSI Colors a reset
Přečteno: 466×
Odpovědět | Admin
Ahojte, robím na jednej konzolovej utilite. kôli zjednodušeniu orientácie tam používam farby.Tie volím cez ANSI escape sekvencie. Inšpiroval som týmto článkom (je to v pythone, ale pre inšpiráciu to stačí).

Do tabuľky vypisujem rôzne hodnoty a veličiny a stringy, skladám cez std::stringstream.

No a zaujímalo by ma, či neexistuje nejaká escape sekvencia, ktorá by dokázala vyresetovať farbu, ale nie na defaultnú farbu ako cez "\x1B[0m", ale na predchádzajúcu farbu. Viete o niečom takom? alebo ANSI nič také nepodporuje? Mohol by som si aktuálnu farbu niekam ukladať a potom sa k nej vrátiť, ale to by mi zbytočne skomplikovalo kód (ale ak to nepojde nejakou escape sekvenciou, tak to tak asi spravím)

Řešení dotazu:


Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

Řešení 1× (Вherzet)
4.11.2021 20:29 z_sk | skóre: 34 | blog: analyzy
Rozbalit Rozbalit vše Re: [C++] ANSI Colors a reset
Odpovědět | | Sbalit | Link | Blokovat | Admin
Ja som o tom nikdy nepočul, o takej feature. Escape sekvencie je LOW level interface, takže predpokladom, že priamo v ňom nie. Uvidí sa, čo iný.
debian.plus@protonmail.com
Řešení 1× (Andrej)
11.11.2021 06:57 Andrej | skóre: 51 | blog: Republic of Mordor
Rozbalit Rozbalit vše Re: [C++] ANSI Colors a reset
Odpovědět | | Sbalit | Link | Blokovat | Admin

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";
}

Založit nové vláknoNahoru

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.