changeset 19797:d73d982499ae v8.2.0455

patch 8.2.0455: cannot set the highlight group for a specific terminal Commit: https://github.com/vim/vim/commit/83d4790a04780328c9c7ad22d18f404a27c11601 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Mar 26 20:34:00 2020 +0100 patch 8.2.0455: cannot set the highlight group for a specific terminal Problem: Cannot set the highlight group for a specific terminal. Solution: Add the "highlight" option to term_start(). (closes https://github.com/vim/vim/issues/5818)
author Bram Moolenaar <Bram@vim.org>
date Thu, 26 Mar 2020 20:45:03 +0100
parents dd865be96964
children ab0a91ba7a13
files runtime/doc/terminal.txt src/channel.c src/structs.h src/terminal.c src/testdir/dumps/Test_terminal_popup_MyTermCol.dump src/testdir/dumps/Test_terminal_popup_Terminal.dump src/testdir/test_terminal.vim src/version.c
diffstat 8 files changed, 194 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/terminal.txt
+++ b/runtime/doc/terminal.txt
@@ -1,4 +1,4 @@
-*terminal.txt*	For Vim version 8.2.  Last change: 2020 Jan 30
+*terminal.txt*	For Vim version 8.2.  Last change: 2020 Mar 26
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -148,7 +148,12 @@ terminal window will start with a white 
 To use a different color the Terminal highlight group can be used, for
 example: >
     hi Terminal ctermbg=lightgrey ctermfg=blue guibg=lightgrey guifg=blue
-<
+The highlight needs to be defined before the terminal is created.  Doing it
+later, or setting 'wincolor', will only have effect when the program running
+in the terminal displays text or clears the terminal.
+Instead of Terminal another group can be specified with the "term_highlight"
+option for `term_start()`.
+
 							*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
@@ -857,6 +862,8 @@ term_start({cmd} [, {options}])			*term_
 				     have "%d" where the buffer number goes,
 				     e.g. "10split|buffer %d"; when not
 				     specified "botright sbuf %d" is used
+		   "term_highlight"  highlight group to use instead of
+				     "Terminal"
 		   "eof_chars"	     Text to send after all buffer lines were
 				     written to the terminal.  When not set
 				     CTRL-D is used on MS-Windows. For Python
--- a/src/channel.c
+++ b/src/channel.c
@@ -5168,6 +5168,21 @@ get_job_options(typval_T *tv, jobopt_T *
 		memcpy(opt->jo_ansi_colors, rgb, sizeof(rgb));
 	    }
 # endif
