diff options
author | Drew Vogel <dvogel@github> | 2021-10-24 20:35:07 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-10-24 20:35:07 +0100 |
commit | e30d10253fa634c4f60daa798d029245f4eed393 (patch) | |
tree | 57aca74b65dc4c3924ef23185b8cb2b6933996c2 /src/highlight.c | |
parent | 3c5904d2a5d7861c227a4c3cd4ddcbc51014c838 (diff) | |
download | vim-git-e30d10253fa634c4f60daa798d029245f4eed393.tar.gz |
patch 8.2.3562: cannot add color namesv8.2.3562
Problem: Cannot add color names.
Solution: Add the v:colornames dictionary. (Drew Vogel, closes #8761)
Diffstat (limited to 'src/highlight.c')
-rw-r--r-- | src/highlight.c | 233 |
1 files changed, 232 insertions, 1 deletions
diff --git a/src/highlight.c b/src/highlight.c index 76d9a7e82..5dde08b8f 100644 --- 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 /* |