Skip to content

Commit adaf29c

Browse files
committed
*: introduce ANSI-escape code rendering
Using ANSI escapes is much more Cool(tm) than using backspace sequences. Not only is it more efficient, it's also handled by most terminals these days, and it works much better with UTF-8 sequences, etc. On top of that, one can do COLOURS, yay! So in this commit a bunch of things are combined on top of each other: 1. ANSI escape handling 2. colour handling, kind of messy, but sometimes works well (e.g. links) 3. table reflow handling to pick up the properties for colours and alignment Signed-off-by: Fabian Groffen <[email protected]>
1 parent 47ca362 commit adaf29c

21 files changed

+3095
-2325
lines changed

Area.cpp

Lines changed: 143 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,28 @@ Line::append(const char *p)
171171
}
172172
}
173173

174+
void
175+
Line::set_fgcolour(unsigned char clr)
176+
{
177+
Cell *p = cells_, *end = cells_ + length_;
178+
for (; p != end; p++)
179+
{
180+
p->fgcolour = clr;
181+
p->attribute |= Cell::FGCOLOUR;
182+
}
183+
}
184+
185+
void
186+
Line::set_bgcolour(unsigned char clr)
187+
{
188+
Cell *p = cells_, *end = cells_ + length_;
189+
for (; p != end; p++)
190+
{
191+
p->bgcolour = clr;
192+
p->attribute |= Cell::BGCOLOUR;
193+
}
194+
}
195+
174196
void
175197
Line::add_attribute(char addition)
176198
{
@@ -180,7 +202,11 @@ Line::add_attribute(char addition)
180202
p++->attribute |= addition;
181203
}
182204

183-
bool Area::use_backspaces = true;
205+
bool Area::use_backspaces = false;
206+
bool Area::use_ansi = true;
207+
208+
Area::size_type Area::widthsize = 6; /* px */
209+
Area::size_type Area::heightsize = 16; /* px, default fontsize */
184210

185211
Area::Area() :
186212
width_(0),
@@ -466,6 +492,32 @@ Area::fill(char c, size_type x, size_type y, size_type w, size_type h)
466492
}
467493
}
468494

