]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.0.1685: can't set ANSI colors of a terminal window v8.0.1685
authorBram Moolenaar <Bram@vim.org>
Tue, 10 Apr 2018 13:59:11 +0000 (15:59 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 10 Apr 2018 13:59:11 +0000 (15:59 +0200)
Problem:    Can't set ANSI colors of a terminal window.
Solution:   Add term_setansicolors(), term_getansicolors() and
            g:term_ansi_colors. (Andy Massimino, closes #2747)

runtime/doc/eval.txt
runtime/doc/terminal.txt
src/channel.c
src/evalfunc.c
src/proto/terminal.pro
src/structs.h
src/terminal.c
src/testdir/test_terminal.vim
src/version.c

index c82f2da342dee0285a2d9a1aeaa7910e684517ad..b0170b847b7c511f3d2cda82fde47e24a0306056 100644 (file)
@@ -2423,6 +2423,7 @@ term_dumpload({filename} [, {options}])
 term_dumpwrite({buf}, {filename} [, {options}])
                                none    dump terminal window contents
 term_getaltscreen({buf})       Number  get the alternate screen flag
+term_getansicolors({buf})      List    get ANSI palette in GUI color mode
 term_getattr({attr}, {what})   Number  get the value of attribute {what}
 term_getcursor({buf})          List    get the cursor position of a terminal
 term_getjob({buf})             Job     get the job associated with a terminal
@@ -2435,6 +2436,8 @@ term_gettty({buf}, [{input}])     String  get the tty name of a terminal
 term_list()                    List    get the list of terminal buffers
 term_scrape({buf}, {row})      List    get row of a terminal screen
 term_sendkeys({buf}, {keys})   none    send keystrokes to a terminal
+term_setansicolors({buf}, {colors})
+                               none    set ANSI palette in GUI color mode
 term_setkill({buf}, {how})     none    set signal to stop job in terminal
 term_setrestore({buf}, {command}) none set command to restore terminal
 term_start({cmd}, {options})   Job     open a terminal window and run a job
@@ -8248,6 +8251,18 @@ term_getaltscreen({buf})                         *term_getaltscreen()*
                {buf} is used as with |term_getsize()|.
                {only available when compiled with the |+terminal| feature}
 
+term_getansicolors({buf})                              *term_getansicolors()*
+               Get the ANSI color palette in use by terminal {buf}.
+               Returns a List of length 16 where each element is a String
+               representing a color in hexadecimal "#rrggbb" format.
+               Also see |term_setansicolors()| and |g:terminal_ansi_colors|.
+               If neither was used returns the default colors.
+
+               {buf} is used as with |term_getsize()|.  If the buffer does not
+               exist or is not a terminal window, an empty list is returned.
+               {only available when compiled with the |+terminal| feature and
+               with GUI enabled and/or the |+termguicolors| feature}
+
 term_getattr({attr}, {what})                           *term_getattr()*
                Given {attr}, a value returned by term_scrape() in the "attr"
                item, return whether {what} is on.  {what} can be one of:
@@ -8379,6 +8394,19 @@ term_sendkeys({buf}, {keys})                             *term_sendkeys()*
                means the character CTRL-X.
                {only available when compiled with the |+terminal| feature}
 
+term_setansicolors({buf}, {colors})                    *term_setansicolors()*
+               Set the ANSI color palette used by terminal {buf}.
+               {colors} must be a List of 16 valid color names or hexadecimal
+               color codes, like those accepted by |highlight-guifg|.
+               Also see |term_getansicolors()| and |g:terminal_ansi_colors|.
+
+               These colors are used in the GUI and in the terminal when
+               'termguicolors' is set.  When not using GUI colors (GUI mode
+               or |termguicolors|), the terminal window always uses the 16
+               ANSI colors of the underlying terminal.
+               {only available when compiled with the |+terminal| feature and
+               with GUI enabled and/or the |+termguicolors| feature}
+
 term_setkill({buf}, {how})                             *term_setkill()*
                When exiting Vim or trying to close the terminal window in
                another way, {how} defines whether the job in the terminal can
@@ -8463,6 +8491,9 @@ term_start({cmd}, {options})                              *term_start()*
                                     CTRL-D is used on MS-Windows. For Python
                                     use CTRL-Z or "exit()". For a shell use
                                     "exit".  A CR is always added.
+                  "ansi_colors"     A list of 16 color names or hex codes
+                                    defining the ANSI palette used in GUI
+                                    color modes.  See |g:terminal_ansi_colors|.
 
                {only available when compiled with the |+terminal| feature}
 
index 2d1af112668ac44c631a8781b88f6d0e536325bf..551a3740c2bc2d20ed7d59e01af7b14ea97b0f94 100644 (file)
@@ -136,6 +136,16 @@ terminal window will start with a white or black background.
 To use a different color the Terminal highlight group can be used, for
 example: >
     hi Terminal ctermbg=lightgrey ctermfg=blue guibg=lightgrey guifg=blue
+<
+                                                       *g:terminal_ansi_colors*
+In GUI mode or with |termguicolors|, the 16 ANSI colors used by default in new
+terminal windows may be configured using the variable
+`g:terminal_ansi_colors`, which should be a list of 16 color names or
+hexadecimal color codes, similar to those accepted by |highlight-guifg|.  When
+not using GUI colors, the terminal window always uses the 16 ANSI colors of
+the underlying terminal.
+The |term_setansicolors()| function can be used to change the colors, and
+|term_getansicolors()| to get the currently used colors.
 
 
 Syntax ~
index 88c53b7e0d4d2d483450a02430f4458a284ef5b6..a25e9fe9c8c696ae3ce218bf2194e5c4ff902eb9 100644 (file)
@@ -4802,6 +4802,50 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
                opt->jo_set2 |= JO2_TERM_KILL;
                opt->jo_term_kill = get_tv_string_chk(item);
            }
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+           else if (STRCMP(hi->hi_key, "ansi_colors") == 0)
+           {
+               int             n = 0;
+               listitem_T      *li;
+               long_u          rgb[16];
+
+               if (!(supported2 & JO2_ANSI_COLORS))
+                   break;
+
+               if (item == NULL || item->v_type != VAR_LIST
+                       || item->vval.v_list == NULL)
+               {
+                   EMSG2(_(e_invargval), "ansi_colors");
+                   return FAIL;
+               }
+
+               li = item->vval.v_list->lv_first;
+               for (; li != NULL && n < 16; li = li->li_next, n++)
+               {
+                   char_u      *color_name;
+                   guicolor_T  guicolor;
+
+                   color_name = get_tv_string_chk(&li->li_tv);
+                   if (color_name == NULL)
+                       return FAIL;
+
+                   guicolor = GUI_GET_COLOR(color_name);
+                   if (guicolor == INVALCOLOR)
+                       return FAIL;
+
+                   rgb[n] = GUI_MCH_GET_RGB(guicolor);
+               }
+
+               if (n != 16 || li != NULL)
+               {
+                   EMSG2(_(e_invargval), "ansi_colors");
+                   return FAIL;
+               }
+
+               opt->jo_set2 |= JO2_ANSI_COLORS;
+               memcpy(opt->jo_ansi_colors, rgb, sizeof(rgb));
+           }
+# endif
 #endif
            else if (STRCMP(hi->hi_key, "env") == 0)
            {
index 1ffbb21fa1669e4115ceeb8332277d100984aae8..65279a52f8b4e54ae08061c43b1bbba0bb13d10e 100644 (file)
@@ -856,6 +856,9 @@ static struct fst
     {"term_dumpload",  1, 2, f_term_dumpload},
     {"term_dumpwrite", 2, 3, f_term_dumpwrite},
     {"term_getaltscreen", 1, 1, f_term_getaltscreen},
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+    {"term_getansicolors", 1, 1, f_term_getansicolors},
+# endif
     {"term_getattr",   2, 2, f_term_getattr},
     {"term_getcursor", 1, 1, f_term_getcursor},
     {"term_getjob",    1, 1, f_term_getjob},
@@ -868,6 +871,9 @@ static struct fst
     {"term_list",      0, 0, f_term_list},
     {"term_scrape",    2, 2, f_term_scrape},
     {"term_sendkeys",  2, 2, f_term_sendkeys},
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+    {"term_setansicolors", 2, 2, f_term_setansicolors},
+# endif
     {"term_setkill",   2, 2, f_term_setkill},
     {"term_setrestore",        2, 2, f_term_setrestore},
     {"term_start",     1, 2, f_term_start},
index 0ef7783cdbdadc4b395df87f7c884fe4af27d617..f7cea5a1615e82b12be9ce7c5296c0661fe9b30a 100644 (file)
@@ -32,6 +32,7 @@ int term_swap_diff(void);
 void f_term_dumpdiff(typval_T *argvars, typval_T *rettv);
 void f_term_dumpload(typval_T *argvars, typval_T *rettv);
 void f_term_getaltscreen(typval_T *argvars, typval_T *rettv);
+void f_term_getansicolors(typval_T *argvars, typval_T *rettv);
 void f_term_getattr(typval_T *argvars, typval_T *rettv);
 void f_term_getcursor(typval_T *argvars, typval_T *rettv);
 void f_term_getjob(typval_T *argvars, typval_T *rettv);
@@ -44,6 +45,7 @@ void f_term_gettty(typval_T *argvars, typval_T *rettv);
 void f_term_list(typval_T *argvars, typval_T *rettv);
 void f_term_scrape(typval_T *argvars, typval_T *rettv);
 void f_term_sendkeys(typval_T *argvars, typval_T *rettv);
+void f_term_setansicolors(typval_T *argvars, typval_T *rettv);
 void f_term_setrestore(typval_T *argvars, typval_T *rettv);
 void f_term_setkill(typval_T *argvars, typval_T *rettv);
 void f_term_start(typval_T *argvars, typval_T *rettv);
index db2792bbd7111c18929a669a9d9d0837bad34768..d3f98ac12f3198df02a8c734924be769462b5c98 100644 (file)
@@ -1708,7 +1708,7 @@ struct channel_S {
 #define JO2_EOF_CHARS      0x1000      /* "eof_chars" */
 #define JO2_NORESTORE      0x2000      /* "norestore" */
 #define JO2_TERM_KILL      0x4000      /* "term_kill" */
-#define JO2_ALL                    0x7FFF
+#define JO2_ANSI_COLORS            0x8000      /* "ansi_colors" */
 
 #define JO_MODE_ALL    (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
 #define JO_CB_ALL \
@@ -1777,6 +1777,9 @@ typedef struct
     int                jo_term_finish;
     char_u     *jo_eof_chars;
     char_u     *jo_term_kill;
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+    long_u     jo_ansi_colors[16];
+# endif
 #endif
 } jobopt_T;
 
index a65fc00701e8ce9186d470462db6f23da3c2690a..7859941380ae43d1dd88d76665c91decc1a14963 100644 (file)
  * in tl_scrollback are no longer used.
  *
  * TODO:
- * - Add a way to set the 16 ANSI colors, to be used for 'termguicolors' and in
- *   the GUI. #2747
  * - Win32: Make terminal used for :!cmd in the GUI work better.  Allow for
  *   redirection.  Probably in call to channel_set_pipes().
  * - implement term_setsize()
+ * - add an optional limit for the scrollback size.  When reaching it remove
+ *   10% at the start.
  * - Copy text in the vterm to the Vim buffer once in a while, so that
  *   completion works.
  * - in GUI vertical split causes problems.  Cursor is flickering. (Hirohito
@@ -64,8 +64,6 @@
  *   http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134
  * - when 'encoding' is not utf-8, or the job is using another encoding, setup
  *   conversions.
- * - add an optional limit for the scrollback size.  When reaching it remove
- *   10% at the start.
  */
 
 #include "vim.h"
@@ -3141,6 +3139,75 @@ init_default_colors(term_T *term)
     }
 }
 
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+/*
+ * Set the 16 ANSI colors from array of RGB values
+ */
+    static void
+set_vterm_palette(VTerm *vterm, long_u *rgb)
+{
+    int                index = 0;
+    VTermState *state = vterm_obtain_state(vterm);
+    for (; index < 16; index++)
+    {
+       VTermColor      color;
+       color.red = (unsigned)(rgb[index] >> 16);
+       color.green = (unsigned)(rgb[index] >> 8) & 255;
+       color.blue = (unsigned)rgb[index] & 255;
+       vterm_state_set_palette_color(state, index, &color);
+    }
+}
+
+/*
+ * Set the ANSI color palette from a list of colors
+ */
+    static int
+set_ansi_colors_list(VTerm *vterm, list_T *list)
+{
+    int                n = 0;
+    long_u     rgb[16];
+    listitem_T *li = list->lv_first;
+
+    for (; li != NULL && n < 16; li = li->li_next, n++)
+    {
+       char_u          *color_name;
+       guicolor_T      guicolor;
+
+       color_name = get_tv_string_chk(&li->li_tv);
+       if (color_name == NULL)
+           return FAIL;
+
+       guicolor = GUI_GET_COLOR(color_name);
+       if (guicolor == INVALCOLOR)
+           return FAIL;
+
+       rgb[n] = GUI_MCH_GET_RGB(guicolor);
+    }
+
+    if (n != 16 || li != NULL)
+       return FAIL;
+
+    set_vterm_palette(vterm, rgb);
+
+    return OK;
+}
+
+/*
+ * Initialize the ANSI color palette from g:terminal_ansi_colors[0:15]
+ */
+    static void
+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
+               || set_ansi_colors_list(vterm, var->di_tv.vval.v_list) == FAIL))
+       EMSG2(_(e_invarg2), "g:terminal_ansi_colors");
+}
+#endif
+
 /*
  * Handles a "drop" command from the job in the terminal.
  * "item" is the file name, "item->li_next" may have options.
@@ -3372,6 +3439,9 @@ create_vterm(term_T *term, int rows, int cols)
            &term->tl_default_color.fg,
            &term->tl_default_color.bg);
 
+    if (t_colors >= 16)
+       vterm_state_set_bold_highbright(vterm_obtain_state(vterm), 1);
+
     /* Required to initialize most things. */
     vterm_screen_reset(screen, 1 /* hard */);
 
