To: vim_dev@googlegroups.com Subject: Patch 8.2.4982 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4982 Problem: Colors in terminal window are not 100% correct. Solution: Use g:terminal_ansi_colors as documented. (closes #10429, closes #7227 closes #10347) Files: src/job.c, src/option.c, src/proto/term.pro, src/terminal.c, src/proto/terminal.pro, src/term.c, src/testdir/test_functions.vim, src/testdir/test_terminal.vim *** ../vim-8.2.4981/src/job.c 2022-05-09 20:09:19.286641426 +0100 --- src/job.c 2022-05-20 09:28:30.147063583 +0100 *************** *** 548,560 **** break; if (item == NULL || item->v_type != VAR_LIST ! || item->vval.v_list == NULL) { 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++) { --- 548,560 ---- break; if (item == NULL || item->v_type != VAR_LIST ! || 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; } li = item->vval.v_list->lv_first; for (; li != NULL && n < 16; li = li->li_next, n++) { *** ../vim-8.2.4981/src/option.c 2022-05-09 20:09:19.290641428 +0100 --- src/option.c 2022-05-20 09:34:38.504068577 +0100 *************** *** 3255,3260 **** --- 3255,3261 ---- # endif # ifdef FEAT_TERMINAL term_update_colors_all(); + term_update_palette_all(); term_update_wincolor_all(); # endif } *** ../vim-8.2.4981/src/proto/term.pro 2021-12-03 20:43:20.088234242 +0000 --- src/proto/term.pro 2022-05-20 09:32:40.535766493 +0100 *************** *** 84,89 **** --- 84,90 ---- 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 : */ *** ../vim-8.2.4981/src/terminal.c 2022-05-09 20:09:19.294641425 +0100 --- src/terminal.c 2022-05-20 09:34:36.096062524 +0100 *************** *** 162,167 **** --- 162,169 ---- 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,247 **** --- 244,268 ---- 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,710 **** --- 726,743 ---- 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,1123 **** --- 1151,1157 ---- #endif vim_free(term->tl_highlight_name); vim_free(term->tl_cursor_color); + vim_free(term->tl_palette); vim_free(term); } } *************** *** 2795,2825 **** int blue = color->blue; int green = color->green; 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) { ! 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 } } if (t_colors >= 256) --- 2829,2852 ---- int blue = color->blue; int green = color->green; + *boldp = FALSE; + if (VTERM_COLOR_IS_INVALID(color)) return 0; + if (VTERM_COLOR_IS_INDEXED(color)) { ! // 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) { ! *boldp = TRUE; ! return (color->index & 7) + 1; } + return 0; } if (t_colors >= 256) *************** *** 4251,4261 **** { 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)) semsg(_(e_invalid_argument_str), "g:terminal_ansi_colors"); } #endif --- 4278,4290 ---- { dictitem_T *var = find_var((char_u *)"g:terminal_ansi_colors", NULL, TRUE); ! 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 *************** *** 4690,4695 **** --- 4719,4780 ---- } /* + * 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,6351 **** --- 6431,6438 ---- { buf_T *buf; term_T *term; + listitem_T *li; + int n = 0; if (in_vim9script() && (check_for_buffer_arg(argvars, 0) == FAIL *************** *** 6364,6372 **** emsg(_(e_list_required)); return; } ! ! if (set_ansi_colors_list(term->tl_vterm, argvars[1].vval.v_list) == FAIL) emsg(_(e_invalid_argument)); } #endif --- 6451,6488 ---- emsg(_(e_list_required)); return; } ! 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,6834 **** 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 channel_set_job(channel, job, opt); job_set_options(job, opt); --- 6939,6951 ---- if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL) goto failed; ! 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,7165 **** 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 channel_set_job(channel, job, opt); job_set_options(job, opt); --- 7271,7283 ---- if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL) goto failed; ! 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,7424 **** 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 // This may change a string in "argvar". term->tl_job = job_start(argvar, argv, opt, &term->tl_job); --- 7531,7543 ---- if (create_vterm(term, term->tl_rows, term->tl_cols) == FAIL) return FAIL; ! 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); *** ../vim-8.2.4981/src/proto/terminal.pro 2021-12-13 21:59:04.895993159 +0000 --- src/proto/terminal.pro 2022-05-20 09:34:11.155999571 +0100 *************** *** 34,39 **** --- 34,40 ---- 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); *** ../vim-8.2.4981/src/term.c 2022-05-09 20:09:19.294641425 +0100 --- src/term.c 2022-05-20 09:28:30.151063595 +0100 *************** *** 6730,6736 **** 0x80, 0x8A, 0x94, 0x9E, 0xA8, 0xB2, 0xBC, 0xC6, 0xD0, 0xDA, 0xE4, 0xEE }; ! static char_u ansi_table[16][3] = { // R G B { 0, 0, 0}, // black {224, 0, 0}, // dark red --- 6730,6736 ---- 0x80, 0x8A, 0x94, 0x9E, 0xA8, 0xB2, 0xBC, 0xC6, 0xD0, 0xDA, 0xE4, 0xEE }; ! static const char_u ansi_table[16][3] = { // R G B { 0, 0, 0}, // black {224, 0, 0}, // dark red *************** *** 6761,6766 **** --- 6761,6785 ---- #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) { int idx; *** ../vim-8.2.4981/src/testdir/test_functions.vim 2022-05-05 20:18:12.408138480 +0100 --- src/testdir/test_functions.vim 2022-05-20 09:28:30.155063608 +0100 *************** *** 2679,2686 **** else let cmd = "ls" endif ! call assert_fails('call term_start("' .. cmd .. '", #{term_finish: "close"})', 'E475:') ! unlet g:terminal_ansi_colors endif " type() --- 2679,2686 ---- else let cmd = "ls" endif ! call assert_fails('call term_start("' .. cmd .. '", #{term_finish: "close"' ! \ .. ', ansi_colors: range(16)})', 'E475:') endif " type() *** ../vim-8.2.4981/src/testdir/test_terminal.vim 2022-03-31 12:33:56.485701120 +0100 --- src/testdir/test_terminal.vim 2022-05-20 09:28:30.155063608 +0100 *************** *** 2012,2021 **** --- 2012,2027 ---- 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,2030 **** --- 2031,2041 ---- 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,2052 **** --- 2058,2064 ---- 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, [])) *** ../vim-8.2.4981/src/version.c 2022-05-19 10:31:06.969630503 +0100 --- src/version.c 2022-05-20 09:30:53.815480276 +0100 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 4982, /**/ -- hundred-and-one symptoms of being an internet addict: 237. You tattoo your email address on your forehead. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///