+	    else if (STRCMP(hi->hi_key, "term_highlight") == 0)
+	    {
+		char_u *p;
+
+		if (!(supported2 & JO2_TERM_HIGHLIGHT))
+		    break;
+		opt->jo_set2 |= JO2_TERM_HIGHLIGHT;
+		p = tv_get_string_buf_chk(item, opt->jo_term_highlight_buf);
+		if (p == NULL || *p == NUL)
+		{
+		    semsg(_(e_invargval), "term_highlight");
+		    return FAIL;
+		}
+		opt->jo_term_highlight = p;
+	    }
 	    else if (STRCMP(hi->hi_key, "term_api") == 0)
 	    {
 		if (!(supported2 & JO2_TERM_API))
--- a/src/structs.h
+++ b/src/structs.h
@@ -2071,6 +2071,7 @@ struct channel_S {
 #define JO2_TTY_TYPE	    0x10000	// "tty_type"
 #define JO2_BUFNR	    0x20000	// "bufnr"
 #define JO2_TERM_API	    0x40000	// "term_api"
+#define JO2_TERM_HIGHLIGHT  0x80000	// "highlight"
 
 #define JO_MODE_ALL	(JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
 #define JO_CB_ALL \
@@ -2143,6 +2144,8 @@ typedef struct
 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
     long_u	jo_ansi_colors[16];
 # endif
+    char_u	jo_term_highlight_buf[NUMBUFLEN];
+    char_u	*jo_term_highlight;
     int		jo_tty_type;	    // first character of "tty_type"
     char_u	jo_term_api_buf[NUMBUFLEN];
     char_u	*jo_term_api;
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -148,6 +148,8 @@ struct terminal_S {
     int		tl_scrollback_scrolled;
     garray_T	tl_scrollback_postponed;
 
+    char_u	*tl_highlight_name; // replaces "Terminal"; allocated
+
     cellattr_T	tl_default_color;
 
     linenr_T	tl_top_diff_rows;   // rows of top diff file or zero
@@ -665,6 +667,9 @@ term_start(
     else
 	term->tl_api = vim_strsave((char_u *)"Tapi_");
 
+    if (opt->jo_set2 & JO2_TERM_HIGHLIGHT)
+	term->tl_highlight_name = vim_strsave(opt->jo_term_highlight);
+
     // System dependent: setup the vterm and maybe start the job in it.
     if (argv == NULL
 	    && argvar->v_type == VAR_STRING
@@ -1024,6 +1029,7 @@ free_unused_terminals()
 	if (term->tl_out_fd != NULL)
 	    fclose(term->tl_out_fd);
 #endif
+	vim_free(term->tl_highlight_name);
 	vim_free(term->tl_cursor_color);
 	vim_free(term);
     }
@@ -2215,6 +2221,17 @@ terminal_is_active()
     return in_terminal_loop != NULL;
 }
 
+/*
+ * Return the highight group name for the terminal; "Terminal" if not set.
+ */
+    static char_u *
+term_get_highlight_name(term_T *term)
+{
+    if (term->tl_highlight_name == NULL)
+	return (char_u *)"Terminal";
+    return term->tl_highlight_name;
+}
+
 #if defined(FEAT_GUI) || defined(PROTO)
     cursorentry_T *
 term_get_cursor_shape(guicolor_T *fg, guicolor_T *bg)
@@ -2237,8 +2254,8 @@ term_get_cursor_shape(guicolor_T *fg, gu
 	entry.blinkoff = 250;
     }
 
-    // The "Terminal" highlight group overrules the defaults.
-    id = syn_name2id((char_u *)"Terminal");
+    // The highlight group overrules the defaults.
+    id = syn_name2id(term_get_highlight_name(term));
     if (id != 0)
     {
 	syn_id2colors(id, &term_fg, &term_bg);
@@ -2618,6 +2635,48 @@ may_toggle_cursor(term_T *term)
 }
 
 /*
+ * Cache "Terminal" highlight group colors.
+ */
+    void
+set_terminal_default_colors(int cterm_fg, int cterm_bg)
+{
+    term_default_cterm_fg = cterm_fg - 1;
+    term_default_cterm_bg = cterm_bg - 1;
+}
+
+    static int
+get_default_cterm_fg(term_T *term)
+{
+    if (term->tl_highlight_name != NULL)
+    {
+	int id = syn_name2id(term->tl_highlight_name);
+	int fg = -1;
+	int bg = -1;
+
+	if (id > 0)
+	    syn_id2cterm_bg(id, &fg, &bg);
+	return fg;
+    }
+    return term_default_cterm_fg;
+}
+
+    static int
+get_default_cterm_bg(term_T *term)
+{
+    if (term->tl_highlight_name != NULL)
+    {
+	int id = syn_name2id(term->tl_highlight_name);
+	int fg = -1;
+	int bg = -1;
+
+	if (id > 0)
+	    syn_id2cterm_bg(id, &fg, &bg);
+	return bg;
+    }
+    return term_default_cterm_bg;
+}
+
+/*
  * Reverse engineer the RGB value into a cterm color index.
  * First color is 1.  Return 0 if no match found (default color).
  */
@@ -2738,6 +2797,7 @@ hl2vtermAttr(int attr, cellattr_T *cell)
  */
     static int
 cell2attr(
+	term_T			*term,
 	win_T			*wp,
 	VTermScreenCellAttrs	cellattrs,
 	VTermColor		cellfg,
@@ -2792,15 +2852,25 @@ cell2attr(
 	    {
 		if (wincolor_fg >= 0)
 		    fg = wincolor_fg + 1;
-		else if (term_default_cterm_fg >= 0)
-		    fg = term_default_cterm_fg + 1;
+		else
+		{
+		    int cterm_fg = get_default_cterm_fg(term);
+
+		    if (cterm_fg >= 0)
+			fg = cterm_fg + 1;
+		}
 	    }
 	    if (bg == 0)
 	    {
 		if (wincolor_bg >= 0)
 		    bg = wincolor_bg + 1;
-		else if (term_default_cterm_bg >= 0)
-		    bg = term_default_cterm_bg + 1;
+		else
+		{
+		    int cterm_bg = get_default_cterm_bg(term);
+
+		    if (cterm_bg >= 0)
+			bg = cterm_bg + 1;
+		}
 	    }
 	}
 
@@ -2856,7 +2926,7 @@ term_scroll_up(term_T *term, int start_r
 	    // Set the color to clear lines with.
 	    vterm_state_get_default_colors(vterm_obtain_state(term->tl_vterm),
 								     &fg, &bg);
-	    clear_attr = cell2attr(wp, attr, fg, bg);
+	    clear_attr = cell2attr(term, wp, attr, fg, bg);
 	    win_del_lines(wp, start_row, count, FALSE, FALSE, clear_attr);
 	}
     }
@@ -3416,6 +3486,7 @@ term_check_channel_closed_recently()
  */
     static void
 term_line2screenline(
+	term_T		*term,
 	win_T		*wp,
 	VTermScreen	*screen,
 	VTermPos	*pos,
@@ -3484,7 +3555,7 @@ term_line2screenline(
 	    else
 		ScreenLines[off] = c;
 	}
-	ScreenAttrs[off] = cell2attr(wp, cell.attrs, cell.fg, cell.bg);
+	ScreenAttrs[off] = cell2attr(term, wp, cell.attrs, cell.fg, cell.bg);
 
 	++pos->col;
 	++off;
@@ -3535,7 +3606,7 @@ update_system_term(term_T *term)
 	{
 	    int max_col = MIN(Columns, term->tl_cols);
 
-	    term_line2screenline(NULL, screen, &pos, max_col);
+	    term_line2screenline(term, NULL, screen, &pos, max_col);
 	}
 	else
 	    pos.col = 0;
@@ -3649,7 +3720,7 @@ term_update_window(win_T *wp)
 	{
 	    int max_col = MIN(wp->w_width, term->tl_cols);
 
-	    term_line2screenline(wp, screen, &pos, max_col);
+	    term_line2screenline(term, wp, screen, &pos, max_col);
 	}
 	else
 	    pos.col = 0;
@@ -3732,7 +3803,7 @@ term_get_attr(win_T *wp, linenr_T lnum, 
 	else
 	    cellattr = line->sb_cells + col;
     }
-    return cell2attr(wp, cellattr->attrs, cellattr->fg, cellattr->bg);
+    return cell2attr(term, wp, cellattr->attrs, cellattr->fg, cellattr->bg);
 }
 
 /*
@@ -3776,11 +3847,11 @@ init_default_colors(term_T *term, win_T 
     bg->red = bg->green = bg->blue = bgval;
     fg->ansi_index = bg->ansi_index = VTERM_ANSI_INDEX_DEFAULT;
 
-    // The 'wincolor' or "Terminal" highlight group overrules the defaults.
+    // The 'wincolor' or the highlight group overrules the defaults.
     if (wp != NULL && *wp->w_p_wcr != NUL)
 	id = syn_name2id(wp->w_p_wcr);
     else
-	id = syn_name2id((char_u *)"Terminal");
+	id = syn_name2id(term_get_highlight_name(term));
 
     // Use the actual color for the GUI and when 'termguicolors' is set.
 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
@@ -3844,10 +3915,13 @@ init_default_colors(term_T *term, win_T 
 #endif
     if (id != 0 && t_colors >= 16)
     {
-	if (term_default_cterm_fg >= 0)
-	    cterm_color2vterm(term_default_cterm_fg, fg);
-	if (term_default_cterm_bg >= 0)
-	    cterm_color2vterm(term_default_cterm_bg, bg);
+	int cterm_fg = get_default_cterm_fg(term);
+	int cterm_bg = get_default_cterm_bg(term);
+
+	if (cterm_fg >= 0)
+	    cterm_color2vterm(cterm_fg, fg);
+	if (cterm_bg >= 0)
+	    cterm_color2vterm(cterm_bg, bg);
     }
     else
     {
@@ -4387,16 +4461,6 @@ set_ref_in_term(int copyID)
 }
 
 /*
- * Cache "Terminal" highlight group colors.
- */
-    void
-set_terminal_default_colors(int cterm_fg, int cterm_bg)
-{
-    term_default_cterm_fg = cterm_fg - 1;
-    term_default_cterm_bg = cterm_bg - 1;
-}
-
-/*
  * Get the buffer from the first argument in "argvars".
  * Returns NULL when the buffer is not for a terminal window and logs a message
  * with "where".
@@ -5745,7 +5809,7 @@ f_term_scrape(typval_T *argvars, typval_
 				     bg.red, bg.green, bg.blue);
 	dict_add_string(dcell, "bg", rgb);
 
-	dict_add_number(dcell, "attr", cell2attr(NULL, attrs, fg, bg));
+	dict_add_number(dcell, "attr", cell2attr(term, NULL, attrs, fg, bg));
 	dict_add_number(dcell, "width", width);
 
 	++pos.col;
@@ -5937,7 +6001,7 @@ f_term_start(typval_T *argvars, typval_T
 		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_NORESTORE + JO2_TERM_KILL + JO2_TERM_HIGHLIGHT
 		    + JO2_ANSI_COLORS + JO2_TTY_TYPE + JO2_TERM_API) == FAIL)
 	return;
 
@@ -6861,6 +6925,8 @@ term_and_job_init(
 	jobopt_T    *orig_opt UNUSED)
 {
     term->tl_arg0_cmd = NULL;
+    if (opt->jo_set2 & JO2_TERM_HIGHLIGHT)
+	term->tl_highlight_name = vim_strsave(opt->jo_term_highlight);
 
     if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL)
 	return FAIL;
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_terminal_popup_MyTermCol.dump
@@ -0,0 +1,15 @@
+|0+0&#ffffff0| @73
+|1| @73
+|2| @73
+|3| @73
+|4| @24|╔+0#0000001#ffd7ff255|═@19|╗| +0#0000000#ffffff0@26
+|5| @24|║+0#0000001#ffd7ff255|h+0#00e0003#5fd7ff255|e|l@1|o| @14|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26
+|6| @24|║+0#0000001#ffd7ff255|h+0#00e0003#5fd7ff255|e|l@1|o| @14|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26
+|7| @24|║+0#0000001#ffd7ff255> +0#00e0003#5fd7ff255@19|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26
+|8| @24|║+0#0000001#ffd7ff255| +0#00e0003#5fd7ff255@19|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26
+|9| @24|║+0#0000001#ffd7ff255| +0#00e0003#5fd7ff255@19|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26
+|1|0| @23|╚+0#0000001#ffd7ff255|═@19|╝| +0#0000000#ffffff0@26
+|1@1| @72
+|1|2| @72
+|1|3| @72
+@75
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_terminal_popup_Terminal.dump
@@ -0,0 +1,15 @@
+|0+0&#ffffff0| @73
+|1| @73
+|2| @73
+|3| @73
+|4| @24|╔+0#0000001#ffd7ff255|═@19|╗| +0#0000000#ffffff0@26
+|5| @24|║+0#0000001#ffd7ff255|h+0#4040ff13#ffff4012|e|l@1|o| @14|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26
+|6| @24|║+0#0000001#ffd7ff255|h+0#4040ff13#ffff4012|e|l@1|o| @14|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26
+|7| @24|║+0#0000001#ffd7ff255> +0#4040ff13#ffff4012@19|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26
+|8| @24|║+0#0000001#ffd7ff255| +0#4040ff13#ffff4012@19|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26
+|9| @24|║+0#0000001#ffd7ff255| +0#4040ff13#ffff4012@19|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@26
+|1|0| @23|╚+0#0000001#ffd7ff255|═@19|╝| +0#0000000#ffffff0@26
+|1@1| @72
+|1|2| @72
+|1|3| @72
+@75
--- a/src/testdir/test_terminal.vim
+++ b/src/testdir/test_terminal.vim
@@ -2434,7 +2434,6 @@ func Test_terminal_in_popup_min_size()
   let lines = [
 	\ 'set t_u7=',
 	\ 'call setline(1, range(20))',
-	\ 'hi PopTerm ctermbg=grey',
 	\ 'func OpenTerm()',
 	\ "  let s:buf = term_start('cat Xtext', #{hidden: 1})",
 	\ '  let g:winid = popup_create(s:buf, #{ border: []})',
@@ -2457,6 +2456,46 @@ func Test_terminal_in_popup_min_size()
   call delete('XtermPopup')
 endfunc
 
+" Check a terminal in popup window with different colors
+func Terminal_in_popup_colored(group_name, highlight_cmd, highlight_opt)
+  CheckRunVimInTerminal
+  CheckUnix
+
+  let lines = [
+	\ 'set t_u7=',
+	\ 'call setline(1, range(20))',
+	\ 'func OpenTerm()',
+	\ "  let s:buf = term_start('cat', #{hidden: 1, "
+	\ .. a:highlight_opt .. "})",
+	\ '  let g:winid = popup_create(s:buf, #{ border: []})',
+	\ 'endfunc',
+	\ a:highlight_cmd,
+	\ ]
+  call writefile(lines, 'XtermPopup')
+  let buf = RunVimInTerminal('-S XtermPopup', #{rows: 15})
+  call term_wait(buf, 200)
+  call term_sendkeys(buf, ":set noruler\<CR>")
+  call term_sendkeys(buf, ":call OpenTerm()\<CR>")
+  call term_wait(buf, 100)
+  call term_sendkeys(buf, "hello\<CR>")
+  call VerifyScreenDump(buf, 'Test_terminal_popup_' .. a:group_name, {})
+
+  call term_sendkeys(buf, "\<C-D>")
+  call term_wait(buf, 100)
+  call term_sendkeys(buf, ":q\<CR>")
+  call term_wait(buf, 100)  " wait for terminal to vanish
+  call StopVimInTerminal(buf)
+  call delete('XtermPopup')
+endfunc
+
+func Test_terminal_in_popup_colored_Terminal()
+  call Terminal_in_popup_colored("Terminal", "highlight Terminal ctermfg=blue ctermbg=yellow", "")
+endfunc
+
+func Test_terminal_in_popup_colored_group()
+  call Terminal_in_popup_colored("MyTermCol", "highlight MyTermCol ctermfg=darkgreen ctermbg=lightblue", "term_highlight: 'MyTermCol',")
+endfunc
+
 func Test_double_popup_terminal()
   let buf1 = term_start(&shell, #{hidden: 1})
   let win1 = popup_create(buf1, {})
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    455,
+/**/
     454,
 /**/
     453,