]> granicus.if.org Git - vim/commitdiff
patch 8.2.4982: colors in terminal window are not 100% correct v8.2.4982
authorLemonBoy <thatlemon@gmail.com>
Fri, 20 May 2022 09:10:34 +0000 (10:10 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 20 May 2022 09:10:34 +0000 (10:10 +0100)
Problem:    Colors in terminal window are not 100% correct.
Solution:   Use g:terminal_ansi_colors as documented. (closes #10429,
            closes #7227 closes #10347)

src/job.c
src/option.c
src/proto/term.pro
src/proto/terminal.pro
src/term.c
src/terminal.c
src/testdir/test_functions.vim
src/testdir/test_terminal.vim
src/version.c

index 31f026097733a05a6f1c5ce021e93b0d053660d3..7cce61181b33dbdf6969bc80fbafbc0bcbadf903 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -548,13 +548,13 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
                    break;
 
                if (item == NULL || item->v_type != VAR_LIST
-                       || item->vval.v_list == NULL)
+                       || item->vval.v_list == NULL
+                       || item->vval.v_list->lv_first == &range_list_item)
                {
                    semsg(_(e_invalid_value_for_argument_str), "ansi_colors");
                    return FAIL;
                }
 
-               CHECK_LIST_MATERIALIZE(item->vval.v_list);
                li = item->vval.v_list->lv_first;
                for (; li != NULL && n < 16; li = li->li_next, n++)
                {
index 559e260ce9215bfbdf4ba23d46395c74d74b1e98..9ff3084adc0b9af936535c50c3b8e027af0fcd41 100644 (file)
@@ -3255,6 +3255,7 @@ set_bool_option(
 # endif
 # ifdef FEAT_TERMINAL
        term_update_colors_all();
+       term_update_palette_all();
        term_update_wincolor_all();
 # endif
     }
index 6f0f08103aa5aa88d5c5ca0679fae98e9adc0806..8c56f62bd713558fa3f649740f0e74f8008602a5 100644 (file)
@@ -84,6 +84,7 @@ void show_termcodes(int flags);
 int show_one_termcode(char_u *name, char_u *code, int printit);
 void update_tcap(int attr);
 void swap_tcap(void);
+void ansi_color2rgb(int nr, char_u *r, char_u *g, char_u *b, char_u *ansi_idx);
 void cterm_color2rgb(int nr, char_u *r, char_u *g, char_u *b, char_u *ansi_idx);
 void term_replace_bs_del_keycode(char_u *ta_buf, int ta_len, int len);
 /* vim: set ft=c : */
index 996ac70e238559bcf545fe31f831b32e6c60c576..07365631115b2449cd652f7868bbadbbcb115019 100644 (file)
@@ -34,6 +34,7 @@ int term_get_attr(win_T *wp, linenr_T lnum, int col);
 void term_reset_wincolor(win_T *wp);
 void term_update_wincolor(win_T *wp);
 void term_update_wincolor_all(void);
+void term_update_palette_all(void);
 void term_update_colors_all(void);
 char_u *term_get_status_text(term_T *term);
 void term_clear_status_text(term_T *term);
index ef3cf9433cda37b6f4876203d8a3cb11bbc27324..7449d88c68acaed466a05ee28fdaef9ee0e125b0 100644 (file)
@@ -6730,7 +6730,7 @@ static int grey_ramp[] = {
     0x80, 0x8A, 0x94, 0x9E, 0xA8, 0xB2, 0xBC, 0xC6, 0xD0, 0xDA, 0xE4, 0xEE
 };
 
-static char_u ansi_table[16][3] = {
+static const char_u ansi_table[16][3] = {
 //   R    G    B
   {  0,   0,   0}, // black
   {224,   0,   0}, // dark red
@@ -6760,6 +6760,25 @@ static const char_u cterm_ansi_idx[] = {
 
 #define ANSI_INDEX_NONE 0
 
+    void
+ansi_color2rgb(int nr, char_u *r, char_u *g, char_u *b, char_u *ansi_idx)
+{
+    if (nr < 16)
+    {
+       *r = ansi_table[nr][0];
+       *g = ansi_table[nr][1];
+       *b = ansi_table[nr][2];
+       *ansi_idx = nr;
+    }
+    else
+    {
+       *r = 0;
+       *g = 0;
+       *b = 0;
+       *ansi_idx = ANSI_INDEX_NONE;
+    }
+}
+
     void
 cterm_color2rgb(int nr, char_u *r, char_u *g, char_u *b, char_u *ansi_idx)
 {
index 703966a877becec76fc21069d4d896981c0dc270..4c8ee7feabce908f53dc34d2eb9a98d5c9058e7e 100644 (file)
@@ -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, int *boldp)
     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
@@ -4689,6 +4718,62 @@ create_vterm(term_T *term, int rows, int cols)
     return OK;
 }
 
+/*
+ * 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, typval_T *rettv UNUSED)
 {
     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, typval_T *rettv UNUSED)
        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);
index 9eae10da3a3b7a942b94e46cdb39ff87c19860e5..68dbb0aa09f4845b8ce5354039b33020e5c68229 100644 (file)
@@ -2679,8 +2679,8 @@ func Test_range()
     else
       let cmd = "ls"
     endif
-    call assert_fails('call term_start("' .. cmd .. '", #{term_finish: "close"})', 'E475:')
-    unlet g:terminal_ansi_colors
+    call assert_fails('call term_start("' .. cmd .. '", #{term_finish: "close"'
+        \ .. ', ansi_colors: range(16)})', 'E475:')
   endif
 
   " type()
index f290eff3ad51cdf6c1b319eac6921438af783f39..2700b7a915f92069c50c3d907ce3947ec3c28be2 100644 (file)
@@ -2012,10 +2012,16 @@ func Test_terminal_ansicolors_global()
   CheckFeature termguicolors
   CheckFunction term_getansicolors
 
+  if has('vtp') && !has('vcon') && !has('gui_running')
+    throw 'Skipped: does not support termguicolors'
+  endif
+
+  set tgc
   let g:terminal_ansi_colors = reverse(copy(s:test_colors))
   let buf = Run_shell_in_terminal({})
   call assert_equal(g:terminal_ansi_colors, term_getansicolors(buf))
   call StopShellInTerminal(buf)
+  set tgc&
 
   exe buf . 'bwipe'
   unlet g:terminal_ansi_colors
@@ -2025,6 +2031,11 @@ func Test_terminal_ansicolors_func()
   CheckFeature termguicolors
   CheckFunction term_getansicolors
 
+  if has('vtp') && !has('vcon') && !has('gui_running')
+    throw 'Skipped: does not support termguicolors'
+  endif
+
+  set tgc
   let g:terminal_ansi_colors = reverse(copy(s:test_colors))
   let buf = Run_shell_in_terminal({'ansi_colors': s:test_colors})
   call assert_equal(s:test_colors, term_getansicolors(buf))
@@ -2047,6 +2058,7 @@ func Test_terminal_ansicolors_func()
   let colors[4] = 'Invalid'
   call assert_fails('call term_setansicolors(buf, colors)', 'E254:')
   call assert_fails('call term_setansicolors(buf, {})', 'E714:')
+  set tgc&
 
   call StopShellInTerminal(buf)
   call assert_equal(0, term_setansicolors(buf, []))
index 01c1f2efd0e61f4a6020f33e81792d40f7cffa41..e758e81ea88493615a2e3303a9b8c27db420242c 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4982,
 /**/
     4981,
 /**/