diff src/terminal.c @ 28919:99c1356f4210 v8.2.4982

patch 8.2.4982: colors in terminal window are not 100% correct Commit: https://github.com/vim/vim/commit/b2b3acbf2b3ae29ecf517f03b46fbeadf0c1a905 Author: LemonBoy <thatlemon@gmail.com> Date: Fri May 20 10:10:34 2022 +0100 patch 8.2.4982: colors in terminal window are not 100% correct Problem: Colors in terminal window are not 100% correct. Solution: Use g:terminal_ansi_colors as documented. (closes https://github.com/vim/vim/issues/10429, closes #7227 closes #10347)
author Bram Moolenaar <Bram@vim.org>
date Fri, 20 May 2022 11:15:04 +0200
parents d0241e74bfdb
children 983ec746af54
line wrap: on
line diff
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -162,6 +162,8 @@ struct terminal_S {
     int		tl_cursor_shape;  // 1: block, 2: underline, 3: bar
     char_u	*tl_cursor_color; // NULL or allocated
 
+    long_u	*tl_palette; // array of 16 colors specified by term_start, can
+			     // be NULL
     int		tl_using_altscreen;
     garray_T	tl_osc_buf;	    // incomplete OSC string
 };
@@ -242,6 +244,25 @@ cursor_color_get(char_u *color)
     return (color == NULL) ? (char_u *)"" : color;
 }
 
