aboutsummaryrefslogtreecommitdiff
path: root/degesch.c
diff options
context:
space:
mode:
Diffstat (limited to 'degesch.c')
-rw-r--r--degesch.c164
1 files changed, 151 insertions, 13 deletions
diff --git a/degesch.c b/degesch.c
index 275f744..2c300b2 100644
--- a/degesch.c
+++ b/degesch.c
@@ -1473,8 +1473,8 @@ static struct
bool stdout_is_tty; ///< `stdout' is a terminal
bool stderr_is_tty; ///< `stderr' is a terminal
- char *color_set_fg[8]; ///< Codes to set the foreground colour
- char *color_set_bg[8]; ///< Codes to set the background colour
+ char *color_set_fg[256]; ///< Codes to set the foreground colour
+ char *color_set_bg[256]; ///< Codes to set the background colour
int lines; ///< Number of lines
int columns; ///< Number of columns
@@ -1527,7 +1527,8 @@ init_terminal (void)
g_terminal.columns = tigetnum ("cols");
update_screen_size ();
- for (size_t i = 0; i < N_ELEMENTS (g_terminal.color_set_fg); i++)
+ int max = MIN (256, max_colors);
+ for (int i = 0; i < max; i++)
{
g_terminal.color_set_fg[i] = xstrdup (tparm (set_a_foreground,
i, 0, 0, 0, 0, 0, 0, 0, 0));
@@ -1544,7 +1545,7 @@ free_terminal (void)
if (!g_terminal.initialized)
return;
- for (size_t i = 0; i < N_ELEMENTS (g_terminal.color_set_fg); i++)
+ for (int i = 0; i < 256; i++)
{
free (g_terminal.color_set_fg[i]);
free (g_terminal.color_set_bg[i]);
@@ -1552,6 +1553,36 @@ free_terminal (void)
del_curterm (cur_term);
}
+static int
+index_to_terminal_palette (int color)
+{
+ hard_assert (color >= 0 && color < 256);
+
+ // No conversion
+ if (max_colors == 256)
+ return color;
+ // These colours are the same everywhere
+ if (color < 16 && max_colors > color)
+ return color;
+
+ // Outside the 16-color range, we only support the 88-color palette,
+ // which we can interpolate to from the 256-color one on input
+ if (max_colors != 88)
+ return -1;
+
+ // 24 -> 8 extra shades of gray
+ if (color >= 232)
+ return 80 + (color - 232) / 3;
+
+ // 6 * 6 * 6 cube -> 4 * 4 * 4 cube
+ int x[6] = { 0, 1, 1, 2, 2, 3 };
+ int index = color - 16;
+ return 16 +
+ ( x[ index / 36 ] << 8
+ | x[(index / 6) % 6 ] << 4
+ | x[(index % 6) ] );
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
typedef int (*terminal_printer_fn) (int);
@@ -1678,6 +1709,7 @@ init_colors (struct app_context *ctx)
// Format strings use a #-quoted notation, to differentiate from printf:
// #s inserts a string
// #d inserts a signed integer; also supports the #<N> and #0<N> notation
+// #m inserts a mIRC-formatted string (auto-resets at boundaries)
//
// #a inserts named attributes (auto-resets)
// #r resets terminal attributes
@@ -1801,6 +1833,105 @@ formatter_add_bg_color (struct formatter *self, int color)
item->color = color;
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+enum
+{
+ MIRC_WHITE, MIRC_BLACK, MIRC_BLUE, MIRC_GREEN,
+ MIRC_L_RED, MIRC_RED, MIRC_PURPLE, MIRC_ORANGE,
+ MIRC_YELLOW, MIRC_L_GREEN, MIRC_CYAN, MIRC_L_CYAN,
+ MIRC_L_BLUE, MIRC_L_PURPLE, MIRC_GRAY, MIRC_L_GRAY,
+};
+
+// We use estimates from the 16 color terminal palette, or the 256 color cube,
+// which is not always available. The mIRC orange colour is only in the cube.
+
+// NOTE: commonly terminals have 8 colors (worst), 16 colors (allows brightness
+// 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
+
+#define FORMATTER_MAP(name, flags, c256) \
+ COLOR_ ## name | FORMATTER_ ## flags | c256 << 16
+
+static const uint32_t 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),
+};
+
+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); }
+
+ formatter_add_reset (self);
+
+ char c;
+ while ((c = *s++))
+ {
+ switch (c)
+ {
+ case '\x02':
+ FLUSH
+ // TODO: bold
+ break;
+ 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
+ break;
+ case '\x0f':
+ FLUSH
+ formatter_add_reset (self);
+ break;
+ default:
+ str_append_c (&buffer, c);
+ }
+ }
+
+ FLUSH
+ str_free (&buffer);
+
+#undef FLUSH
+
+ formatter_add_reset (self);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
static const char *
formatter_parse_field (struct formatter *self,
const char *field, struct str *buf, va_list *ap)
@@ -1822,6 +1953,10 @@ 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++)
@@ -1981,6 +2116,9 @@ buffer_line_display (struct app_context *ctx,
char *nick = NULL;
const char *userhost = NULL;
+
+ // TODO: always assign the default colour to ourselves
+ // FIXME: never use the black colour, use the default instead
int nick_color = -1;
int object_color = -1;
@@ -2019,24 +2157,24 @@ buffer_line_display (struct app_context *ctx,
{
case BUFFER_LINE_PRIVMSG:
if (line->flags & BUFFER_LINE_HIGHLIGHT)
- formatter_add (&f, "#a<#s>#r #s", ATTR_HIGHLIGHT, nick, a->text);
+ formatter_add (&f, "#a<#s>#r #m", ATTR_HIGHLIGHT, nick, a->text);
else
- formatter_add (&f, "<#c#s#r> #s", nick_color, nick, a->text);
+ formatter_add (&f, "<#c#s#r> #m", nick_color, nick, a->text);
break;
case BUFFER_LINE_ACTION:
if (line->flags & BUFFER_LINE_HIGHLIGHT)
formatter_add (&f, " #a*#r ", ATTR_HIGHLIGHT);
else
formatter_add (&f, " #a*#r ", ATTR_ACTION);
- formatter_add (&f, "#c#s#r #s", nick_color, nick, a->text);
+ formatter_add (&f, "#c#s#r #m", nick_color, nick, a->text);
break;
case BUFFER_LINE_NOTICE:
formatter_add (&f, " - ");
if (line->flags & BUFFER_LINE_HIGHLIGHT)
- formatter_add (&f, "#a#s(#s)#r: #s",
+ formatter_add (&f, "#a#s(#s)#r: #m",
ATTR_HIGHLIGHT, "Notice", nick, a->text);
else
- formatter_add (&f, "#s(#c#s#r): #s",
+ formatter_add (&f, "#s(#c#s#r): #m",
"Notice", nick_color, nick, a->text);
break;
case BUFFER_LINE_JOIN:
@@ -2051,7 +2189,7 @@ buffer_line_display (struct app_context *ctx,
nick_color, nick, ATTR_USERHOST, userhost,
ATTR_PART, "has left", a->object);
if (a->reason)
- formatter_add (&f, " (#s)", a->reason);
+ formatter_add (&f, " (#m)", a->reason);
break;
case BUFFER_LINE_KICK:
formatter_add (&f, "#a<--#r ", ATTR_PART);
@@ -2059,7 +2197,7 @@ buffer_line_display (struct app_context *ctx,
nick_color, nick, ATTR_USERHOST, userhost,
ATTR_PART, "has kicked", object_color, a->object);
if (a->reason)
- formatter_add (&f, " (#s)", a->reason);
+ formatter_add (&f, " (#m)", a->reason);
break;
case BUFFER_LINE_NICK:
formatter_add (&f, " - ");
@@ -2073,7 +2211,7 @@ buffer_line_display (struct app_context *ctx,
break;
case BUFFER_LINE_TOPIC:
formatter_add (&f, " - ");
- formatter_add (&f, "#c#s#r #s \"#s\"",
+ formatter_add (&f, "#c#s#r #s \"#m\"",
nick_color, nick,
"has changed the topic to", a->text);
break;
@@ -2083,7 +2221,7 @@ buffer_line_display (struct app_context *ctx,
nick_color, nick, ATTR_USERHOST, userhost,
ATTR_PART, "has quit");
if (a->reason)
- formatter_add (&f, " (#s)", a->reason);
+ formatter_add (&f, " (#m)", a->reason);
break;
case BUFFER_LINE_STATUS:
formatter_add (&f, " - ");