Initial implementation of 256 colour support for Irssi

This patch implements some 256 colour support for Irssi up from the
previous 16 colours. Initial parsing of the %x/%X format codes is
implemented and the parser accounts in advances the char* for
that.

The colour attributes are widened from 4 to 8 bit. The colour protocol
is changed to a new format. Some pointers to remaining work are
written in the comment in textbuffer.h.

Note that Irssi already does support requesting 256 colours from the
terminal in the original source code, so this part did not have to be
touched.
This commit is contained in:
Tom Feist 2011-05-03 15:40:34 +01:00 committed by Ailin Nemui
commit 2d4edc5187
15 changed files with 437 additions and 105 deletions

View file

@ -146,24 +146,43 @@ static void remove_old_lines(TEXT_BUFFER_VIEW_REC *view)
static void get_colors(int flags, int *fg, int *bg, int *attr)
{
if (flags & GUI_PRINT_FLAG_MIRC_COLOR) {
g_message( "getcolor: handling mirc colors\n");
/* mirc colors - real range is 0..15, but after 16
colors wrap to 0, 1, ... */
if (*bg >= 0) *bg = mirc_colors[*bg % 16];
if (*fg >= 0) *fg = mirc_colors[*fg % 16];
/* TODO: What to do here? */
if (settings_get_bool("mirc_blink_fix"))
*bg &= ~0x08;
}
if (*fg < 0 || *fg > 15)
if (*fg < 0 || *fg > 255) {
g_message( "getcolor: fg %d outside range, setting to -1\n", *fg);
*fg = -1;
if (*bg < 0 || *bg > 15)
}
if (*bg < 0 || *bg > 255) {
g_message( "getcolor: bf %d outside range, setting to -1\n", *bg);
*bg = -1;
}
*attr = 0;
if (flags & GUI_PRINT_FLAG_REVERSE) *attr |= ATTR_REVERSE;
if (flags & GUI_PRINT_FLAG_BOLD) *attr |= ATTR_BOLD;
if (flags & GUI_PRINT_FLAG_UNDERLINE) *attr |= ATTR_UNDERLINE;
if (flags & GUI_PRINT_FLAG_BLINK) *attr |= ATTR_BLINK;
if (flags & GUI_PRINT_FLAG_REVERSE) {
*attr |= ATTR_REVERSE;
g_message( "getcolor: setting flag_reverse\n");
}
if (flags & GUI_PRINT_FLAG_BOLD) {
*attr |= ATTR_BOLD;
g_message( "getcolor: setting flag_bold\n");
}
if (flags & GUI_PRINT_FLAG_UNDERLINE) {
*attr |= ATTR_UNDERLINE;
g_message( "getcolor: setting flag_underline\n");
}
if (flags & GUI_PRINT_FLAG_BLINK) {
*attr |= ATTR_BLINK;
g_message( "getcolor: setting flag_blink\n");
}
}
static void view_add_eol(TEXT_BUFFER_VIEW_REC *view, LINE_REC **line)
@ -184,16 +203,32 @@ static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor,
LINE_INFO_REC lineinfo;
int fg, bg, flags, attr;
attr = 0;
flags = GPOINTER_TO_INT(pflags);
fg = GPOINTER_TO_INT(fgcolor);
bg = GPOINTER_TO_INT(bgcolor);
g_message( "SGPT str: '%s'\n", str);
g_message( "SGPT start: fg: %d (%02x), bg: %d (%02x) attr: %d (%04x), flags: %d (0x%04x)\n",
fg, fg, bg, bg, attr, attr, flags, flags);
get_colors(flags, &fg, &bg, &attr);
g_message( "SGPT getcol: fg: %d (%02x), bg: %d (%02x) attr: %d (%04x)\n",
fg, fg, (bg << 8), (bg << 8), attr, attr);
if (window == NULL) {
g_return_if_fail(next_xpos != -1);
attr |= fg >= 0 ? fg : ATTR_RESETFG;
attr |= bg >= 0 ? (bg << 4) : ATTR_RESETBG;
attr |= bg >= 0 ? (bg << 8) : ATTR_RESETBG;
g_message(
"SGPT nowin: fg: %d (%02x), bg: %d (%02x) attr: %d (%04x)\n",
fg, fg, (bg << 8), (bg << 8), attr, attr);
term_set_color(root_window, attr);
term_move(root_window, next_xpos, next_ypos);

View file

@ -293,75 +293,116 @@ void term_window_scroll(TERM_WINDOW *window, int count)
term_lines_empty[window->y+y] = FALSE;
}
/* Change active color */
void term_set_color(TERM_WINDOW *window, int col)
{
int set_normal;
int fg = col & 0x0f;
int bg = (col & 0xf0) >> 4;
set_normal = ((col & ATTR_RESETFG) && last_fg != -1) ||
((col & ATTR_RESETBG) && last_bg != -1);
if (((last_attrs & ATTR_BOLD) && (col & ATTR_BOLD) == 0) ||
((last_attrs & ATTR_BLINK) && (col & ATTR_BLINK) == 0)) {
int fg = (col & FG_MASK);
int bg = (col & BG_MASK) >> 8;
// int attrs = (col & 0xff0000) >> 16;
if (col != ATTR_RESET) {
g_message( "T-TI: set color called with col: %d (%08x)\n", col, col);
g_message( "T-TI: fg: %d (0x%02x), bg: %d (0x%02x)\n", fg, fg, bg, bg);
} else {
//g_message( "T-TI: set color called with col: %d (%08x)\n", col, col);
}
set_normal = ((col & ATTR_RESETFG) && last_fg != ATTR_COLOR_UNDEFINED) ||
((col & ATTR_RESETBG) && last_bg != ATTR_COLOR_UNDEFINED);
if (((last_attrs & ATTR_BOLD) && !(col & ATTR_BOLD)) ||
((last_attrs & ATTR_BLINK) && !(col & ATTR_BLINK))) {
/* we'll need to get rid of bold/blink - this can only be
done with setting the default color */
set_normal = TRUE;
}
if (set_normal) {
last_fg = last_bg = -1;
last_fg = last_bg = ATTR_COLOR_UNDEFINED;
last_attrs = 0;
g_message( "setnormal: setting last_* to 0%04x\n", last_fg);
terminfo_set_normal();
/* terminfo_set_bg(123); */
//terminfo_set_fg(47);
}
if (!term_use_colors && (col & 0xf0) != 0)
/* if colors are disabled, any background color setting enables
* reverse video mode
*/
if (!term_use_colors && bg > 0) {
col |= ATTR_REVERSE;
}
/* reversed text (use standout) */
if (col & ATTR_REVERSE) {
if ((last_attrs & ATTR_REVERSE) == 0)
if ((last_attrs & ATTR_REVERSE) == 0) {
g_message( "setreverse: on\n");
terminfo_set_standout(TRUE);
} else if (last_attrs & ATTR_REVERSE)
}
} else if (last_attrs & ATTR_REVERSE) {
g_message( "setreverse: off\n");
terminfo_set_standout(FALSE);
}
/* set foreground color */
if (fg != last_fg &&
(fg != 0 || (col & ATTR_RESETFG) == 0)) {
if (fg != last_fg && (fg != 0 || (col & ATTR_RESETFG) == 0)) {
if (term_use_colors) {
last_fg = fg;
terminfo_set_fg(last_fg);
g_message( "setfg: setting fg to %d (0x%04x)\n", fg, fg);
}
}
/* set background color */
if (col & 0x80 && window->term->TI_colors == 8)
/* TODO: What magic numbers? - originally 0xf0 - 11110000
*
*/
if (col & 0x8000 && window->term->TI_colors == 8) {
g_message( "0x080 match: setting attr_bold\n");
col |= ATTR_BLINK;
if (col & ATTR_BLINK)
current_term->set_blink(current_term);
}
if (bg != last_bg &&
(bg != 0 || (col & ATTR_RESETBG) == 0)) {
if (col & ATTR_BLINK) {
g_message( "setblink\n");
current_term->set_blink(current_term);
}
if (bg != last_bg && (bg != 0 || (col & ATTR_RESETBG) == 0)) {
if (term_use_colors) {
last_bg = bg;
terminfo_set_bg(last_bg);
g_message( "setbg: setting bg to %d (0x%04x)\n", bg, bg);
}
}
/* bold */
if (col & 0x08 && window->term->TI_colors == 8)
/* TODO: maybe make this fg > 7, since that implies a bright
* color,which bold can emulate.
*/
if (fg > 0 && window->term->TI_colors == 8) {
g_message( "0x080 match: setting attr_bold\n");
col |= ATTR_BOLD;
if (col & ATTR_BOLD)
}
if (col & ATTR_BOLD) {
g_message("setbold\n");
terminfo_set_bold();
}
/* underline */
if (col & ATTR_UNDERLINE) {
if ((last_attrs & ATTR_UNDERLINE) == 0)
if ((last_attrs & ATTR_UNDERLINE) == 0) {
terminfo_set_uline(TRUE);
} else if (last_attrs & ATTR_UNDERLINE)
}
} else if (last_attrs & ATTR_UNDERLINE) {
terminfo_set_uline(FALSE);
}
last_attrs = col & ~0xff;
/* update the new attribute settings whilst ignoring color values. */
last_attrs = col & ~( BG_MASK | FG_MASK );
}
void term_move(TERM_WINDOW *window, int x, int y)

View file

@ -4,12 +4,29 @@
typedef struct _TERM_WINDOW TERM_WINDOW;
/* text attributes */
#define ATTR_RESETFG 0x0100
#define ATTR_RESETBG 0x0200
#define ATTR_BOLD 0x0400
#define ATTR_BLINK 0x0800
#define ATTR_UNDERLINE 0x1000
#define ATTR_REVERSE 0x2000
#define FG_MASK ( 0x00ff )
#define BG_MASK ( 0xff00 )
#define ATTR_RESETFG ( 0x010000 )
#define ATTR_RESETBG ( 0x020000 )
#define ATTR_BOLD ( 0x040000 )
#define ATTR_BLINK ( 0x080000 )
#define ATTR_UNDERLINE ( 0x100000 )
#define ATTR_REVERSE ( 0x200000 )
/* can also mean default color, probably. */
#define ATTR_COLOR_UNDEFINED ( -1 )
#define EXT_COLOR_BLACK ( 0 )
#define EXT_COLOR_RED ( 1 )
#define EXT_COLOR_GREEN ( 2 )
#define EXT_COLOR_YELLOW ( 3 )
#define EXT_COLOR_BLUE ( 4 )
#define EXT_COLOR_MAGENTA ( 5 )
#define EXT_COLOR_CYAN ( 6 )
#define EXT_COLOR_WHITE ( 7 )
#define ATTR_RESET (ATTR_RESETFG|ATTR_RESETBG)
@ -65,6 +82,8 @@ void term_window_scroll(TERM_WINDOW *window, int count);
void term_set_color(TERM_WINDOW *window, int col);
void term_set_extended_color(TERM_WINDOW *window, int fg, int bg);
void term_move(TERM_WINDOW *window, int x, int y);
void term_addch(TERM_WINDOW *window, char chr);
void term_add_unichar(TERM_WINDOW *window, unichar chr);

View file

@ -519,19 +519,19 @@ static int term_setup(TERM_REC *term)
term_env = getenv("TERM");
if (term_env == NULL) {
fprintf(stderr, "TERM environment not set\n");
g_message( "TERM environment not set\n");
return 0;
}
#ifdef HAVE_TERMINFO
if (setupterm(term_env, 1, &err) != 0) {
fprintf(stderr, "setupterm() failed for TERM=%s: %d\n", term_env, err);
g_message( "setupterm() failed for TERM=%s: %d\n", term_env, err);
return 0;
}
#else
if (tgetent(term->buffer1, term_env) < 1)
{
fprintf(stderr, "Termcap not found for TERM=%s\n", term_env);
g_message( "Termcap not found for TERM=%s\n", term_env);
return 0;
}
#endif
@ -544,7 +544,7 @@ static int term_setup(TERM_REC *term)
else if (term->TI_hpa && term->TI_vpa)
term->move = _move_pa;
else {
fprintf(stderr, "Terminal doesn't support cursor movement\n");
g_message( "Terminal doesn't support cursor movement\n");
return 0;
}
term->move_relative = _move_relative;
@ -561,7 +561,7 @@ static int term_setup(TERM_REC *term)
else if (term->scroll == NULL && (term->TI_il1 && term->TI_dl1))
term->scroll = _scroll_line_1;
else if (term->scroll == NULL) {
fprintf(stderr, "Terminal doesn't support scrolling\n");
g_message( "Terminal doesn't support scrolling\n");
return 0;
}
@ -578,7 +578,7 @@ static int term_setup(TERM_REC *term)
/* we could do this by line inserts as well, but don't
bother - if some terminal has insert line it most probably
has delete line as well, if not a regular clear screen */
fprintf(stderr, "Terminal doesn't support clearing screen\n");
g_message( "Terminal doesn't support clearing screen\n");
return 0;
}
@ -586,7 +586,7 @@ static int term_setup(TERM_REC *term)
if (term->TI_el)
term->clrtoeol = _clrtoeol;
else {
fprintf(stderr, "Terminal doesn't support clearing to end of line\n");
g_message( "Terminal doesn't support clearing to end of line\n");
return 0;
}

