123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 |
- #ifndef ANSICOLOR_H
- #define ANSICOLOR_H
- #include <cstdint>
- #include <string>
- #include <stdexcept>
- #define CSI "\x1b["
- /**
- * ANSI Color codes
- */
- /**
- * @brief The colors available under ANSI-BBS
- */
- enum class COLOR : std::int8_t {
- /// BLACK (0)
- BLACK,
- /// RED (1)
- RED,
- /// GREEN (2)
- GREEN,
- /// BROWN (3)
- BROWN,
- /// YELLOW (3)
- YELLOW = 3,
- /// BLUE (4)
- BLUE,
- /// MAGENTA (5)
- MAGENTA,
- /// CYAN (6)
- CYAN,
- /// WHITE (7)
- WHITE
- };
- /**
- * @brief ANSI-BBS text attributes
- */
- enum class ATTR : std::int8_t {
- /// RESET forces all attributes (and Colors) to be sent.
- RESET,
- /// BOLD is the same as BRIGHT.
- BOLD,
- /// BRIGHT is the same as BOLD.
- BRIGHT = 1,
- /// SLOW BLINK
- BLINK = 5,
- /// INVERSE is Background on Foreground.
- INVERSE = 7
- };
- // std::int32_t
- constexpr long strhash(const char *txt) {
- long result = 0;
- for (int x = 0; x < 3; ++x) {
- if (txt[x] == 0) break;
- char c = txt[x];
- // toupper
- if ((c >= 'a') && (c <= 'z')) c &= ~0x20;
- result = (result << 8) | c;
- }
- return result;
- };
- #define A_BOLD 0x01
- #define A_BLINK 0x02
- #define A_INVERSE 0x04
- #define A_RESET 0x10
- /**
- * @class ANSIColor
- * This holds foreground, background and ANSI-BBS attribute
- * information.
- * The special attribute RESET forces attribute and color
- * output always.
- *
- * @brief Foreground, Background and Attributes
- *
- */
- class ANSIColor {
- /** Foreground color */
- COLOR fg;
- /** Background color */
- COLOR bg;
- int attr;
- public:
- ANSIColor();
- ANSIColor(ATTR a);
- ANSIColor(COLOR f);
- ANSIColor(COLOR f, ATTR a);
- ANSIColor(COLOR f, ATTR a1, ATTR a2);
- ANSIColor(COLOR f, COLOR b);
- ANSIColor(COLOR f, COLOR b, ATTR a);
- ANSIColor(COLOR f, COLOR b, ATTR a1, ATTR a2);
- ANSIColor(std::initializer_list<int> il);
- constexpr ANSIColor(const char *text)
- : fg(COLOR::WHITE), bg(COLOR::BLACK), attr(0) {
- const char *cp = text;
- bool use_on = false;
- while (*cp != 0) {
- long key = strhash(cp);
- switch (key) {
- case strhash("BRI"):
- attr |= A_BOLD;
- break;
- case strhash("BOL"):
- attr |= A_BOLD;
- break;
- case strhash("BLI"):
- attr |= A_BLINK;
- break;
- case strhash("INV"):
- attr |= A_INVERSE;
- break;
- case strhash("RES"):
- attr |= A_RESET;
- break;
- case strhash("ON "):
- use_on = true;
- break;
- case strhash("BLA"):
- if (use_on)
- bg = COLOR::BLACK;
- else
- fg = COLOR::BLACK;
- break;
- case strhash("RED"):
- if (use_on)
- bg = COLOR::RED;
- else
- fg = COLOR::RED;
- break;
- case strhash("GRE"):
- if (use_on)
- bg = COLOR::GREEN;
- else
- fg = COLOR::GREEN;
- break;
- case strhash("BRO"):
- if (use_on)
- bg = COLOR::BROWN;
- else
- fg = COLOR::BROWN;
- break;
- case strhash("YEL"):
- if (use_on)
- bg = COLOR::YELLOW;
- else {
- fg = COLOR::YELLOW;
- attr |= A_BOLD;
- }
- // if (use_on) throw error!
- break;
- case strhash("BLU"):
- if (use_on)
- bg = COLOR::BLUE;
- else
- fg = COLOR::BLUE;
- break;
- case strhash("MAG"):
- if (use_on)
- bg = COLOR::MAGENTA;
- else
- fg = COLOR::MAGENTA;
- break;
- case strhash("CYA"):
- if (use_on)
- bg = COLOR::CYAN;
- else
- fg = COLOR::CYAN;
- break;
- case strhash("WHI"):
- if (use_on)
- bg = COLOR::WHITE;
- else
- fg = COLOR::WHITE;
- break;
- default:
- throw std::range_error("Invalid/unknown color or attribute");
- }
- // skip to the space character
- while ((*cp != ' ') && (*cp != 0)) ++cp;
- // skip past the space character
- while (*cp == ' ') ++cp;
- }
- };
- /*
- ANSIColor(int c1);
- ANSIColor(int c1, int c2);
- */
- ANSIColor &Attr(ATTR a);
- bool operator==(const ANSIColor &c) const;
- bool operator!=(const ANSIColor &c) const;
- void setFg(COLOR f);
- void setFg(COLOR f, ATTR a);
- void setBg(COLOR b);
- /**
- * Get the foreground color
- * @return COLOR
- */
- COLOR getFg() { return fg; };
- /**
- * Get the background color
- * @return COLOR
- */
- COLOR getBg() { return bg; };
- void setAttr(ATTR a);
- std::string output(void) const;
- std::string operator()(void) const;
- };
- #ifdef NON_WORKING
- #include <vector>
- constexpr std::vector<int> from_text(const char *text) {
- std::vector<int> vi;
- const char *cp = text;
- bool use_on = false;
- while (*cp != 0) {
- int key = strhash(cp);
- switch (key) {
- case strhash("BRI"):
- vi.push_back(1);
- break;
- case strhash("BOL"):
- vi.push_back(1);
- break;
- case strhash("BLI"):
- vi.push_back(5);
- break;
- case strhash("INV"):
- vi.push_back(7);
- break;
- case strhash("ON "):
- use_on = true;
- break;
- case strhash("BLU"):
- if (use_on)
- ac.setBg(COLOR::BLUE);
- else
- ac.setFg(COLOR::BLUE);
- break;
- case strhash("RED"):
- if (use_on)
- ac.setBg(COLOR::RED);
- else
- ac.setFg(COLOR::RED);
- break;
- case strhash("GRE"):
- if (use_on)
- ac.setBg(COLOR::GREEN);
- else
- ac.setFg(COLOR::GREEN);
- break;
- case strhash("YEL"):
- // if (use_on) throw error!
- ac.setFg(COLOR::YELLOW);
- ac.Attr(ATTR::BOLD);
- break;
- case strhash("BRO"):
- if (use_on)
- ac.setBg(COLOR::BROWN);
- else
- ac.setFg(COLOR::BROWN);
- break;
- case strhash("CYA"):
- if (use_on)
- ac.setBg(COLOR::CYAN);
- else
- ac.setFg(COLOR::CYAN);
- break;
- case strhash("MAG"):
- if (use_on)
- ac.setBg(COLOR::MAGENTA);
- else
- ac.setFg(COLOR::MAGENTA);
- break;
- case strhash("BLA"):
- if (use_on)
- ac.setBg(COLOR::BLACK);
- else
- ac.setFg(COLOR::BLACK);
- break;
- case strhash("WHI"):
- if (use_on)
- ac.setBg(COLOR::WHITE);
- else
- ac.setFg(COLOR::WHITE);
- break;
- }
- // skip to the space character
- while ((*cp != ' ') && (*cp != 0)) ++cp;
- // skip past the space character
- while (*cp == ' ') ++cp;
- }
- return vi;
- }
- #endif
- /*
- Maybe make char, char, char (fg, bg, attr) and store those from
- the constexpr.
- This "works", in that it does construct an ANSIColor from text.
- However, it isn't stored as an ANSIColor, but calls the function
- at run-time. (I was hoping for an efficient way to construct
- ANSIColor from a string.)
- Maybe a template that constructs it from a initializer_list?
- */
- constexpr ANSIColor ac_from_text(const char *text) {
- ANSIColor ac(nullptr);
- const char *cp = text;
- bool use_on = false;
- while (*cp != 0) {
- int key = strhash(cp);
- switch (key) {
- case strhash("BRI"):
- ac.Attr(ATTR::BRIGHT);
- break;
- case strhash("BOL"):
- ac.Attr(ATTR::BOLD);
- break;
- case strhash("BLI"):
- ac.Attr(ATTR::BLINK);
- break;
- case strhash("INV"):
- ac.Attr(ATTR::INVERSE);
- break;
- case strhash("ON "):
- use_on = true;
- break;
- case strhash("BLU"):
- if (use_on)
- ac.setBg(COLOR::BLUE);
- else
- ac.setFg(COLOR::BLUE);
- break;
- case strhash("RED"):
- if (use_on)
- ac.setBg(COLOR::RED);
- else
- ac.setFg(COLOR::RED);
- break;
- case strhash("GRE"):
- if (use_on)
- ac.setBg(COLOR::GREEN);
- else
- ac.setFg(COLOR::GREEN);
- break;
- case strhash("YEL"):
- // if (use_on) throw error!
- ac.setFg(COLOR::YELLOW);
- ac.Attr(ATTR::BOLD);
- break;
- case strhash("BRO"):
- if (use_on)
- ac.setBg(COLOR::BROWN);
- else
- ac.setFg(COLOR::BROWN);
- break;
- case strhash("CYA"):
- if (use_on)
- ac.setBg(COLOR::CYAN);
- else
- ac.setFg(COLOR::CYAN);
- break;
- case strhash("MAG"):
- if (use_on)
- ac.setBg(COLOR::MAGENTA);
- else
- ac.setFg(COLOR::MAGENTA);
- break;
- case strhash("BLA"):
- if (use_on)
- ac.setBg(COLOR::BLACK);
- else
- ac.setFg(COLOR::BLACK);
- break;
- case strhash("WHI"):
- if (use_on)
- ac.setBg(COLOR::WHITE);
- else
- ac.setFg(COLOR::WHITE);
- break;
- }
- // skip to the space character
- while ((*cp != ' ') && (*cp != 0)) ++cp;
- // skip past the space character
- while (*cp == ' ') ++cp;
- }
- return ac;
- };
- extern ANSIColor reset;
- #endif
|