diff --git a/degesch.c b/degesch.c index 924032f..012e54a 100644 --- a/degesch.c +++ b/degesch.c @@ -1465,7 +1465,13 @@ serialize_configuration (struct app_context *ctx, struct str *output) config_item_write (ctx->config.root, true, output); } -// --- Attributed output ------------------------------------------------------- +// --- Terminal output --------------------------------------------------------- + +/// Default color pair +#define COLOR_DEFAULT -1 + +/// Bright versions of the basic color set +#define COLOR_BRIGHT(x) (COLOR_ ## x + 8) static struct { @@ -1721,7 +1727,14 @@ enum formatter_item_type FORMATTER_ITEM_TEXT, ///< Text FORMATTER_ITEM_ATTR, ///< Formatting attributes FORMATTER_ITEM_FG_COLOR, ///< Foreground color - FORMATTER_ITEM_BG_COLOR ///< Background color + FORMATTER_ITEM_BG_COLOR, ///< Background color + + // These are internal, for mIRC formatting only so far: + + FORMATTER_ITEM_BOLD, ///< Bold + FORMATTER_ITEM_ITALIC, ///< Italic + FORMATTER_ITEM_UNDERLINE, ///< Underline + FORMATTER_ITEM_INVERSE ///< Inverse }; struct formatter_item @@ -1850,83 +1863,104 @@ enum // without the bold/blink attributes), 88 colors (the same plus a 4^3 RGB cube // and a few shades of gray), or 256 colors (best) -#define FORMATTER_NORMAL 0 -#define FORMATTER_BRIGHT 1 << 8 +/// Builds a color pair for 256-color terminals with a 16-color backup value +#define FORMATTER_COLOR(name, c256) \ + (COLOR_ ## name) & 0xFFFF | ((c256 << 16) & 0xFFFF) -#define FORMATTER_MAP(name, flags, c256) \ - COLOR_ ## name | FORMATTER_ ## flags | c256 << 16 - -static const uint32_t g_mirc_to_term[] = +static const int g_mirc_to_term[] = { - [MIRC_WHITE] = FORMATTER_MAP (WHITE, BRIGHT, 231), - [MIRC_BLACK] = FORMATTER_MAP (BLACK, NORMAL, 16), - [MIRC_BLUE] = FORMATTER_MAP (BLUE, NORMAL, 19), - [MIRC_GREEN] = FORMATTER_MAP (GREEN, NORMAL, 34), - [MIRC_L_RED] = FORMATTER_MAP (RED, BRIGHT, 196), - [MIRC_RED] = FORMATTER_MAP (RED, NORMAL, 124), - [MIRC_PURPLE] = FORMATTER_MAP (MAGENTA, NORMAL, 127), - [MIRC_ORANGE] = FORMATTER_MAP (YELLOW, BRIGHT, 214), - [MIRC_YELLOW] = FORMATTER_MAP (YELLOW, BRIGHT, 226), - [MIRC_L_GREEN] = FORMATTER_MAP (GREEN, BRIGHT, 46), - [MIRC_CYAN] = FORMATTER_MAP (CYAN, NORMAL, 37), - [MIRC_L_CYAN] = FORMATTER_MAP (CYAN, BRIGHT, 51), - [MIRC_L_BLUE] = FORMATTER_MAP (BLUE, BRIGHT, 21), - [MIRC_L_PURPLE] = FORMATTER_MAP (MAGENTA, BRIGHT, 201), - [MIRC_GRAY] = FORMATTER_MAP (BLACK, BRIGHT, 244), - [MIRC_L_GRAY] = FORMATTER_MAP (WHITE, NORMAL, 252), + [MIRC_WHITE] = FORMATTER_COLOR (BRIGHT (WHITE), 231), + [MIRC_BLACK] = FORMATTER_COLOR (BLACK, 16), + [MIRC_BLUE] = FORMATTER_COLOR (BLUE, 19), + [MIRC_GREEN] = FORMATTER_COLOR (GREEN, 34), + [MIRC_L_RED] = FORMATTER_COLOR (BRIGHT (RED), 196), + [MIRC_RED] = FORMATTER_COLOR (RED, 124), + [MIRC_PURPLE] = FORMATTER_COLOR (MAGENTA, 127), + [MIRC_ORANGE] = FORMATTER_COLOR (BRIGHT (YELLOW), 214), + [MIRC_YELLOW] = FORMATTER_COLOR (BRIGHT (YELLOW), 226), + [MIRC_L_GREEN] = FORMATTER_COLOR (BRIGHT (GREEN), 46), + [MIRC_CYAN] = FORMATTER_COLOR (CYAN, 37), + [MIRC_L_CYAN] = FORMATTER_COLOR (BRIGHT (CYAN), 51), + [MIRC_L_BLUE] = FORMATTER_COLOR (BRIGHT (BLUE), 21), + [MIRC_L_PURPLE] = FORMATTER_COLOR (BRIGHT (MAGENTA),201), + [MIRC_GRAY] = FORMATTER_COLOR (BRIGHT (BLACK), 244), + [MIRC_L_GRAY] = FORMATTER_COLOR (WHITE, 252), }; +static void +formatter_add_simple (struct formatter *self, enum formatter_item_type type) +{ + if (!self->ignore_new_attributes) + formatter_add_blank (self)->type = type; +} + +static const char * +formatter_parse_mirc_color (struct formatter *self, const char *s) +{ + if (!isdigit_ascii (*s)) + return s; + + int fg = *s++ - '0'; + if (isdigit_ascii (*s)) + fg = fg * 10 + (*s++ - '0'); + if (fg >= 0 && fg < 16) + formatter_add_fg_color (self, g_mirc_to_term[fg]); + + if (*s != ',' || !isdigit_ascii (s[1])) + return s; + + int bg = *++s - '0'; + if (isdigit_ascii (s[1])) + bg = bg * 10 + (*++s - '0'); + if (bg >= 0 && bg < 16) + formatter_add_bg_color (self, g_mirc_to_term[bg]); + + return s; +} + static void formatter_parse_mirc (struct formatter *self, const char *s) { - struct str buffer; - str_init (&buffer); - -#define FLUSH if (buffer.len) \ - { formatter_add_text (self, buffer.str); str_reset (&buffer); } + struct str buf; + str_init (&buf); formatter_add_reset (self); char c; while ((c = *s++)) { + if (buf.len && c < 0x20) + { + formatter_add_text (self, buf.str); + str_reset (&buf); + } + +#define SIMPLE(type) formatter_add_simple (self, FORMATTER_ITEM_ ## type) + switch (c) { - case '\x02': - FLUSH - // TODO: bold - break; + case '\x02': SIMPLE (BOLD); break; + case '\x1d': SIMPLE (ITALIC); break; + case '\x1f': SIMPLE (UNDERLINE); break; + case '\x16': SIMPLE (INVERSE); break; + +#undef SIMPLE + case '\x03': - FLUSH - // TODO: color - // TODO: parse \d(\d(,\d(\d)?)?)? - break; - case '\x1d': - FLUSH - // TODO: italic - break; - case '\x1f': - FLUSH - // TODO: underline - break; - case '\x16': - FLUSH - // TODO: swap background/foreground + s = formatter_parse_mirc_color (self, s); break; case '\x0f': - FLUSH formatter_add_reset (self); break; default: - str_append_c (&buffer, c); + str_append_c (&buf, c); } } - FLUSH - str_free (&buffer); - -#undef FLUSH + if (buf.len) + formatter_add_text (self, buf.str); + str_free (&buf); formatter_add_reset (self); } @@ -1953,10 +1987,6 @@ restart: str_append_c (buf, ' '); str_append (buf, s); break; - case 'm': - s = va_arg (*ap, char *); - formatter_parse_mirc (self, s); - break; case 'd': s = xstrdup_printf ("%d", va_arg (*ap, int)); for (size_t len = strlen (s); len < width; len++) @@ -1965,6 +1995,10 @@ restart: free (s); break; + case 'm': + formatter_parse_mirc (self, va_arg (*ap, char *)); + break; + case 'a': formatter_add_attr (self, va_arg (*ap, int)); break;