+/*
+ * Return TRUE if the user-defined palette (either g:terminal_ansi_colors or the
+ * "ansi_colors" argument in term_start()) shall be applied.
+ */
+    static int
+term_use_palette()
+{
+    if (0
+#ifdef FEAT_GUI
+	    || gui.in_use
+#endif
+#ifdef FEAT_TERMGUICOLORS
+	    || p_tgc
+#endif
+       )
+	return TRUE;
+    return FALSE;
+}
+
 
 /*
  * Parse 'termwinsize' and set "rows" and "cols" for the terminal size in the
@@ -705,6 +726,18 @@ term_start(
     if (opt->jo_set2 & JO2_TERM_HIGHLIGHT)
 	term->tl_highlight_name = vim_strsave(opt->jo_term_highlight);
 
+    // Save the user-defined palette, it is only used in GUI (or 'tgc' is on).
+    if (opt->jo_set2 & JO2_ANSI_COLORS)
+    {
+	term->tl_palette = ALLOC_MULT(long_u, 16);
+	if (term->tl_palette == NULL)
+	{
+	    vim_free(term);
+	    return NULL;
+	}
+	memcpy(term->tl_palette, opt->jo_ansi_colors, sizeof(long_u) * 16);
+    }
+
     // System dependent: setup the vterm and maybe start the job in it.
     if (argv == NULL
 	    && argvar->v_type == VAR_STRING
@@ -1118,6 +1151,7 @@ free_unused_terminals()
 #endif
 	vim_free(term->tl_highlight_name);
 	vim_free(term->tl_cursor_color);
+	vim_free(term->tl_palette);
 	vim_free(term);
     }
 }
@@ -2795,31 +2829,24 @@ color2index(VTermColor *color, int fg, i
     int blue = color->blue;
     int green = color->green;
 
+    *boldp = FALSE;
+
     if (VTERM_COLOR_IS_INVALID(color))
 	return 0;
+
     if (VTERM_COLOR_IS_INDEXED(color))
     {
-	// The first 16 colors and default: use the ANSI index.
-	switch (color->index + 1)
+	// Use the color as-is if possible, give up otherwise.
+	if (color->index < t_colors)
+	    return color->index + 1;
+	// 8-color terminals can actually display twice as many colors by
+	// setting the high-intensity/bold bit.
+	else if (t_colors == 8 && fg && color->index < 16)
 	{
-	    case  0: return 0;
-	    case  1: return lookup_color( 0, fg, boldp) + 1; // black
-	    case  2: return lookup_color( 4, fg, boldp) + 1; // dark red
-	    case  3: return lookup_color( 2, fg, boldp) + 1; // dark green
-	    case  4: return lookup_color( 7, fg, boldp) + 1; // dark yellow
-	    case  5: return lookup_color( 1, fg, boldp) + 1; // dark blue
-	    case  6: return lookup_color( 5, fg, boldp) + 1; // dark magenta
-	    case  7: return lookup_color( 3, fg, boldp) + 1; // dark cyan
-	    case  8: return lookup_color( 8, fg, boldp) + 1; // light grey
-	    case  9: return lookup_color(12, fg, boldp) + 1; // dark grey
-	    case 10: return lookup_color(20, fg, boldp) + 1; // red
-	    case 11: return lookup_color(16, fg, boldp) + 1; // green
-	    case 12: return lookup_color(24, fg, boldp) + 1; // yellow
-	    case 13: return lookup_color(14, fg, boldp) + 1; // blue
-	    case 14: return lookup_color(22, fg, boldp) + 1; // magenta
-	    case 15: return lookup_color(18, fg, boldp) + 1; // cyan
-	    case 16: return lookup_color(26, fg, boldp) + 1; // white
+	    *boldp = TRUE;
+	    return (color->index & 7) + 1;
 	}
+	return 0;
     }
 
     if (t_colors >= 256)
@@ -4251,11 +4278,13 @@ init_vterm_ansi_colors(VTerm *vterm)
 {
     dictitem_T	*var = find_var((char_u *)"g:terminal_ansi_colors", NULL, TRUE);
 
-    if (var != NULL
-	    && (var->di_tv.v_type != VAR_LIST
-		|| var->di_tv.vval.v_list == NULL
-		|| var->di_tv.vval.v_list->lv_first == &range_list_item
-		|| set_ansi_colors_list(vterm, var->di_tv.vval.v_list) == FAIL))
+    if (var == NULL)
+	return;
+
+    if (var->di_tv.v_type != VAR_LIST
+	    || var->di_tv.vval.v_list == NULL
+	    || var->di_tv.vval.v_list->lv_first == &range_list_item
+	    || set_ansi_colors_list(vterm, var->di_tv.vval.v_list) == FAIL)
 	semsg(_(e_invalid_argument_str), "g:terminal_ansi_colors");
 }
 #endif
@@ -4690,6 +4719,62 @@ create_vterm(term_T *term, int rows, int
 }
 
 /*
+ * Reset the terminal palette to its default value.
+ */
+    static void
+term_reset_palette(VTerm *vterm)
+{
+    VTermState	*state = vterm_obtain_state(vterm);
+    int		index;
+
+    for (index = 0; index < 16; index++)
+    {
+	VTermColor	color;
+
+	color.type = VTERM_COLOR_INDEXED;
+	ansi_color2rgb(index, &color.red, &color.green, &color.blue,
+		&color.index);
+	// The first valid index starts at 1.
+	color.index -= 1;
+
+	vterm_state_set_palette_color(state, index, &color);
+    }
+}
+
+    static void
+term_update_palette(term_T *term)
+{
+    if (term_use_palette()
+	    && (term->tl_palette != NULL
+		|| find_var((char_u *)"g:terminal_ansi_colors", NULL, TRUE)
+		!= NULL))
+    {
+	if (term->tl_palette != NULL)
+	    set_vterm_palette(term->tl_vterm, term->tl_palette);
+	else
+	    init_vterm_ansi_colors(term->tl_vterm);
+    }
+    else
+	term_reset_palette(term->tl_vterm);
+}
+
+/*
+ * Called when option 'termguicolors' is changed.
+ */
+    void
+term_update_palette_all()
+{
+    term_T *term;
+
+    FOR_ALL_TERMS(term)
+    {
+	if (term->tl_vterm == NULL)
+	    continue;
+	term_update_palette(term);
+    }
+}
+
+/*
  * Called when option 'background' or 'termguicolors' was set,
  * or when any highlight is changed.
  */
