diff options
| author | Robin Haberkorn <rhaberkorn@fmsbw.de> | 2026-05-10 00:15:52 +0200 |
|---|---|---|
| committer | Robin Haberkorn <rhaberkorn@fmsbw.de> | 2026-05-10 00:15:52 +0200 |
| commit | 58a0f8def5742248bf235c7c9cd9d3efcb334751 (patch) | |
| tree | 1e41bcfa8fe8bb5d4964060623e68ab865507cfb /src/interface-curses/interface.c | |
| parent | 26bcf1e04d5fcadc2fa968d7b5ce0e458d0aaa92 (diff) | |
support "default colors"master-fmsbw-ci
* The terminal's default foreground and background colors
are now used by default (`sciteco --no-profile`), so SciTECO
integrates naturally into all terminal color schemes, even
dark-on-bright ones.
* The default Scintilla colors use only 0x000000 (COLOR_BLACK) and 0xC0C0C0 (COLOR_WHITE)
now.
* You can use `7EJ` to configure the default colors in color
schemes or your profile.
All existing color schemes had to disable default colors
(`-1,-1,7EJ`) since they wouldn't look well otherwise.
* You may add `-1,7EJ` to ~/.teco_ini when using a terminal emulator
with a washed-out palettized COLOR_BLACK.
We cannot detect the terminal's default colors automatically.
* Scinterm updated to v6.0.
We require a not-yet-upstreamed patch:
https://github.com/orbitalquark/scinterm/pull/40
* In fact, we might decide not to support default colors at all in Scinterm,
so this feature should be considered experimental.
Diffstat (limited to 'src/interface-curses/interface.c')
| -rw-r--r-- | src/interface-curses/interface.c | 170 |
1 files changed, 103 insertions, 67 deletions
diff --git a/src/interface-curses/interface.c b/src/interface-curses/interface.c index 21e728f..ff6a0f2 100644 --- a/src/interface-curses/interface.c +++ b/src/interface-curses/interface.c @@ -200,6 +200,12 @@ static struct { * so every color is initialized to exact RGB values. */ gboolean use_palette; + /** + * Scintilla RGB values which should be rendered + * as the terminal's default foreground/background colors. + * This is -1 if colors haven't been configured. + */ + gint32 default_fg, default_bg; int stdin_orig, stdout_orig, stderr_orig; SCREEN *screen; @@ -237,58 +243,6 @@ static struct { } teco_interface; /** - * Returns the curses color pair for the given curses foreground and background colors. - * Initializes a new pair if necessary. - * - * Scinterm no longer initializes all color pairs for all combinations of - * the builtin foreground and background colors. - * Since curses does not guarantee any number of color pairs, we cannot do that either. - * Instead we allocate color pairs in the first half of - * color pair space on demand, while the second half is reserved to Scinterm. - * - * @param attr attributes to modify (for supporting monochrome terminals) - * @param fg curses foreground color - * @param bg curses background color - * @return curses color pair number - */ -static gshort -teco_color_pair(attr_t *attr, gshort fg, gshort bg) -{ - static guint next_pair = 1; - - /* - * Basic support for monochrome terminals: - * Every background, that is not black is assumed to be a - * dark-on-bright area, rendered in reverse. - * This will at least work with the terminal.tes and contrast.tes - * color schemes. - */ - if (!has_colors()) { - if (bg != COLOR_BLACK) - *attr |= WA_REVERSE; - return 0; - } - - G_STATIC_ASSERT(sizeof(gshort)*2 <= sizeof(guint)); - gpointer key = GUINT_TO_POINTER(((guint)fg << 8*sizeof(bg)) | bg); - gpointer value = g_hash_table_lookup(teco_interface.pair_table, key); - if (G_LIKELY(value != NULL)) - return GPOINTER_TO_UINT(value); - if (G_UNLIKELY(next_pair >= MAX_PAIRS)) - return 0; - init_pair(next_pair, fg, bg); - g_hash_table_insert(teco_interface.pair_table, key, GUINT_TO_POINTER(next_pair)); - return next_pair++; -} - -static inline gint -teco_wattr_set(WINDOW *win, attr_t attr, gshort fg, gshort bg) -{ - gshort pair = teco_color_pair(&attr, fg, bg); - return wattr_set(win, attr, pair, NULL); -} - -/** * Translate a Scintilla-compatible RGB color value * (0xBBGGRR) to a Curses color triple (0 to 1000 * for each component). @@ -358,6 +312,72 @@ teco_rgb2curses(guint32 rgb) return next_color; } +/** + * Returns the curses color pair for the given curses foreground and background colors. + * Initializes a new pair if necessary. + * + * Scinterm no longer initializes all color pairs for all combinations of + * the builtin foreground and background colors. + * Since curses does not guarantee any number of color pairs, we cannot do that either. + * Instead we allocate color pairs in the first half of + * color pair space on demand, while the second half is reserved to Scinterm. + * + * @param attr attributes to modify (for supporting monochrome terminals) + * @param fg curses foreground color (0xBBGGRR) + * @param bg curses background color (0xBBGGRR) + * @return curses color pair number + */ +static gshort +teco_color_pair(attr_t *attr, guint32 fg, guint32 bg) +{ + static guint next_pair = 1; + + /* + * Basic support for monochrome terminals: + * Every background, that is not black is assumed to be a + * dark-on-bright area, rendered in reverse. + * This will at least work with the terminal.tes and contrast.tes + * color schemes. + */ + if (!has_colors()) { + if (bg != 0x000000) + *attr ^= WA_REVERSE; + return 0; + } + + gshort fg_id, bg_id; + + /* + * Prefer to use reverse attribute since it will work with + * the terminals default colors. + */ + if (fg == teco_interface.default_bg && bg == teco_interface.default_fg) { + fg_id = bg_id = -1; + *attr ^= WA_REVERSE; + } else { + fg_id = fg == teco_interface.default_fg ? -1 : teco_rgb2curses(fg); + bg_id = bg == teco_interface.default_bg ? -1 : teco_rgb2curses(bg); + } + + G_STATIC_ASSERT(sizeof(gshort)*2 <= sizeof(guint)); + gpointer key = GUINT_TO_POINTER(((guint)fg_id << 8*sizeof(bg_id)) | bg_id); + gpointer value = g_hash_table_lookup(teco_interface.pair_table, key); + if (G_LIKELY(value != NULL)) + return GPOINTER_TO_UINT(value); + if (G_UNLIKELY(next_pair >= MAX_PAIRS)) + return 0; + init_pair(next_pair, fg_id, bg_id); + g_hash_table_insert(teco_interface.pair_table, key, GUINT_TO_POINTER(next_pair)); + return next_pair++; +} + +static inline gint +teco_wattr_set(WINDOW *win, attr_t attr, guint32 fg, guint32 bg) +{ + gshort pair = teco_color_pair(&attr, fg, bg); + return wattr_set(win, attr, pair, NULL); +} + static gint teco_xterm_version(void) { @@ -461,6 +481,8 @@ void teco_interface_init(gint argc, gchar **argv) { teco_interface.use_palette = TRUE; + teco_interface.default_fg = 0xC0C0C0; /* white */ + teco_interface.default_bg = 0x000000; /* black */; teco_interface.stdin_orig = teco_interface.stdout_orig = teco_interface.stderr_orig = -1; @@ -506,7 +528,13 @@ void teco_interface_disable_palette(void) { teco_interface.use_palette = FALSE; - scintilla_disable_color_palette(); +} + +void +teco_interface_set_default_colors(gint32 fg, gint32 bg) +{ + teco_interface.default_fg = fg; + teco_interface.default_bg = bg; } #ifdef CURSES_TTY @@ -652,6 +680,14 @@ teco_interface_init_interactive(GError **error) teco_interface.pair_table = g_hash_table_new(g_direct_hash, g_direct_equal); start_color(); scintilla_set_color_offsets(MAX_COLORS, MAX_PAIRS); + if (!teco_interface.use_palette) + scintilla_disable_color_palette(); +#ifdef HAVE_USE_DEFAULT_COLORS + /* color -1 will be the terminal's default foreground or background color */ + use_default_colors(); +#endif + scintilla_set_default_colors(teco_interface.default_fg, + teco_interface.default_bg); if (teco_interface.use_palette && has_colors()) { teco_interface_insert_color(0x000000, COLOR_BLACK); @@ -851,23 +887,23 @@ teco_interface_msg_literal(teco_msg_t type, const gchar *str, gsize len) teco_interface_stdio_msg(type, str, len); #endif - gshort fg, bg; + guint32 fg, bg; - fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0)); + fg = teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0); switch (type) { default: case TECO_MSG_USER: - bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0)); + bg = teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0); break; case TECO_MSG_INFO: - bg = COLOR_GREEN; + bg = 0x008000; /* green */ break; case TECO_MSG_WARNING: - bg = COLOR_YELLOW; + bg = 0x008080; /* yellow */ break; case TECO_MSG_ERROR: - bg = COLOR_RED; + bg = 0x000080; /* red */ beep(); break; } @@ -884,8 +920,8 @@ teco_interface_msg_clear(void) if (!teco_interface.input_pad) /* batch mode */ return; - gshort fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0)); - gshort bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0)); + guint32 fg = teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0); + guint32 bg = teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0); wmove(teco_interface.msg_window, 0, 0); teco_wattr_set(teco_interface.msg_window, 0, fg, bg); @@ -1077,8 +1113,8 @@ teco_interface_draw_info(void) * the current buffer's STYLE_DEFAULT. * The same style is used for MSG_USER messages. */ - gshort fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0)); - gshort bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0)); + guint32 fg = teco_interface_ssm(SCI_STYLEGETBACK, STYLE_DEFAULT, 0); + guint32 bg = teco_interface_ssm(SCI_STYLEGETFORE, STYLE_DEFAULT, 0); wmove(teco_interface.info_window, 0, 0); teco_wattr_set(teco_interface.info_window, 0, fg, bg); @@ -1650,8 +1686,8 @@ teco_interface_popup_show(gsize prefix_len) /* batch mode */ return; - gshort fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0)); - gshort bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0)); + guint32 fg = teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0); + guint32 bg = teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0); teco_interface.popup_prefix_len = prefix_len; attr_t attr = 0; @@ -1856,8 +1892,8 @@ teco_interface_process_mevent(MEVENT *event, GError **error) else if (event->bstate & BUTTON_NUM(5)) teco_curses_info_popup_scroll(&teco_interface.popup, +2); - gshort fg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0)); - gshort bg = teco_rgb2curses(teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0)); + guint32 fg = teco_interface_ssm(SCI_STYLEGETFORE, STYLE_CALLTIP, 0); + guint32 bg = teco_interface_ssm(SCI_STYLEGETBACK, STYLE_CALLTIP, 0); attr_t attr = 0; gshort pair = teco_color_pair(&attr, fg, bg); teco_curses_info_popup_show(&teco_interface.popup, attr, pair); |
