SlHelpers
Color.h
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #pragma once
4 
5 #include <iostream>
6 #include <unistd.h>
7 
8 namespace SlHelpers {
18 class Color {
19 public:
21  enum C : unsigned {
22  BOLD = 1,
23  BLACK = 30,
24  RED = 31,
25  GREEN = 32,
26  YELLOW = 33,
27  BLUE = 34,
28  MAGENTA = 35,
29  CYAN = 36,
30  WHITE = 37,
31  COL256 = 38,
32  DEFAULT = 39,
33  };
34 
36  enum Ctrl {
37  NoNL,
38  NL,
39  };
40 
45  explicit Color(enum C c = DEFAULT) noexcept : Color(std::cout, c) {}
46 
52  explicit Color(std::ostream &os, enum C c = DEFAULT) noexcept : m_NL(true), m_os(os) {
53  if (!doColor(os))
54  return;
55  auto origFlags = m_os.setf(std::ios::dec, std::ios::basefield);
56  m_os << seqBegin;
57  if (c != DEFAULT)
58  m_os << BOLD << ';';
59  m_os << c << 'm';
60  m_os.flags(origFlags);
61  }
62 
69  Color(unsigned char r, unsigned char g, unsigned char b) noexcept
70  : Color(std::cout, r, g, b) {}
71 
79  Color(std::ostream &os, unsigned char r, unsigned char g, unsigned char b) noexcept
80  : m_NL(true), m_os(os) {
81  if (!doColor(os))
82  return;
83  auto origFlags = m_os.setf(std::ios::dec, std::ios::basefield);
84  m_os << seqBegin << BOLD << ';' << COL256 << ";2;" <<
85  toUnsigned(r) << ';' <<
86  toUnsigned(g) << ';' <<
87  toUnsigned(b) << 'm';
88  m_os.flags(origFlags);
89  }
90 
91  ~Color() {
92  if (doColor(m_os))
93  m_os << seqEnd;
94  if (m_NL)
95  m_os << '\n';
96  }
97 
102  static void forceColor(bool force) { m_forceColor = force; }
107  static void forceColorValue(bool value) { m_forceColorValue = value; }
108 
113  std::ostream &os() { return m_os; }
114 
119  void ctrl(Ctrl ctrl) {
120  switch (ctrl) {
121  case NL:
122  case NoNL:
123  m_NL = ctrl == NL;
124  break;
125  }
126  }
127 
128 private:
129  template<typename T>
130  static unsigned toUnsigned(const T &val) { return val; }
131  static unsigned outIndex(const std::ostream &os) {
132  if (os.rdbuf() == std::cout.rdbuf())
133  return 0U;
134  if (os.rdbuf() == std::cerr.rdbuf())
135  return 1U;
136  return 2U;
137  }
138  static bool doColor(const std::ostream &os) {
139  if (m_forceColor)
140  return m_forceColorValue;
141  auto idx = outIndex(os);
142  if (m_doColor[idx] < 0)
143  m_doColor[idx] = isatty(idx + 1);
144  return m_doColor[idx];
145  }
146 
147  friend void testColor();
148  inline static std::string_view seqBegin = "\033[";
149  inline static std::string_view seqEnd = "\033[0m";
150  inline static signed char m_doColor[] = { -1, -1, 1 };
151  inline static bool m_forceColor = false;
152  inline static bool m_forceColorValue = false;
153  bool m_NL;
154  std::ostream &m_os;
155 };
156 
157 inline Color &&operator<<(Color &&os, const Color::Ctrl &ctrl)
158 {
159  os.ctrl(ctrl);
160  return std::move(os);
161 }
162 
163 template<typename T>
164 Color &&operator<<(Color &&os, const T &x)
165 {
166  os.os() << x;
167  return std::move(os);
168 }
169 
170 }
std::ostream & os()
Return current output stream.
Definition: Color.h:113
Color(std::ostream &os, enum C c=DEFAULT) noexcept
New Color stream (into os) using color c.
Definition: Color.h:52
Color(std::ostream &os, unsigned char r, unsigned char g, unsigned char b) noexcept
New Color stream (into os) using an RGB color.
Definition: Color.h:79
static void forceColorValue(bool value)
If forceColor(true) was called, use of colors is bound to value.
Definition: Color.h:107
C
Predefined colors.
Definition: Color.h:21
Color(unsigned char r, unsigned char g, unsigned char b) noexcept
New Color stream (stdout) using an RGB color.
Definition: Color.h:69
static void forceColor(bool force)
Force color value (see forceColorValue())
Definition: Color.h:102
Colorized output.
Definition: Color.h:18
Ctrl
Controls for Color.
Definition: Color.h:36
void ctrl(Ctrl ctrl)
Controls the stream behavior.
Definition: Color.h:119
Color(enum C c=DEFAULT) noexcept
New Color stream (stdout) using color c.
Definition: Color.h:45
Definition: Color.h:8