@@ -6346,6 +6431,8 @@ f_term_setansicolors(typval_T *argvars, 
 {
     buf_T	*buf;
     term_T	*term;
+    listitem_T	*li;
+    int		n = 0;
 
     if (in_vim9script()
 	    && (check_for_buffer_arg(argvars, 0) == FAIL
@@ -6364,9 +6451,38 @@ f_term_setansicolors(typval_T *argvars, 
 	emsg(_(e_list_required));
 	return;
     }
-
-    if (set_ansi_colors_list(term->tl_vterm, argvars[1].vval.v_list) == FAIL)
+    if (argvars[1].vval.v_list->lv_first == &range_list_item
+	    || argvars[1].vval.v_list->lv_len != 16)
+    {
 	emsg(_(e_invalid_argument));
+	return;
+    }
+
+    if (term->tl_palette == NULL)
+	term->tl_palette = ALLOC_MULT(long_u, 16);
+    if (term->tl_palette == NULL)
+	return;
+
+    FOR_ALL_LIST_ITEMS(argvars[1].vval.v_list, li)
+    {
+	char_u		*color_name;
+	guicolor_T	guicolor;
+
+	color_name = tv_get_string_chk(&li->li_tv);
+	if (color_name == NULL)
+	    return;
+
+	guicolor = GUI_GET_COLOR(color_name);
+	if (guicolor == INVALCOLOR)
+	{
+	    semsg(_(e_cannot_allocate_color_str), color_name);
+	    return;
+	}
+
+	term->tl_palette[n++] = GUI_MCH_GET_RGB(guicolor);
+    }
+
+    term_update_palette(term);
 }
 #endif
 
@@ -6823,12 +6939,13 @@ conpty_term_and_job_init(
     if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
 	goto failed;
 
-#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
-    if (opt->jo_set2 & JO2_ANSI_COLORS)
-	set_vterm_palette(term->tl_vterm, opt->jo_ansi_colors);
-    else
-	init_vterm_ansi_colors(term->tl_vterm);
-#endif
+    if (term_use_palette())
+    {
+	if (term->tl_palette != NULL)
+	    set_vterm_palette(term->tl_vterm, term->tl_palette);
+	else
+	    init_vterm_ansi_colors(term->tl_vterm);
+    }
 
     channel_set_job(channel, job, opt);
     job_set_options(job, opt);
@@ -7154,12 +7271,13 @@ winpty_term_and_job_init(
     if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
 	goto failed;
 
-#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
-    if (opt->jo_set2 & JO2_ANSI_COLORS)
-	set_vterm_palette(term->tl_vterm, opt->jo_ansi_colors);
-    else
-	init_vterm_ansi_colors(term->tl_vterm);
-#endif
+    if (term_use_palette())
+    {
+	if (term->tl_palette != NULL)
+	    set_vterm_palette(term->tl_vterm, term->tl_palette);
+	else
+	    init_vterm_ansi_colors(term->tl_vterm);
+    }
 
     channel_set_job(channel, job, opt);
     job_set_options(job, opt);
@@ -7413,12 +7531,13 @@ term_and_job_init(
     if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
 	return FAIL;
 
-#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
-    if (opt->jo_set2 & JO2_ANSI_COLORS)
-	set_vterm_palette(term->tl_vterm, opt->jo_ansi_colors);
-    else
-	init_vterm_ansi_colors(term->tl_vterm);
-#endif
+    if (term_use_palette())
+    {
+	if (term->tl_palette != NULL)
+	    set_vterm_palette(term->tl_vterm, term->tl_palette);
+	else
+	    init_vterm_ansi_colors(term->tl_vterm);
+    }
 
     // This may change a string in "argvar".
     term->tl_job = job_start(argvar, argv, opt, &term->tl_job);