495+
void
496+
Area::set_bgcolour(unsigned char clr)
497+
{
498+
for (size_type y = 0; y < height(); y++) {
499+
Cell *p = cells_[y], *end = p + width();
500+
while (p != end) {
501+
p->bgcolour = clr;
502+
p->attribute |= Cell::BGCOLOUR;
503+
p++;
504+
}
505+
}
506+
}
507+
508+
void
509+
Area::set_fgcolour(unsigned char clr)
510+
{
511+
for (size_type y = 0; y < height(); y++) {
512+
Cell *p = cells_[y], *end = p + width();
513+
while (p != end) {
514+
p->fgcolour = clr;
515+
p->attribute |= Cell::FGCOLOUR;
516+
p++;
517+
}
518+
}
519+
}
520+
469521
void
470522
Area::add_attribute(char addition)
471523
{
@@ -506,62 +558,113 @@ iconvstream &
506558
operator<<(iconvstream& os, const Area &a)
507559
{
508560
for (Area::size_type y = 0; y < a.height(); y++) {
509-
const Cell *cell = a.cells_[y];
510-
const Cell *end = cell + a.width();
511-
while (
512-
end != cell && end[-1].character == ' ' &&
513-
(end[-1].attribute &
514-
(Cell::UNDERLINE | Cell::STRIKETHROUGH)) == 0
515-
)
561+
/* compute visible part */
562+
const Cell *cell = a.cells_[y];
563+
const Cell *end = cell + a.width();
564+
char attrs = Cell::NONE;
565+
unsigned char fgcolour = Cell::BLACK;
566+
unsigned char bgcolour = Cell::WHITE;
567+
568+
/* trim off trailing spaces when they are not "visible" due to
569+
* attributes (underline/strikethrough) */
570+
while (end != cell &&
571+
end[-1].character == ' ' &&
572+
(end[-1].attribute & (Cell::UNDERLINE |
573+
Cell::STRIKETHROUGH)) == 0)
516574
end--;
517575

518576
for (const Cell *p = cell; p != end; p++) {
519-
int c = p->character;
520-
char a = p->attribute;
577+
int c = p->character;
578+
char a = p->attribute;
521579
char u[5] = {0, 0, 0, 0, 0};
522580

581+
/* compute codepoint, this is a bit unfortunate and should
582+
* go away once we use wchar_t */
523583
u[0] = c & 0xFF;
524584
if ((c >> 7) & 1) {
525-
unsigned int d = c;
585+
unsigned int d = c;
526586
unsigned char point = 1;
527587
while ((c >> (7 - point++)) & 1) {
528588
d >>= 8;
529589
u[point - 1] = d & 0xFF;
530-
};
590+
}
531591
}
532592

533-
if (a == Cell::NONE) {
593+
if (Area::use_ansi) {
594+
/* use ANSI escape sequences to produce colours, bold
595+
* and underline */
596+
597+
/* see if there's something that needs disabling */
598+
if (attrs != a ||
599+
(a & Cell::COLOUR &&
600+
(p->fgcolour != fgcolour ||
601+
p->bgcolour != bgcolour)))
602+
{
603+
/* reset all properties, rebuild afterwards
604+
* we do this also because it's the only way to
605+
* unset something :) */
606+
os << "\e[0";
607+
608+
attrs = a;
609+
fgcolour = p->fgcolour;
610+
bgcolour = p->bgcolour;
611+
612+
/* enable needed properties */
613+
if (attrs & Cell::UNDERLINE) {
614+
os << ";4";
615+
}
616+
if (attrs & Cell::BOLD) {
617+
os << ";1";
618+
}
619+
/* ignore strikethrough, can't represent it */
620+
621+
if (attrs & Cell::FGCOLOUR) {
622+
os << ";38;5;" << std::to_string(fgcolour);
623+
}
624+
if (attrs & Cell::BGCOLOUR) {
625+
os << ";48;5;" << std::to_string(bgcolour);
626+
}
627+
628+
/* finish sequence */
629+
os << "m";
630+
}
631+
os << u;
632+
} else if (Area::use_backspaces &&
633+
a != Cell::NONE)
634+
{
635+
/* old method of producing bold and underline */
636+
637+
/* No LESS / terminal combination that I know of
638+
* supports dash-backspace-character as
639+
* "strikethrough". Pity.
640+
* (For historical reasons we're still doing it though.) */
641+
if (a & Cell::STRIKETHROUGH)
642+
os << '-' << backspace;
643+
644+
/* No LESS that I know of can combine underlining
645+
* and boldface. In practice, boldface always takes
646+
* precedence.
647+
*
648+
* It's not a good idea to optimize an underlined
649+
* space as a single underscore (as opposed to
650+
* underscore-backspace-space) -- this would not
651+
* look nice next to an underlined character. */
652+
if ((a & Cell::UNDERLINE))
653+
os << '_' << backspace;
654+
if ((a & Cell::BOLD ) && c != ' ')
655+
os << u << backspace;
534656
os << u;
535657
} else {
536-
if (Area::use_backspaces) {
537-
/*
538-
* No LESS / terminal combination that I know of
539-
* supports dash-backspace-character as
540-
* "strikethrough". Pity.
541-
*/
542-
if (a & Cell::STRIKETHROUGH)
543-
os << '-' << backspace;
544-
545-
/*
546-
* No LESS that I know of can combine underlining
547-
* and boldface. In practice, boldface always takes
548-
* precedence.
549-
*
550-
* It's not a good idea to optimize an underlined
551-
* space as a single underscore (as opposed to
552-
* underscore-backspace-space) -- this would not
553-
* look nice next to an underlined character.
554-
*/
555-
if ((a & Cell::UNDERLINE))
556-
os << '_' << backspace;
557-
if ((a & Cell::BOLD ) && c != ' ')
558-
os << c << backspace;
559-
os << u;
560-
} else {
561-
os << (c == ' ' && (a & Cell::UNDERLINE) ? "_" : u);
562-
}
658+
/* no rendering, historical behaviour to turn spaces
659+
* into underscores when the input is underlined */
660+
os << (c == ' ' && (a & Cell::UNDERLINE) ? "_" : u);
563661
}
564662
}
663+
664+
/* if we haven't yet, unset all features */
665+
if (Area::use_ansi && attrs != Cell::NONE)
666+
os << "\e[0;m";
667+
565668
os << endl;
566669
}
567670

Area.h

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,51 @@
2424
#include "iconvstream.h"
2525
#include "istr.h"
2626

27-
#ifdef BOOL_DEFINITION
28-
BOOL_DEFINITION
29-
#undef BOOL_DEFINITION
30-
#endif
31-
3227
using std::string;
3328

3429
struct Cell {
35-
int character;
30+
int character;
3631
char attribute;
3732

33+
/* these are the decoration properties */
34+
enum {
35+
NONE = 0<<0,
36+
UNDERLINE = 1<<0,
37+
BOLD = 1<<1,
38+
STRIKETHROUGH = 1<<2,
39+
FGCOLOUR = 1<<3,
40+
BGCOLOUR = 1<<4,
41+
COLOUR = FGCOLOUR | BGCOLOUR
42+
};
43+
44+
/* 8-bit colours */
45+
unsigned char fgcolour;
46+
unsigned char bgcolour;
47+
3848
enum {
39-
NONE = 0, UNDERLINE = 1, BOLD = 2, STRIKETHROUGH = 4
49+
/* standard */
50+
BLACK = 0,
51+
RED = 1,
52+
GREEN = 2,
53+
YELLOW = 3,
54+
BLUE = 4,
55+
MAGENTA = 5,
56+
CYAN = 6,
57+
WHITE = 7,
58+
/* intense (bright) */
59+
BRBLACK = 8,
60+
BRRED = 9,
61+
BRGREEN = 10,
62+
BRYELLOW = 11,
63+
BRBLUE = 12,
64+
BRMAGENTA = 13,
65+
BRCYAN = 14,
66+
BRWHITE = 15,
67+
/* 216 colours: 16 + 36 * r + 6 * g + b */
68+
/* shades of grey: 233-255 */
69+
DKGREY = 238,
70+
GREY = 244,
71+
BRGREY = 250
4072
};
4173

4274
void clear()
@@ -109,6 +141,8 @@ class Line {
109141
return *this;
110142
}
111143

144+
void set_bgcolour(unsigned char clr);
145+
void set_fgcolour(unsigned char clr);
112146
void add_attribute(char addition);
113147

114148
private:
@@ -194,6 +228,8 @@ class Area {
194228
void fill(const Cell &, size_type x, size_type y, size_type w, size_type h);
195229
void fill(char, size_type x, size_type y, size_type w, size_type h);
196230

231+
void set_bgcolour(unsigned char clr);
232+
void set_fgcolour(unsigned char clr);
197233
void add_attribute(char addition); // ...but not to left and right free areas
198234
void add_attribute(
199235
char addition,
@@ -202,7 +238,12 @@ class Area {
202238
size_type w,
203239
size_type h
204240
);
205-
static bool use_backspaces; // "true" by default.
241+
242+
/* see Area.cpp for the defaults for the below variables */
243+
static bool use_backspaces;
244+
static bool use_ansi;
245+
static Area::size_type widthsize;
246+
static Area::size_type heightsize;
206247

207248
private:
208249
Area(const Area &);

Properties.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@
1919
#ifndef __Properties_h_INCLUDED__ /* { */
2020
#define __Properties_h_INCLUDED__
2121

22-
#ifdef BOOL_DEFINITION
23-
BOOL_DEFINITION
24-
#undef BOOL_DEFINITION
25-
#endif
26-
2722
#include <string>
2823
#include <map>
2924
#include <istream>

0 commit comments

Comments
 (0)