diff src/highlight.c @ 26057:92c424550367 v8.2.3562

patch 8.2.3562: cannot add color names Commit: https://github.com/vim/vim/commit/e30d10253fa634c4f60daa798d029245f4eed393 Author: Drew Vogel <dvogel@github> Date: Sun Oct 24 20:35:07 2021 +0100 patch 8.2.3562: cannot add color names Problem: Cannot add color names. Solution: Add the v:colornames dictionary. (Drew Vogel, closes https://github.com/vim/vim/issues/8761)
author Bram Moolenaar <Bram@vim.org>
date Sun, 24 Oct 2021 21:45:04 +0200
parents 09a273f0af05
children c7e09c069ece
line wrap: on
line diff
--- a/src/highlight.c
+++ b/src/highlight.c
@@ -475,6 +475,9 @@ load_colors(char_u *name)
     buf = alloc(STRLEN(name) + 12);
     if (buf != NULL)
     {
+#ifdef FEAT_EVAL
+	load_default_colors_lists();
+#endif
 	apply_autocmds(EVENT_COLORSCHEMEPRE, name,
 					       curbuf->b_fname, FALSE, curbuf);
 	sprintf((char *)buf, "colors/%s.vim", name);
@@ -1190,7 +1193,7 @@ highlight_set_guibg(
 	    HL_TABLE()[idx].sg_set |= SG_GUI;
 
 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
-	// In GUI guifg colors are only used when recognized
+	// In GUI guibg colors are only used when recognized
 	i = color_name2handle(arg);
 	if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !USE_24BIT)
 	{
@@ -2231,6 +2234,234 @@ color_name2handle(char_u *name)
 
     return GUI_GET_COLOR(name);
 }
+
+// On MS-Windows an RGB macro is available and it produces 0x00bbggrr color
+// values as used by the MS-Windows GDI api.  It should be used only for
+// MS-Windows GDI builds.
+# if defined(RGB) && defined(MSWIN) && !defined(FEAT_GUI)
+#  undef RGB
+# endif
+# ifndef RGB
+#  define RGB(r, g, b)	((r<<16) | (g<<8) | (b))
+# endif
+
+# ifdef VIMDLL
+    static guicolor_T
+gui_adjust_rgb(guicolor_T c)
+{
+    if (gui.in_use)
+	return c;
+    else
+	return ((c & 0xff) << 16) | (c & 0x00ff00) | ((c >> 16) & 0xff);
+}
+# else
+#  define gui_adjust_rgb(c) (c)
+# endif
+
+    static int
+hex_digit(int c)
+{
+    if (isdigit(c))
+	return c - '0';
+    c = TOLOWER_ASC(c);
+    if (c >= 'a' && c <= 'f')
+	return c - 'a' + 10;
+    return 0x1ffffff;
+}
+
+    guicolor_T
+decode_hex_color(char_u *hex)
+{
+    guicolor_T color;
+
+    if (hex[0] != '#' || STRLEN(hex) != 7)
+	return INVALCOLOR;
+
+    // Name is in "#rrggbb" format
+    color = RGB(((hex_digit(hex[1]) << 4) + hex_digit(hex[2])),
+		((hex_digit(hex[3]) << 4) + hex_digit(hex[4])),
+		((hex_digit(hex[5]) << 4) + hex_digit(hex[6])));
+    if (color > 0xffffff)
+	return INVALCOLOR;
+    return gui_adjust_rgb(color);
+}
+
+#if defined(FEAT_EVAL)
+// Returns the color currently mapped to the given name or INVALCOLOR if no
+// such name exists in the color table. The convention is to use lowercase for
+// all keys in the v:colornames dictionary. The value can be either a string in
+// the form #rrggbb or a number, either of which is converted to a guicolor_T.
+    guicolor_T
+colorname2rgb(char_u *name)
+{
+    dict_T      *colornames_table = get_vim_var_dict(VV_COLORNAMES);
+    char_u      *lc_name;
+    dictitem_T  *colentry;
+    char_u      *colstr;
+    varnumber_T colnum;
+
+    lc_name = strlow_save(name);
+    if (lc_name == NULL)
+	return INVALCOLOR;
+
+    colentry = dict_find(colornames_table, lc_name, -1);
+    vim_free(lc_name);
+    if (colentry == NULL)
+	return INVALCOLOR;
+
+    if (colentry->di_tv.v_type == VAR_STRING)
+    {
+	colstr = tv_get_string_strict(&colentry->di_tv);
+	if ((STRLEN(colstr) == 7) && (*colstr == '#'))
+	{
+	    return decode_hex_color(colstr);
+	}
+	else
+	{
+	    semsg(_(e_bad_color_string_str), colstr);
+	    return INVALCOLOR;
+	}
+    }
+
+    if (colentry->di_tv.v_type == VAR_NUMBER)
+    {
+	colnum = tv_get_number(&colentry->di_tv);
+	return (guicolor_T)colnum;
+    }
+
+    return INVALCOLOR;
+}
+
+// Maps the given name to the given color value, overwriting any current
+// mapping. If allocation fails the named color will no longer exist in the
+// table and the user will receive an error message.
+    void
+save_colorname_hexstr(int r, int g, int b, char_u *name)
+{
+    int        result;
+    dict_T     *colornames_table;
+    dictitem_T *existing;
+    char_u     hexstr[8];
+
+    if (vim_snprintf((char *)hexstr, sizeof(hexstr),
+						 "#%02x%02x%02x", r, g, b) < 0)
+    {
+	semsg(_(e_cannot_allocate_color_str), name);
+	return;
+    }
+
+    colornames_table = get_vim_var_dict(VV_COLORNAMES);
+    // The colornames_table dict is safe to use here because it is allocated at
+    // startup in evalvars.c
+    existing = dict_find(colornames_table, name, -1);
+    if (existing != NULL)
+    {
+	dictitem_remove(colornames_table, existing);
+	existing = NULL; // dictitem_remove freed the item
+    }
+
+    result = dict_add_string(colornames_table, (char *)name, hexstr);
+    if (result == FAIL)
+	semsg(_(e_cannot_allocate_color_str), name);
+}
+
+/*
+ * Load a default color list. Intended to support legacy color names but allows
+ * the user to override the color values. Only loaded once.
+ */
+    void
+load_default_colors_lists()
+{
+    // Lacking a default color list isn't the end of the world but it is likely
+    // an inconvenience so users should know when it is missing.
+    if (source_runtime((char_u *)"colors/lists/default.vim", DIP_ALL) != OK)
+	msg("failed to load colors/lists/default.vim");
+}
+#endif
+
+    guicolor_T
+gui_get_color_cmn(char_u *name)
+{
+    int         i;
+    guicolor_T  color;
+
+    struct rgbcolor_table_S {
+	char_u	    *color_name;
+	guicolor_T  color;
+    };
+
+    // Only non X11 colors (not present in rgb.txt) and colors in
+    // color_names[], useful when $VIMRUNTIME is not found,.
+    static struct rgbcolor_table_S rgb_table[] = {
+	    {(char_u *)"black",		RGB(0x00, 0x00, 0x00)},
+	    {(char_u *)"blue",		RGB(0x00, 0x00, 0xFF)},
+	    {(char_u *)"brown",		RGB(0xA5, 0x2A, 0x2A)},
+	    {(char_u *)"cyan",		RGB(0x00, 0xFF, 0xFF)},
+	    {(char_u *)"darkblue",	RGB(0x00, 0x00, 0x8B)},
+	    {(char_u *)"darkcyan",	RGB(0x00, 0x8B, 0x8B)},
+	    {(char_u *)"darkgray",	RGB(0xA9, 0xA9, 0xA9)},
+	    {(char_u *)"darkgreen",	RGB(0x00, 0x64, 0x00)},
+	    {(char_u *)"darkgrey",	RGB(0xA9, 0xA9, 0xA9)},
+	    {(char_u *)"darkmagenta",	RGB(0x8B, 0x00, 0x8B)},
+	    {(char_u *)"darkred",	RGB(0x8B, 0x00, 0x00)},
+	    {(char_u *)"darkyellow",	RGB(0x8B, 0x8B, 0x00)}, // No X11
+	    {(char_u *)"gray",		RGB(0xBE, 0xBE, 0xBE)},
+	    {(char_u *)"green",		RGB(0x00, 0xFF, 0x00)},
+	    {(char_u *)"grey",		RGB(0xBE, 0xBE, 0xBE)},
+	    {(char_u *)"grey40",	RGB(0x66, 0x66, 0x66)},
+	    {(char_u *)"grey50",	RGB(0x7F, 0x7F, 0x7F)},
+	    {(char_u *)"grey90",	RGB(0xE5, 0xE5, 0xE5)},
+	    {(char_u *)"lightblue",	RGB(0xAD, 0xD8, 0xE6)},
+	    {(char_u *)"lightcyan",	RGB(0xE0, 0xFF, 0xFF)},
+	    {(char_u *)"lightgray",	RGB(0xD3, 0xD3, 0xD3)},
+	    {(char_u *)"lightgreen",	RGB(0x90, 0xEE, 0x90)},
+	    {(char_u *)"lightgrey",	RGB(0xD3, 0xD3, 0xD3)},
+	    {(char_u *)"lightmagenta",	RGB(0xFF, 0x8B, 0xFF)}, // No X11
+	    {(char_u *)"lightred",	RGB(0xFF, 0x8B, 0x8B)}, // No X11
+	    {(char_u *)"lightyellow",	RGB(0xFF, 0xFF, 0xE0)},
+	    {(char_u *)"magenta",	RGB(0xFF, 0x00, 0xFF)},
+	    {(char_u *)"red",		RGB(0xFF, 0x00, 0x00)},
+	    {(char_u *)"seagreen",	RGB(0x2E, 0x8B, 0x57)},
+	    {(char_u *)"white",		RGB(0xFF, 0xFF, 0xFF)},
+	    {(char_u *)"yellow",	RGB(0xFF, 0xFF, 0x00)},
+    };
+
+    color = decode_hex_color(name);
+    if (color != INVALCOLOR)
+	return color;
+
+    // Check if the name is one of the colors we know
+    for (i = 0; i < (int)ARRAY_LENGTH(rgb_table); i++)
+	if (STRICMP(name, rgb_table[i].color_name) == 0)
+	    return gui_adjust_rgb(rgb_table[i].color);
+
+#if defined(FEAT_EVAL)
+    /*
+     * Not a traditional color. Load additional color aliases and then consult the alias table.
+     */
+
+    color = colorname2rgb(name);
+    if (color == INVALCOLOR)
+    {
+	load_default_colors_lists();
+	color = colorname2rgb(name);
+    }
+
+    return color;
+#else
+    return INVALCOLOR;
+#endif
+}
+
+    guicolor_T
+gui_get_rgb_color_cmn(int r, int g, int b)
+{
+    guicolor_T  color = RGB(r, g, b);
+
+    if (color > 0xffffff)
+	return INVALCOLOR;
+    return gui_adjust_rgb(color);
+}
 #endif
 
 /*