aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--degesch.c142
1 files changed, 79 insertions, 63 deletions
diff --git a/degesch.c b/degesch.c
index 501b63e..a4dbb3e 100644
--- a/degesch.c
+++ b/degesch.c
@@ -1563,40 +1563,6 @@ free_terminal (void)
del_curterm (cur_term);
}
-// 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)
-
-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);
@@ -1726,7 +1692,8 @@ enum
ATTRIBUTE_BOLD = 1 << 0,
ATTRIBUTE_ITALIC = 1 << 1,
ATTRIBUTE_UNDERLINE = 1 << 2,
- ATTRIBUTE_INVERSE = 1 << 3
+ ATTRIBUTE_INVERSE = 1 << 3,
+ ATTRIBUTE_BLINK = 1 << 4
};
struct attribute_printer
@@ -1773,50 +1740,94 @@ attribute_printer_apply (struct attribute_printer *self, int attribute)
}
}
-// TODO: 256-color output
-// - 8 color -> maybe bold, maybe inverse (should text be bold now?)
-// - 16 color -> just use the fallback color
-// - 88 color -> use the 256color value if available
-// - 256 color -> use the 256color value if available
+// NOTE: commonly terminals have:
+// 8 colors (worst, bright fg with BOLD, bg sometimes with BLINK)
+// 16 colors (okayish, we have the full basic range guaranteed)
+// 88 colors (the same plus a 4^3 RGB cube and a few shades of gray)
+// 256 colors (best, like above but with a larger cube and more gray)
+
+/// Interpolate from the 256-color palette to the 88-color one
+static int
+attribute_printer_256_to_88 (int color)
+{
+ // These colours are the same everywhere
+ if (color < 16)
+ return color;
+
+ // 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) ] );
+}
+
+static int
+attribute_printer_decode_color (int color, bool *is_bright)
+{
+ int16_t c16 = color; hard_assert (c16 < 16);
+ int16_t c256 = color >> 16; hard_assert (c256 < 256);
+
+ *is_bright = false;
+ switch (max_colors)
+ {
+ case 8:
+ if (c16 >= 8)
+ {
+ c16 -= 8;
+ *is_bright = true;
+ }
+ case 16:
+ return c16;
+
+ case 88:
+ return c256 <= 0 ? c16 : attribute_printer_256_to_88 (c256);
+ case 256:
+ return c256 <= 0 ? c16 : c256;
+
+ default:
+ // Unsupported palette
+ return -1;
+ }
+}
static void
attribute_printer_update (struct attribute_printer *self)
{
- int fg = 0;
- if ((int16_t) (self->want_foreground >> 16) > 0)
- fg = index_to_terminal_palette ((int16_t) (self->want_foreground >> 16));
- int bg = 0;
- if ((int16_t) (self->want_background >> 16) > 0)
- bg = index_to_terminal_palette ((int16_t) (self->want_background >> 16));
- if (fg <= 0) fg = (int16_t) (self->want_foreground);
- if (bg <= 0) bg = (int16_t) (self->want_background);
+ bool fg_is_bright;
+ int fg = attribute_printer_decode_color
+ (self->want_foreground, &fg_is_bright);
+ bool bg_is_bright;
+ int bg = attribute_printer_decode_color
+ (self->want_background, &bg_is_bright);
+ // TODO: (INVERSE | BOLD) should be used for bright backgrounds
+ // when possible, i.e. when the foreground shouldn't be bright as well
+ // and when the BOLD attribute hasn't already been set
int attributes = self->want;
- if (max_colors == 8)
+ if (attributes & ATTRIBUTE_INVERSE)
{
- if (fg >= 8)
- {
- attributes |= ATTRIBUTE_BOLD;
- fg -= 8;
- }
- if (bg >= 8)
- {
- attributes |= ATTRIBUTE_BOLD;
- bg -= 8;
- }
+ bool tmp = fg_is_bright;
+ fg_is_bright = bg_is_bright;
+ bg_is_bright = tmp;
}
- attribute_printer_reset (self);
+ if (fg_is_bright) attributes |= ATTRIBUTE_BOLD;
+ if (bg_is_bright) attributes |= ATTRIBUTE_BLINK;
- if (fg >= 0) tputs (g_terminal.color_set_fg[fg], 1, self->printer);
- if (bg >= 0) tputs (g_terminal.color_set_bg[bg], 1, self->printer);
+ attribute_printer_reset (self);
if (attributes)
tputs (tparm (set_attributes,
0, // standout
attributes & ATTRIBUTE_UNDERLINE,
attributes & ATTRIBUTE_INVERSE,
- 0, // blink
+ attributes & ATTRIBUTE_BLINK,
0, // dim
attributes & ATTRIBUTE_BOLD,
0, // blank
@@ -1824,6 +1835,11 @@ attribute_printer_update (struct attribute_printer *self)
0) // acs
, 1, self->printer);
+ if (fg >= 0)
+ tputs (g_terminal.color_set_fg[fg], 1, self->printer);
+ if (bg >= 0)
+ tputs (g_terminal.color_set_bg[bg], 1, self->printer);
+
self->dirty = true;
}