View file

@ -16,6 +16,8 @@
#define terminfo_set_bold() current_term->set_bold(current_term)
#define terminfo_set_uline(set) current_term->set_uline(current_term, set)
#define terminfo_set_standout(set) current_term->set_standout(current_term, set)
// new
#define terminfo_set_blink() current_term->set_blink(current_term)
#define terminfo_is_colors_set(term) (term->TI_fg != NULL)
#define terminfo_beep(term) current_term->beep(current_term)

View file

@ -104,46 +104,63 @@ static void textbuffer_cache_unref(TEXT_BUFFER_CACHE_REC *cache)
textbuffer_cache_destroy(cache);
}
#define FGATTR (ATTR_NOCOLORS | ATTR_RESETFG | 0x0f)
#define BGATTR (ATTR_NOCOLORS | ATTR_RESETBG | 0xf0)
#define FGATTR (ATTR_NOCOLORS | ATTR_RESETFG | 0xff)
#define BGATTR (ATTR_NOCOLORS | ATTR_RESETBG | 0xff00)
static void update_cmd_color(unsigned char cmd, int *color)
{
if ((cmd & 0x80) == 0) {
if (cmd & LINE_COLOR_BG) {
/* set background color */
*color &= FGATTR;
if ((cmd & LINE_COLOR_DEFAULT) == 0)
*color |= (cmd & 0x0f) << 4;
else {
*color = (*color & FGATTR) | ATTR_RESETBG;
}
} else {
/* set foreground color */
*color &= BGATTR;
if ((cmd & LINE_COLOR_DEFAULT) == 0)
*color |= cmd & 0x0f;
else {
*color = (*color & BGATTR) | ATTR_RESETFG;
}
}
} else switch (cmd) {
static int next_color_bg = 0;
g_message( "update_cmd_color() color: 0x%08x, cmd: 0x%08x\n", *color, cmd);
if (cmd & 0x80) { /* cmd message */
switch (cmd) {
case LINE_CMD_UNDERLINE:
*color ^= ATTR_UNDERLINE;
g_message( "update_cmd_color() toggle underline 0x%08d\n", *color);
break;
case LINE_CMD_REVERSE:
*color ^= ATTR_REVERSE;
g_message( "update_cmd_color() toggle reverse 0x%08d\n", *color);
break;
case LINE_CMD_BLINK:
*color ^= ATTR_BLINK;
g_message( "update_cmd_color() toggle blink 0x%08d\n", *color);
break;
case LINE_CMD_BOLD:
*color ^= ATTR_BOLD;
g_message( "update_cmd_color() toggle bold 0x%08d\n", *color);
break;
case LINE_CMD_COLOR0:
*color &= BGATTR;
g_message( "update_cmd_color() set BGATTR RESET 0x%08d\n", *color);
break;
case LINE_CMD_SELECT_FG:
next_color_bg = 0;
g_message( "update_cmd_color() Next color will be FG\n");
break;
case LINE_CMD_SELECT_BG:
next_color_bg = 1;
g_message( "update_cmd_color() Next color will be BG\n");
break;
}
} else {
if (next_color_bg == 1) {
*color = cmd << 8;
} else {
*color = cmd;
}
}
}
static inline unichar read_unichar(const unsigned char *data, const unsigned char **next, int *width)
@ -356,6 +373,7 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
xpos = drawcount = 0; first = TRUE;
text_newline = text =
subline == 0 ? line->text : cache->lines[subline-1].start;
g_message( "view_line_draw()\n");
for (;;) {
if (text == text_newline) {
if (need_clrtoeol && xpos < term_width) {
@ -394,9 +412,11 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
xpos = indent_func(view, line, ypos);
}
if (need_move || xpos > 0)
if (need_move || xpos > 0) {
term_move(view->window, xpos, ypos);
}
g_message( "view_line_draw(): color: 0x%08x\n", color);
term_set_color(view->window, color);
if (subline == cache->count-1) {
@ -424,6 +444,9 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
continue;
} else {
update_cmd_color(*text, &color);
g_message( "post update_cmd_color: 0x%08x\n",
color);
term_set_color(view->window, color);
}
text++;
@ -453,8 +476,12 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
term_addch(view->window, *text);
} else {
/* low-ascii */
g_message( "printing inverse char %c\n",
(chr & 127)+'A'-1);
term_set_color(view->window, ATTR_RESET|ATTR_REVERSE);
term_addch(view->window, (chr & 127)+'A'-1);
g_message( "setting color back to: 0x%08x\n",
color);
term_set_color(view->window, color);
}
}

View file

@ -242,47 +242,80 @@ void textbuffer_line_add_colors(TEXT_BUFFER_REC *buffer, LINE_REC **line,
int fg, int bg, int flags)
{
unsigned char data[20];
int pos;
memset(data, 0, 20);
int pos = 0;
int i = 0;
/* get the fg & bg command chars */
fg = fg < 0 ? LINE_COLOR_DEFAULT : fg & 0x0f;
bg = LINE_COLOR_BG | (bg < 0 ? LINE_COLOR_DEFAULT : bg & 0x0f);
/* TODO: These things are adding additional data to colours. */
g_message( "TBLAC1: fg: 0x%08x, bg: 0x%08x, flags: 0x%08x, last_flags: 0x%08x\n",
fg, bg, flags, buffer->last_flags);
/* fg = fg < 0 ? LINE_COLOR_DEFAULT : fg & 0xff; */
/* bg = LINE_COLOR_BG | (bg < 0 ? LINE_COLOR_DEFAULT : bg & 0xff); */
g_message( "TBLAC2: fg: 0x%02x, bg: 0x%02x\n", fg, bg);
pos = 0;
if (fg != buffer->last_fg) {
buffer->last_fg = fg;
data[pos++] = 0;
data[pos++] = LINE_CMD_SELECT_FG;
data[pos++] = 0;
data[pos++] = fg == 0 ? LINE_CMD_COLOR0 : fg;
g_message( "TBLAC2: fg: data[%d}=%d(0x%02x)\n", pos-1,data[pos-1],data[pos-1]);
}
if (bg != buffer->last_bg) {
buffer->last_bg = bg;
data[pos++] = 0;
data[pos++] = LINE_CMD_SELECT_BG;
data[pos++] = 0;
data[pos++] = bg;
g_message( "TBLAC2: bg: data[%d}=%d(0x%02x)\n", pos-1,data[pos-1],data[pos-1]);
}
if ((flags & GUI_PRINT_FLAG_UNDERLINE) != (buffer->last_flags & GUI_PRINT_FLAG_UNDERLINE)) {
data[pos++] = 0;
data[pos++] = LINE_CMD_UNDERLINE;
g_message( "TBLAC2: underline: data[%d}=%d(0x%02x)\n", pos-1,data[pos-1],data[pos-1]);
}
if ((flags & GUI_PRINT_FLAG_REVERSE) != (buffer->last_flags & GUI_PRINT_FLAG_REVERSE)) {
data[pos++] = 0;
data[pos++] = LINE_CMD_REVERSE;
g_message( "TBLAC2: reverse: data[%d}=%d(0x%02x)\n", pos-1,data[pos-1],data[pos-1]);
}
if ((flags & GUI_PRINT_FLAG_BLINK) != (buffer->last_flags & GUI_PRINT_FLAG_BLINK)) {
data[pos++] = 0;
data[pos++] = LINE_CMD_BLINK;
g_message( "TBLAC2: blink: data[%d}=%d(0x%02x)\n", pos-1,data[pos-1],data[pos-1]);
}
if ((flags & GUI_PRINT_FLAG_BOLD) != (buffer->last_flags & GUI_PRINT_FLAG_BOLD)) {
data[pos++] = 0;
data[pos++] = LINE_CMD_BOLD;
g_message( "TBLAC2: bold: data[%d}=%d(0x%02x)\n", pos,data[pos-1],data[pos-1]);
}
if (flags & GUI_PRINT_FLAG_INDENT) {
data[pos++] = 0;
data[pos++] = LINE_CMD_INDENT;
g_message( "TBLAC2: indent: data[%d}=%d(0x%02x)\n", pos-1,data[pos-1],data[pos-1]);
}
if (pos > 0)
g_message( "TBLAC data:\n");
for (i=0; i < 20; i++) {
g_message( "%02x\n", data[i]);
}
g_message( "\n");
if (pos > 0) {
g_message( "calling textbuffer_insert()\n");
*line = textbuffer_insert(buffer, *line, data, pos, NULL);
}
buffer->last_flags = flags;
}
@ -323,6 +356,9 @@ LINE_REC *textbuffer_insert(TEXT_BUFFER_REC *buffer, LINE_REC *insert_after,
buffer->last_flags = 0;
}
g_message( "line created: '%s' %d\n", line->text, line->info.time);
g_message( "Buffer %p\n", buffer);
return line;
}
@ -377,18 +413,22 @@ void textbuffer_remove_all_lines(TEXT_BUFFER_REC *buffer)
static void set_color(GString *str, int cmd)
{
int color = -1;
int color = ATTR_COLOR_UNDEFINED;
if (!(cmd & LINE_COLOR_DEFAULT))
color = (cmd & 0x0f)+'0';
color = (cmd & 0xff) + '0';
g_message( "textbuffer.c:set_color color: %d (%02x)\n", color, color);
if ((cmd & LINE_COLOR_BG) == 0) {
/* change foreground color */
g_string_append_printf(str, "\004%c%c",
g_string_append_printf(str, "%c%c%c",
LINE_FORMAT_MARKER,
color, FORMAT_COLOR_NOCHANGE);
} else {
/* change background color */
g_string_append_printf(str, "\004%c%c",
g_string_append_printf(str, "%c%c%c",
LINE_FORMAT_MARKER,
FORMAT_COLOR_NOCHANGE, color);
}
}
@ -430,6 +470,9 @@ void textbuffer_line2text(LINE_REC *line, int coloring, GString *str)
continue;
}
/* these magic numbers correspond with some of IS_COLOR_CODE in
* formats.c:843 (31 and 22) */
if ((cmd & 0x80) == 0) {
/* set color */
set_color(str, cmd);

View file

@ -8,15 +8,20 @@
#define LINE_COLOR_BG 0x20
#define LINE_COLOR_DEFAULT 0x10
/* command values (see _LINE_REC protocol) */
enum {
LINE_CMD_EOL=0x80, /* line ends here */
LINE_CMD_CONTINUE, /* line continues in next block */
/* TODO: no longer needed */
LINE_CMD_COLOR0, /* change to black, would be same as \0\0 but it breaks things.. */
LINE_CMD_UNDERLINE, /* enable/disable underlining */
LINE_CMD_REVERSE, /* enable/disable reversed text */
LINE_CMD_INDENT, /* if line is split, indent it at this position */
LINE_CMD_BLINK, /* enable/disable blink */
LINE_CMD_BOLD, /* enable/disable bold */
LINE_CMD_SELECT_FG,
LINE_CMD_SELECT_BG
};
typedef struct {
@ -24,6 +29,7 @@ typedef struct {
time_t time;
} LINE_INFO_REC;
/* TODO: fixme. */
typedef struct _LINE_REC {
/* Text in the line. \0 means that the next char will be a
color or command.
@ -38,6 +44,28 @@ typedef struct _LINE_REC {
DO NOT ADD BLACK WITH \0\0 - this will break things. Use
LINE_CMD_COLOR0 instead. */
/* NEW COLOUR PROTOCOL:
0x00 - indicates command or colour.
0x01 - command follows (1 byte)
-- following may be omitted if LINE_CMD_USE_DEFAULT_[FB}G is set.
0x02 - BG colour follows (1 byte)
0x04 - FG colour follows (1 byte)
Things that will need to be fixed:
* textbuffer-view.c:update_cmd_color()
* textbuffer-view.c:view_line_draw()
* textbuffer-view.c:view_update_line_cache()
* textbuffer.c:textbuffer_line2text()
* textbuffer.c:mark_temp_eol macro
* gui-printtext.c ?
*/
struct _LINE_REC *prev, *next;
unsigned char *text;