@@ -4762,6 +4832,68 @@ f_term_sendkeys(typval_T *argvars, typval_T *rettv)
     }
 }
 
+#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO)
+/*
+ * "term_getansicolors(buf)" function
+ */
+    void
+f_term_getansicolors(typval_T *argvars, typval_T *rettv)
+{
+    buf_T      *buf = term_get_buf(argvars, "term_getansicolors()");
+    term_T     *term;
+    VTermState *state;
+    VTermColor  color;
+    char_u     hexbuf[10];
+    int                index;
+    list_T     *list;
+
+    if (rettv_list_alloc(rettv) == FAIL)
+       return;
+
+    if (buf == NULL)
+       return;
+    term = buf->b_term;
+    if (term->tl_vterm == NULL)
+       return;
+
+    list = rettv->vval.v_list;
+    state = vterm_obtain_state(term->tl_vterm);
+    for (index = 0; index < 16; index++)
+    {
+       vterm_state_get_palette_color(state, index, &color);
+       sprintf((char *)hexbuf, "#%02x%02x%02x",
+               color.red, color.green, color.blue);
+       if (list_append_string(list, hexbuf, 7) == FAIL)
+           return;
+    }
+}
+
+/*
+ * "term_setansicolors(buf, list)" function
+ */
+    void
+f_term_setansicolors(typval_T *argvars, typval_T *rettv UNUSED)
+{
+    buf_T      *buf = term_get_buf(argvars, "term_setansicolors()");
+    term_T     *term;
+
+    if (buf == NULL)
+       return;
+    term = buf->b_term;
+    if (term->tl_vterm == NULL)
+       return;
+
+    if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
+    {
+       EMSG(_(e_listreq));
+       return;
+    }
+
+    if (set_ansi_colors_list(term->tl_vterm, argvars[1].vval.v_list) == FAIL)
+       EMSG(_(e_invarg));
+}
+#endif
+
 /*
  * "term_setrestore(buf, command)" function
  */
