To: vim_dev@googlegroups.com Subject: Patch 8.0.1685 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.1685 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) Files: 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 *** ../vim-8.0.1684/runtime/doc/eval.txt 2018-03-29 15:55:30.862510255 +0200 --- runtime/doc/eval.txt 2018-04-10 15:28:26.552370314 +0200 *************** *** 2418,2423 **** --- 2423,2429 ---- 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 *************** *** 2430,2435 **** --- 2436,2443 ---- 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 *************** *** 8190,8195 **** --- 8251,8268 ---- {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: *************** *** 8321,8326 **** --- 8394,8412 ---- 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 *************** *** 8405,8410 **** --- 8491,8499 ---- 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} *** ../vim-8.0.1684/runtime/doc/terminal.txt 2018-04-06 22:26:17.981196807 +0200 --- runtime/doc/terminal.txt 2018-04-10 15:29:47.271797892 +0200 *************** *** 136,141 **** --- 136,151 ---- 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 ~ *** ../vim-8.0.1684/src/channel.c 2018-04-10 12:42:41.027042171 +0200 --- src/channel.c 2018-04-10 15:19:04.308358494 +0200 *************** *** 4802,4807 **** --- 4802,4851 ---- 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) { *** ../vim-8.0.1684/src/evalfunc.c 2018-04-05 22:44:33.771423818 +0200 --- src/evalfunc.c 2018-04-10 15:19:04.312358465 +0200 *************** *** 856,861 **** --- 856,864 ---- {"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,873 **** --- 871,879 ---- {"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}, *** ../vim-8.0.1684/src/proto/terminal.pro 2018-03-16 20:46:52.670189987 +0100 --- src/proto/terminal.pro 2018-04-10 15:19:04.312358465 +0200 *************** *** 32,37 **** --- 32,38 ---- 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,49 **** --- 45,51 ---- 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); *** ../vim-8.0.1684/src/structs.h 2018-03-10 20:27:32.071757661 +0100 --- src/structs.h 2018-04-10 15:47:33.184279955 +0200 *************** *** 1708,1714 **** #define JO2_EOF_CHARS 0x1000 /* "eof_chars" */ #define JO2_NORESTORE 0x2000 /* "norestore" */ #define JO2_TERM_KILL 0x4000 /* "term_kill" */ ! #define JO2_ALL 0x7FFF #define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE) #define JO_CB_ALL \ --- 1708,1714 ---- #define JO2_EOF_CHARS 0x1000 /* "eof_chars" */ #define JO2_NORESTORE 0x2000 /* "norestore" */ #define JO2_TERM_KILL 0x4000 /* "term_kill" */ ! #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,1782 **** --- 1777,1785 ---- 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; *** ../vim-8.0.1684/src/terminal.c 2018-04-10 14:56:14.178103493 +0200 --- src/terminal.c 2018-04-10 15:36:41.076876925 +0200 *************** *** 38,48 **** * 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() * - 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 --- 38,48 ---- * in tl_scrollback are no longer used. * * TODO: * - 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,71 **** * 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" --- 64,69 ---- *************** *** 3141,3146 **** --- 3139,3213 ---- } } + #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,3377 **** --- 3439,3447 ---- &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,4767 **** --- 4832,4899 ---- } } + #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,4830 **** 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) return; buf = term_start(&argvars[0], NULL, &opt, 0); --- 4956,4963 ---- 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 ! + JO2_ANSI_COLORS) == FAIL) return; buf = term_start(&argvars[0], NULL, &opt, 0); *************** *** 5152,5157 **** --- 5285,5297 ---- 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,5329 **** --- 5464,5476 ---- { 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) *** ../vim-8.0.1684/src/testdir/test_terminal.vim 2018-04-07 19:27:11.938983767 +0200 --- src/testdir/test_terminal.vim 2018-04-10 15:45:54.656975883 +0200 *************** *** 1255,1257 **** --- 1255,1327 ---- 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 *** ../vim-8.0.1684/src/version.c 2018-04-10 14:56:14.178103493 +0200 --- src/version.c 2018-04-10 15:22:48.738766256 +0200 *************** *** 764,765 **** --- 764,767 ---- { /* Add new patch number below this line */ + /**/ + 1685, /**/ -- hundred-and-one symptoms of being an internet addict: 144. You eagerly await the update of the "Cool Site of the Day." /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///