1
+ #include " door.h"
2
+ #include < string>
3
+
4
+ namespace door {
5
+
6
+ /* *
7
+ * Construct a new ANSIColor::ANSIColor object
8
+ * with sensible defaults (White on Black).
9
+ *
10
+ */
11
+ ANSIColor::ANSIColor ()
12
+ : fg(COLOR::WHITE), bg(COLOR::BLACK), reset(0 ), bold (0 ), blink(0 ),
13
+ inverse (0 ) {}
14
+
15
+ /* *
16
+ * Construct a new ANSIColor::ANSIColor object
17
+ * with attribute set.
18
+ *
19
+ * @param a ATTR
20
+ */
21
+ ANSIColor::ANSIColor (ATTR a) : ANSIColor() { Attr (a); }
22
+ /* *
23
+ * Construct a new ANSIColor::ANSIColor object
24
+ * with a foreground color.
25
+ *
26
+ * @param f COLOR
27
+ */
28
+ ANSIColor::ANSIColor (COLOR f) : ANSIColor() { fg = f; }
29
+
30
+ /* *
31
+ * Construct a new ANSIColor::ANSIColor object
32
+ * with a foreground color and attribute.
33
+ *
34
+ * @param f COLOR
35
+ * @param a ATTR
36
+ */
37
+ ANSIColor::ANSIColor (COLOR f, ATTR a) : ANSIColor() {
38
+ fg = f;
39
+ Attr (a);
40
+ }
41
+
42
+ /* *
43
+ * Construct a new ANSIColor::ANSIColor object
44
+ * with a foreground color and attributes.
45
+ *
46
+ * @param f COLOR
47
+ * @param a1 ATTR
48
+ * @param a2 ATTR
49
+ */
50
+ ANSIColor::ANSIColor (COLOR f, ATTR a1, ATTR a2) : ANSIColor() {
51
+ fg = f;
52
+ Attr (a1);
53
+ Attr (a2);
54
+ }
55
+
56
+ /* *
57
+ * Construct a new ANSIColor::ANSIColor object
58
+ * with a foreground and background color.
59
+ *
60
+ * @param f COLOR
61
+ * @param b COLOR
62
+ */
63
+ ANSIColor::ANSIColor (COLOR f, COLOR b) : ANSIColor() {
64
+ fg = f;
65
+ bg = b;
66
+ }
67
+
68
+ /* *
69
+ * Construct a new ANSIColor::ANSIColor object
70
+ * with a foreground color, background color,
71
+ * and attribute.
72
+ *
73
+ * @param f COLOR
74
+ * @param b COLOR
75
+ * @param a ATTR
76
+ */
77
+ ANSIColor::ANSIColor (COLOR f, COLOR b, ATTR a) : ANSIColor() {
78
+ fg = f;
79
+ bg = b;
80
+ Attr (a);
81
+ }
82
+
83
+ /* *
84
+ * Construct a new ANSIColor::ANSIColor object
85
+ * with foreground, background color and attributes.
86
+ *
87
+ * @param f COLOR
88
+ * @param b COLOR
89
+ * @param a1 ATTR
90
+ * @param a2 ATTR
91
+ */
92
+ ANSIColor::ANSIColor (COLOR f, COLOR b, ATTR a1, ATTR a2) : ANSIColor() {
93
+ fg = f;
94
+ bg = b;
95
+ Attr (a1);
96
+ Attr (a2);
97
+ }
98
+
99
+ /* *
100
+ * Set attribute. We return the object so
101
+ * calls can be chained.
102
+ *
103
+ * @param a ATTR
104
+ * @return ANSIColor&
105
+ */
106
+ ANSIColor &ANSIColor::Attr (ATTR a) {
107
+ switch (a) {
108
+ case ATTR::RESET:
109
+ reset = 1 ;
110
+ break ;
111
+ case ATTR::BOLD:
112
+ bold = 1 ;
113
+ break ;
114
+ case ATTR::BLINK:
115
+ blink = 1 ;
116
+ break ;
117
+ case ATTR::INVERSE:
118
+ inverse = 1 ;
119
+ break ;
120
+ }
121
+ return *this ;
122
+ }
123
+
124
+ /* *
125
+ * Equal operator.
126
+ *
127
+ * This compares colors and attributes, but ignores reset.
128
+ *
129
+ * @param c const ANSIColor &
130
+ * @return bool
131
+ */
132
+ bool ANSIColor::operator ==(const ANSIColor &c) const {
133
+ return ((fg == c.fg ) and (bg == c.bg ) and (bold == c.bold ) and
134
+ (blink == c.blink ) and (inverse == c.inverse ));
135
+ }
136
+
137
+ /* *
138
+ * Not-equal operator.
139
+ *
140
+ * This compares colors and attributes, but ignores reset.
141
+ *
142
+ * @param c const ANSIColor &
143
+ * @return bool
144
+ */
145
+ bool ANSIColor::operator !=(const ANSIColor &c) const {
146
+ return !((fg == c.fg ) and (bg == c.bg ) and (bold == c.bold ) and
147
+ (blink == c.blink ) and (inverse == c.inverse ));
148
+ }
149
+
150
+ /* *
151
+ * Output the full ANSI codes for attributes and color.
152
+ * This does not look at the previous values.
153
+ */
154
+ std::string ANSIColor::output (void ) const {
155
+ std::string clr (CSI);
156
+
157
+ // check for special cases
158
+ if (reset and fg == COLOR::BLACK and bg == COLOR::BLACK) {
159
+ clr += " 0m" ;
160
+ return clr;
161
+ }
162
+
163
+ if (reset) {
164
+ clr += " 0;" ;
165
+ }
166
+ if (bold ) {
167
+ clr += " 1;" ;
168
+ } else {
169
+ if (!reset)
170
+ clr += " 0;" ;
171
+ }
172
+ clr += std::to_string (30 + (int )fg) + " ;" ;
173
+ clr += std::to_string (40 + (int )bg) + " m" ;
174
+ return clr;
175
+ }
176
+
177
+ /* *
178
+ * Output only what ANSI attributes and colors have changed.
179
+ * This uses the previous ANSIColor value to determine what
180
+ * has changed.
181
+ *
182
+ * This sets previous to the current upon completion.
183
+ */
184
+ std::string ANSIColor::output (ANSIColor &previous) const {
185
+ std::string clr (CSI);
186
+ // color output optimization
187
+
188
+ // check for special cases
189
+ if (reset and fg == COLOR::BLACK and bg == COLOR::BLACK) {
190
+ clr += " 0m" ;
191
+ previous = *this ;
192
+ return clr;
193
+ }
194
+
195
+ if (reset) {
196
+ // current has RESET, so default to always sending colors.
197
+ clr = output ();
198
+ previous = *this ;
199
+ return clr;
200
+ }
201
+
202
+ if (*this == previous) {
203
+ clr.clear ();
204
+ return clr;
205
+ }
206
+
207
+ // resume "optimization"
208
+ if (bold != previous.bold ) {
209
+ // not the same, so handle this.
210
+ if (bold ) {
211
+ clr += " 1;" ;
212
+ if (fg != previous.fg )
213
+ clr += std::to_string ((int )fg + 30 ) + " ;" ;
214
+ if (bg != previous.bg )
215
+ clr += std::to_string ((int )bg + 40 ) + " ;" ;
216
+ } else {
217
+ clr += " 0;" ;
218
+ // RESET to turn OFF BOLD, clears previous
219
+ if (fg != COLOR::WHITE)
220
+ clr += std::to_string ((int )fg + 30 ) + " ;" ;
221
+ if (bg != COLOR::BLACK)
222
+ clr += std::to_string ((int )bg + 40 ) + " ;" ;
223
+ }
224
+ } else {
225
+ if (fg != previous.fg )
226
+ clr += std::to_string ((int )fg + 30 ) + " ;" ;
227
+ if (bg != previous.bg )
228
+ clr += std::to_string ((int )bg + 40 ) + " ;" ;
229
+ };
230
+
231
+ // Remove ';' if last character
232
+ std::string::iterator si = clr.end () - 1 ;
233
+ if (*si == ' ;' ) {
234
+ clr.erase (si);
235
+ }
236
+
237
+ if (clr.compare (CSI) == 0 )
238
+ clr.clear ();
239
+ else
240
+ clr += " m" ;
241
+
242
+ // final step, set previous to current and return the string;
243
+ previous = *this ;
244
+ return clr;
245
+ };
246
+
247
+ /* *
248
+ * This converts ANSI \ref COLOR and \ref ATTR to ANSI codes
249
+ * understood by the \ref Door output class.
250
+ */
251
+ std::ostream &operator <<(std::ostream &os, const ANSIColor &c) {
252
+ std::string out;
253
+
254
+ Door *d = dynamic_cast <Door *>(&os);
255
+ if (d != nullptr ) {
256
+ d->track = false ;
257
+ out = c.output (d->previous );
258
+ // if (!out.empty())
259
+ if (out.compare (" \x1b [" ) == 0 )
260
+ std::abort ();
261
+
262
+ *d << out;
263
+ d->track = true ;
264
+ } else {
265
+ // "dumb" version that can't remember anything/ doesn't optimize color
266
+ // output.
267
+ std::string out = c.output ();
268
+ os << out;
269
+ }
270
+ return os;
271
+ }
272
+
273
+ ANSIColor reset (ATTR::RESET);
274
+
275
+ } // namespace door
0 commit comments