@@ -4824,7 +4956,8 @@ f_term_start(typval_T *argvars, typval_T *rettv)
                JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
                    + JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
                    + JO2_CWD + JO2_ENV + JO2_EOF_CHARS
-                   + JO2_NORESTORE + JO2_TERM_KILL) == FAIL)
+                   + JO2_NORESTORE + JO2_TERM_KILL
+                   + JO2_ANSI_COLORS) == FAIL)
        return;
 
     buf = term_start(&argvars[0], NULL, &opt, 0);
@@ -5152,6 +5285,13 @@ term_and_job_init(
 
     create_vterm(term, term->tl_rows, term->tl_cols);
 
+#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
+
     channel_set_job(channel, job, opt);
     job_set_options(job, opt);
 
@@ -5324,6 +5464,13 @@ term_and_job_init(
 {
     create_vterm(term, term->tl_rows, term->tl_cols);
 
+#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
+
     /* This may change a string in "argvar". */
     term->tl_job = job_start(argvar, argv, opt);
     if (term->tl_job != NULL)
index 5645625cb378d82fd616021cd3e848ec7ff6d407..3b95d39dd07f2436d591802fe60e1496fb5de1f4 100644 (file)
@@ -1255,3 +1255,73 @@ func Test_terminal_api_call_fails()
   call ch_logfile('', '')
   call delete('Xlog')
 endfunc
+
+func Test_terminal_ansicolors_default()
+  let colors = [
+       \ '#000000', '#e00000',
+       \ '#00e000', '#e0e000',
+       \ '#0000e0', '#e000e0',
+       \ '#00e0e0', '#e0e0e0',
+       \ '#808080', '#ff4040',
+       \ '#40ff40', '#ffff40',
+       \ '#4040ff', '#ff40ff',
+       \ '#40ffff', '#ffffff',
+       \]
+
+  let buf = Run_shell_in_terminal({})
+  call assert_equal(colors, term_getansicolors(buf))
+  call Stop_shell_in_terminal(buf)
+  call term_wait(buf)
+
+  exe buf . 'bwipe'
+endfunc
+
+let s:test_colors = [
+       \ '#616e64', '#0d0a79',
+       \ '#6d610d', '#0a7373',
+       \ '#690d0a', '#6d696e',
+       \ '#0d0a6f', '#616e0d',
+       \ '#0a6479', '#6d0d0a',
+       \ '#617373', '#0d0a69',
+       \ '#6d690d', '#0a6e6f',
+       \ '#610d0a', '#6e6479',
+       \]
+
+func Test_terminal_ansicolors_global()
+  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 Stop_shell_in_terminal(buf)
+  call term_wait(buf)
+
+  exe buf . 'bwipe'
+  unlet g:terminal_ansi_colors
+endfunc
+
+func Test_terminal_ansicolors_func()
+  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))
+
+  call term_setansicolors(buf, g:terminal_ansi_colors)
+  call assert_equal(g:terminal_ansi_colors, term_getansicolors(buf))
+
+  let colors = [
+       \ 'ivory', 'AliceBlue',
+       \ 'grey67', 'dark goldenrod',
+       \ 'SteelBlue3', 'PaleVioletRed4',
+       \ 'MediumPurple2', 'yellow2',
+       \ 'RosyBrown3', 'OrangeRed2',
+       \ 'white smoke', 'navy blue',
+       \ 'grey47', 'gray97',
+       \ 'MistyRose2', 'DodgerBlue4',
+       \]
+  call term_setansicolors(buf, colors)
+
+  let colors[4] = 'Invalid'
+  call assert_fails('call term_setansicolors(buf, colors)', 'E474:')
+
+  call Stop_shell_in_terminal(buf)
+  call term_wait(buf)
+  exe buf . 'bwipe'
+endfunc
index 2890f7135bd783939c1261c241d6b6eef289d817..ff8d0c4bbe973c5624047fe8a725b0dd7227090e 100644 (file)
@@ -762,6 +762,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1685,
 /**/
     1684,
 /**/