# HG changeset patch # User Bram Moolenaar # Date 1585251903 -3600 # Node ID d73d982499aee8b4034174d86dbf34c03f139254 # Parent dd865be96964dedf26024cc8bc0dbbe0855ae0e5 patch 8.2.0455: cannot set the highlight group for a specific terminal Commit: https://github.com/vim/vim/commit/83d4790a04780328c9c7ad22d18f404a27c11601 Author: Bram Moolenaar 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) diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt --- 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 diff --git a/src/channel.c b/src/channel.c --- 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)) diff --git a/src/structs.h b/src/structs.h --- 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; diff --git a/src/terminal.c b/src/terminal.c --- 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; diff --git a/src/testdir/dumps/Test_terminal_popup_MyTermCol.dump b/src/testdir/dumps/Test_terminal_popup_MyTermCol.dump 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 diff --git a/src/testdir/dumps/Test_terminal_popup_Terminal.dump b/src/testdir/dumps/Test_terminal_popup_Terminal.dump 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 diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim --- 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\") + call term_sendkeys(buf, ":call OpenTerm()\") + call term_wait(buf, 100) + call term_sendkeys(buf, "hello\") + call VerifyScreenDump(buf, 'Test_terminal_popup_' .. a:group_name, {}) + + call term_sendkeys(buf, "\") + call term_wait(buf, 100) + call term_sendkeys(buf, ":q\") + 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, {}) diff --git a/src/version.c b/src/version.c --- 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,