From c077f5e9d82189f5d1ce86068e10540139fec6cb Mon Sep 17 00:00:00 2001 From: Foxe Chen Date: Sun, 14 Sep 2025 04:38:33 -0400 Subject: [PATCH] patch 9.1.1757: The colorresp plugin causes additional redraws Problem: The colorresp plugin causes additional redraws (Linwei, after v9.1.1703) Solution: Move the code back into the C core and get rid of the vim plugin (Foxe Chen) fixes: #18251 closes: #18279 Signed-off-by: Foxe Chen Signed-off-by: Christian Brabandt --- runtime/doc/autocmd.txt | 13 +- runtime/doc/eval.txt | 17 ++- runtime/doc/version9.txt | 5 +- runtime/plugin/README.txt | 1 - runtime/plugin/colorresp.vim | 51 -------- src/evalvars.c | 4 +- src/main.c | 2 + src/proto/term.pro | 1 + src/term.c | 181 +++++++++++++++++++++++--- src/testdir/Make_all.mak | 2 - src/testdir/test_plugin_colorresp.vim | 74 ----------- src/testdir/test_termcodes.vim | 68 ++++++++++ src/version.c | 2 + 13 files changed, 251 insertions(+), 170 deletions(-) delete mode 100644 runtime/plugin/colorresp.vim delete mode 100644 src/testdir/test_plugin_colorresp.vim diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 490ad44563..24dbca49cc 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -1,4 +1,4 @@ -*autocmd.txt* For Vim version 9.1. Last change: 2025 Sep 11 +*autocmd.txt* For Vim version 9.1. Last change: 2025 Sep 14 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1313,8 +1313,10 @@ TermResponseAll After the response to |t_RV|, |t_RC|, |t_RS|, correspondingly, can be used. will be set to any of: "ambiguouswidth" (|t_u7|), + "background" (|t_RB|), "cursorblink" (|t_RC|), "cursorshape" (|t_RS|), + "foreground" (|t_RF|), "da1", "osc", "version" (|t_RV|) @@ -1322,15 +1324,6 @@ TermResponseAll After the response to |t_RV|, |t_RC|, |t_RS|, executing another event, especially if file I/O, a shell command or anything else that takes time is involved. - Note: Traditionally, TermResponseAll was also - used for "foreground" and "background" - patterns. These are now handled as part of - the "osc" value. For backwards compatibility, - the $VIMRUNTIME/plugin/colorresp.vim plugin - will handle "osc" events and emit - TermResponseAll autocommand events when it - encounters "foreground" and "background" - values. *TextChanged* TextChanged After a change was made to the text in the current buffer in Normal mode. That is after diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index efd6218d49..fde9ac3190 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 9.1. Last change: 2025 Aug 29 +*eval.txt* For Vim version 9.1. Last change: 2025 Sep 14 VIM REFERENCE MANUAL by Bram Moolenaar @@ -2896,15 +2896,16 @@ v:termstyleresp The escape sequence returned by the terminal for the |t_RS| *v:termrbgresp* *termrbgresp-variable* v:termrbgresp The escape sequence returned by the terminal for the |t_RB| termcap entry. This is used to find out what the terminal - background color is; see 'background'. This is set by the - $VIMRUNTIME/plugin/colorresp.vim plugin normally included with - Vim, but can be set manually if you know what you are doing. - Note that changing this will not do anything. + background color is; see 'background'. When this option is + set, the TermResponseAll autocommand event is fired, with + set to "background". *v:termrfgresp* *termrfgresp-variable* v:termrfgresp The escape sequence returned by the terminal for the |t_RF| termcap entry. This is used to find out what the terminal - foreground color is. Behaves the same as |v:termrbgresp| + foreground color is. When this option is set, the + TermResponseAll autocommand event is fired, with set + to "foreground". *v:termu7resp* *termu7resp-variable* v:termu7resp The escape sequence returned by the terminal for the |t_u7| @@ -2923,9 +2924,7 @@ v:termda1 The escape sequence returned by a primary device attributes v:termosc The escape sequence of the most recent OSC response received from the terminal. When this variable is set, the |TermResponseAll| autocommand event is fired, with - set to "osc". Also used to set the |v:termrbgresp| and - |v:termrfgresp| via the $VIMRUNTIME/plugin/colorresp.vim - plugin + set to "osc". *v:testing* *testing-variable* v:testing Must be set before using `test_garbagecollect_now()`. diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index 0fe59634ca..0a1e385046 100644 --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -1,4 +1,4 @@ -*version9.txt* For Vim version 9.1. Last change: 2025 Sep 13 +*version9.txt* For Vim version 9.1. Last change: 2025 Sep 14 VIM REFERENCE MANUAL by Bram Moolenaar @@ -41759,9 +41759,6 @@ Others: ~ Command-line. - |min()|/|max()| can handle all comparable data types. - Vim triggers the |TermResponseAll| autocommand for any terminal OSC value. -- Vim includes the $VIMRUNTIME/plugins/colorresp.vim which parses the terminal - OSC response and can trigger a |TermResponseAll| with the "background" or - "foreground" value. Platform specific ~ - MS-Winodws: Paths like "\Windows" and "/Windows" are now considered to be diff --git a/runtime/plugin/README.txt b/runtime/plugin/README.txt index e4f3c1b708..6161b6f640 100644 --- a/runtime/plugin/README.txt +++ b/runtime/plugin/README.txt @@ -3,7 +3,6 @@ The plugin directory is for standard Vim plugin scripts. All files here ending in .vim will be sourced by Vim when it starts up. Look in the file for hints on how it can be disabled without deleting it. -colorresp.vim used to detect terminal background and foreground colours getscriptPlugin.vim get latest version of Vim scripts gzip.vim edit compressed files logiPat.vim logical operators on patterns diff --git a/runtime/plugin/colorresp.vim b/runtime/plugin/colorresp.vim deleted file mode 100644 index b03f68fbfd..0000000000 --- a/runtime/plugin/colorresp.vim +++ /dev/null @@ -1,51 +0,0 @@ -vim9script - -# Vim plugin for setting the background and foreground colours depending on -# the terminal response. -# -# Maintainer: The Vim Project -# Last Change: 2025 Sep 05 - -if exists("g:loaded_colorresp") - finish -endif -g:loaded_colorresp = 1 - -augroup ColorResp - au! - au TermResponseAll osc { - var parts: list = matchlist(v:termosc, '\(\d\+\);rgb:\(\w\+\)/\(\w\+\)/\(\w\+\)') - if len(parts) >= 5 - var type: string = parts[1] - var rval: number = str2nr(parts[2][: 1], 16) - var gval: number = str2nr(parts[3][: 1], 16) - var bval: number = str2nr(parts[4][: 1], 16) - - if type == '11' - # Detect light or dark background by parsing OSC 11 RGB background reply - # from terminal. Sum the RGB values roughly; if bright enough, set - # 'background' to 'light', otherwise set it to 'dark'. - var new_bg_val: string = (3 * char2nr('6') < char2nr(parts[2]) + char2nr(parts[3]) + char2nr(parts[4])) ? "light" : "dark" - - v:termrbgresp = v:termosc - &background = new_bg_val - # For backwards compatibility - if exists('#TermResponseAll#background') - doautocmd TermResponseAll background - endif - else - v:termrfgresp = v:termosc - # For backwards compatibility - if exists('#TermResponseAll#foreground') - doautocmd TermResponseAll foreground - endif - endif - endif - } - au VimEnter * ++once { - call echoraw(&t_RB) - call echoraw(&t_RF) - } -augroup END - -# vim: set sw=2 sts=2 : diff --git a/src/evalvars.c b/src/evalvars.c index c43841d348..e1eb89437a 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -141,8 +141,8 @@ static struct vimvar {VV_NAME("t_blob", VAR_NUMBER), NULL, VV_RO}, {VV_NAME("t_class", VAR_NUMBER), NULL, VV_RO}, {VV_NAME("t_object", VAR_NUMBER), NULL, VV_RO}, - {VV_NAME("termrfgresp", VAR_STRING), NULL, 0}, - {VV_NAME("termrbgresp", VAR_STRING), NULL, 0}, + {VV_NAME("termrfgresp", VAR_STRING), NULL, VV_RO}, + {VV_NAME("termrbgresp", VAR_STRING), NULL, VV_RO}, {VV_NAME("termu7resp", VAR_STRING), NULL, VV_RO}, {VV_NAME("termstyleresp", VAR_STRING), NULL, VV_RO}, {VV_NAME("termblinkresp", VAR_STRING), NULL, VV_RO}, diff --git a/src/main.c b/src/main.c index 942a7e5f8f..c77454a26f 100644 --- a/src/main.c +++ b/src/main.c @@ -883,6 +883,8 @@ vim_main2(void) // Requesting the termresponse is postponed until here, so that a "-c q" // argument doesn't make it appear in the shell Vim was started from. may_req_termresponse(); + + may_req_bg_color(); #endif // start in insert mode diff --git a/src/proto/term.pro b/src/proto/term.pro index 8b48011b63..c76acabbf3 100644 --- a/src/proto/term.pro +++ b/src/proto/term.pro @@ -59,6 +59,7 @@ void starttermcap(void); void stoptermcap(void); void may_req_termresponse(void); void check_terminal_behavior(void); +void may_req_bg_color(void); int swapping_screen(void); void scroll_start(void); void cursor_on_force(void); diff --git a/src/term.c b/src/term.c index aec9559d0e..ce0d24caa5 100644 --- a/src/term.c +++ b/src/term.c @@ -131,6 +131,19 @@ static termrequest_T u7_status = TERMREQUEST_INIT; static termrequest_T xcc_status = TERMREQUEST_INIT; #ifdef FEAT_TERMRESPONSE +# ifdef FEAT_TERMINAL +// Request foreground color report: +static termrequest_T rfg_status = TERMREQUEST_INIT; +static int fg_r = 0; +static int fg_g = 0; +static int fg_b = 0; +static int bg_r = 255; +static int bg_g = 255; +static int bg_b = 255; +# endif + +// Request background color report: +static termrequest_T rbg_status = TERMREQUEST_INIT; // Request cursor blinking mode report: static termrequest_T rbm_status = TERMREQUEST_INIT; @@ -145,6 +158,10 @@ static termrequest_T *all_termrequests[] = { &crv_status, &u7_status, &xcc_status, +# ifdef FEAT_TERMINAL + &rfg_status, +# endif + &rbg_status, &rbm_status, &rcs_status, &winpos_status, @@ -4190,6 +4207,49 @@ check_terminal_behavior(void) } } +/* + * Similar to requesting the version string: Request the terminal background + * color when it is the right moment. + */ + void +may_req_bg_color(void) +{ + if (can_get_termresponse() && starting == 0) + { + int didit = FALSE; + +# ifdef FEAT_TERMINAL + // Only request foreground if t_RF is set. + if (rfg_status.tr_progress == STATUS_GET && *T_RFG != NUL) + { + MAY_WANT_TO_LOG_THIS; + LOG_TR1("Sending FG request"); + out_str(T_RFG); + termrequest_sent(&rfg_status); + didit = TRUE; + } +# endif + + // Only request background if t_RB is set. + if (rbg_status.tr_progress == STATUS_GET && *T_RBG != NUL) + { + MAY_WANT_TO_LOG_THIS; + LOG_TR1("Sending BG request"); + out_str(T_RBG); + termrequest_sent(&rbg_status); + didit = TRUE; + } + + if (didit) + { + // check for the characters now, otherwise they might be eaten by + // get_keystroke() + out_flush(); + (void)vpeekc_nomap(); + } + } +} + #endif /* @@ -4983,6 +5043,8 @@ handle_u7_response(int *arg, char_u *tp UNUSED, int csi_len UNUSED) } } + + /* * Handle a response to T_CRV: {lead}{first}{x};{vers};{y}c * Xterm and alike use '>' for {first}. @@ -5743,6 +5805,93 @@ handle_csi( return 0; } +static void +check_for_color_response(char_u *resp, int len) +{ + int i, j; + char_u *argp; + + j = 1 + (resp[0] == ESC); + argp = resp + j; + + if (len >= j + 3 && (argp[0] != '1' + || (argp[1] != '1' && argp[1] != '0') + || argp[2] != ';')) + i = 0; // no match + else + { + for (i = j; i < len; ++i) + if (resp[i] == '\007' || (resp[0] == OSC ? resp[i] == STERM + : (resp[i] == ESC && i + 1 < len && resp[i + 1] == '\\'))) + { + int is_bg = argp[1] == '1'; + int is_4digit = i - j >= 21 && resp[j + 11] == '/' + && resp[j + 16] == '/'; + + if (i - j >= 15 && STRNCMP(resp + j + 3, "rgb:", 4) == 0 + && (is_4digit + || (resp[j + 9] == '/' && resp[j + 12] == '/'))) + { + char_u *tp_r = resp + j + 7; + char_u *tp_g = resp + j + (is_4digit ? 12 : 10); + char_u *tp_b = resp + j + (is_4digit ? 17 : 13); +#if defined(FEAT_TERMRESPONSE) && defined(FEAT_TERMINAL) + int rval, gval, bval; + + rval = hexhex2nr(tp_r); + gval = hexhex2nr(tp_g); + bval = hexhex2nr(tp_b); +#endif + if (is_bg) + { + char *new_bg_val = (3 * '6' < *tp_r + *tp_g + + *tp_b) ? "light" : "dark"; + + LOG_TRN("Received RBG response: %s", tp); +#ifdef FEAT_TERMRESPONSE + rbg_status.tr_progress = STATUS_GOT; +# ifdef FEAT_TERMINAL + bg_r = rval; + bg_g = gval; + bg_b = bval; +# endif +#endif + if (!option_was_set((char_u *)"bg") + && STRCMP(p_bg, new_bg_val) != 0) + { + // value differs, apply it + set_option_value_give_err((char_u *)"bg", + 0L, (char_u *)new_bg_val, 0); + reset_option_was_set((char_u *)"bg"); + redraw_asap(UPD_CLEAR); + } + } +#if defined(FEAT_TERMRESPONSE) && defined(FEAT_TERMINAL) + else + { + LOG_TRN("Received RFG response: %s", tp); + rfg_status.tr_progress = STATUS_GOT; + fg_r = rval; + fg_g = gval; + fg_b = bval; + } +#endif + } + +#ifdef FEAT_EVAL + set_vim_var_string(is_bg ? VV_TERMRBGRESP + : VV_TERMRFGRESP, resp, len); +#endif + apply_autocmds(EVENT_TERMRESPONSEALL, + is_bg ? (char_u *)"background" : (char_u *)"foreground", + NULL, FALSE, curbuf); + break; + } + } + if (i == len) + LOG_TR1("not enough characters for RB"); +} + static oscstate_T osc_state; /* @@ -5803,6 +5952,9 @@ handle_osc(char_u *tp, int len, char_u *key_name, int *slen) #ifdef FEAT_EVAL set_vim_var_string_direct(VV_TERMOSC, osc_state.buf.ga_data); #endif + // Check for background/foreground colour response + check_for_color_response(osc_state.buf.ga_data, osc_state.buf.ga_len - 1); + char_u savebg = *p_bg; apply_autocmds(EVENT_TERMRESPONSEALL, (char_u *)"osc", NULL, FALSE, curbuf); @@ -6584,28 +6736,18 @@ handle_osc: } #if (defined(FEAT_TERMINAL) && defined(FEAT_TERMRESPONSE)) || defined(PROTO) - - static void -term_get_color(char_u *str, char_u *r, char_u *g, char_u *b) -{ - char_u rn[3], gn[3], bn[3]; - - if (sscanf((char *)str, "%*[^:]:%2s%*[^/]/%2s%*[^/]/%2s", - (char *)&rn, (char *)&gn, (char *)&bn) != 3) - return; - - *r = hexhex2nr(rn); - *g = hexhex2nr(gn); - *b = hexhex2nr(bn); -} - /* * Get the text foreground color, if known. */ void term_get_fg_color(char_u *r, char_u *g, char_u *b) { - term_get_color(get_vim_var_str(VV_TERMRFGRESP), r, g, b); + if (rfg_status.tr_progress != STATUS_GOT) + return; + + *r = fg_r; + *g = fg_g; + *b = fg_b; } /* @@ -6614,7 +6756,12 @@ term_get_fg_color(char_u *r, char_u *g, char_u *b) void term_get_bg_color(char_u *r, char_u *g, char_u *b) { - term_get_color(get_vim_var_str(VV_TERMRBGRESP), r, g, b); + if (rbg_status.tr_progress != STATUS_GOT) + return; + + *r = bg_r; + *g = bg_g; + *b = bg_b; } #endif diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index e02c63d528..0d4aeb0432 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -252,7 +252,6 @@ NEW_TESTS = \ test_plugin_tohtml \ test_plugin_tutor \ test_plugin_zip \ - test_plugin_colorresp \ test_plus_arg_edit \ test_popup \ test_popupwin \ @@ -526,7 +525,6 @@ NEW_TESTS_RES = \ test_plugin_tohtml.res \ test_plugin_tutor.res \ test_plugin_zip.res \ - test_plugin_colorresp.res \ test_plus_arg_edit.res \ test_popup.res \ test_popupwin.res \ diff --git a/src/testdir/test_plugin_colorresp.vim b/src/testdir/test_plugin_colorresp.vim deleted file mode 100644 index 0300ff4847..0000000000 --- a/src/testdir/test_plugin_colorresp.vim +++ /dev/null @@ -1,74 +0,0 @@ -" Test for the colorresp plugin - -CheckNotGui -CheckUnix - -runtime plugin/colorresp.vim - -func Test_colorresp() - set t_RF=x - set t_RB=y - - " response to t_RF, 4 digits - let red = 0x12 - let green = 0x34 - let blue = 0x56 - let seq = printf("\]10;rgb:%02x00/%02x00/%02x00\x07", red, green, blue) - call feedkeys(seq, 'Lx!') - call assert_equal(seq, v:termrfgresp) - " call WaitForAssert({-> assert_equal(seq, v:termrfgresp)}) - - " response to t_RF, 2 digits - let red = 0x78 - let green = 0x9a - let blue = 0xbc - let seq = printf("\]10;rgb:%02x/%02x/%02x\x07", red, green, blue) - call feedkeys(seq, 'Lx!') - call assert_equal(seq, v:termrfgresp) - - " response to t_RB, 4 digits, dark - set background=light - call test_option_not_set('background') - let red = 0x29 - let green = 0x4a - let blue = 0x6b - let seq = printf("\]11;rgb:%02x00/%02x00/%02x00\x07", red, green, blue) - call feedkeys(seq, 'Lx!') - call assert_equal(seq, v:termrbgresp) - call assert_equal('dark', &background) - - " response to t_RB, 4 digits, light - set background=dark - call test_option_not_set('background') - let red = 0x81 - let green = 0x63 - let blue = 0x65 - let seq = printf("\]11;rgb:%02x00/%02x00/%02x00\x07", red, green, blue) - call feedkeys(seq, 'Lx!') - call assert_equal(seq, v:termrbgresp) - call assert_equal('light', &background) - - " response to t_RB, 2 digits, dark - set background=light - call test_option_not_set('background') - let red = 0x47 - let green = 0x59 - let blue = 0x5b - let seq = printf("\]11;rgb:%02x/%02x/%02x\x07", red, green, blue) - call feedkeys(seq, 'Lx!') - call assert_equal(seq, v:termrbgresp) - call assert_equal('dark', &background) - - " response to t_RB, 2 digits, light - set background=dark - call test_option_not_set('background') - let red = 0x83 - let green = 0xa4 - let blue = 0xc2 - let seq = printf("\]11;rgb:%02x/%02x/%02x\x07", red, green, blue) - call feedkeys(seq, 'Lx!') - call assert_equal(seq, v:termrbgresp) - call assert_equal('light', &background) - - set t_RF= t_RB= - endfunc diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim index 6fb612e276..bc31cdafa3 100644 --- a/src/testdir/test_termcodes.vim +++ b/src/testdir/test_termcodes.vim @@ -2790,4 +2790,72 @@ func Test_term_response_osc() call assert_equal("\]15;hello world!\x07", v:termosc) endfunc +" This only checks if the sequence is recognized. +func Test_term_rgb_response() + set t_RF=x + set t_RB=y + + " response to t_RF, 4 digits + let red = 0x12 + let green = 0x34 + let blue = 0x56 + let seq = printf("\]10;rgb:%02x00/%02x00/%02x00\x07", red, green, blue) + call feedkeys(seq, 'Lx!') + call assert_equal(seq, v:termrfgresp) + + " response to t_RF, 2 digits + let red = 0x78 + let green = 0x9a + let blue = 0xbc + let seq = printf("\]10;rgb:%02x/%02x/%02x\x07", red, green, blue) + call feedkeys(seq, 'Lx!') + call assert_equal(seq, v:termrfgresp) + + " response to t_RB, 4 digits, dark + set background=light + eval 'background'->test_option_not_set() + let red = 0x29 + let green = 0x4a + let blue = 0x6b + let seq = printf("\]11;rgb:%02x00/%02x00/%02x00\x07", red, green, blue) + call feedkeys(seq, 'Lx!') + call assert_equal(seq, v:termrbgresp) + call assert_equal('dark', &background) + + " response to t_RB, 4 digits, light + set background=dark + call test_option_not_set('background') + let red = 0x81 + let green = 0x63 + let blue = 0x65 + let seq = printf("\]11;rgb:%02x00/%02x00/%02x00\x07", red, green, blue) + call feedkeys(seq, 'Lx!') + call assert_equal(seq, v:termrbgresp) + call assert_equal('light', &background) + + " response to t_RB, 2 digits, dark + set background=light + call test_option_not_set('background') + let red = 0x47 + let green = 0x59 + let blue = 0x5b + let seq = printf("\]11;rgb:%02x/%02x/%02x\x07", red, green, blue) + call feedkeys(seq, 'Lx!') + call assert_equal(seq, v:termrbgresp) + call assert_equal('dark', &background) + + " response to t_RB, 2 digits, light + set background=dark + call test_option_not_set('background') + let red = 0x83 + let green = 0xa4 + let blue = 0xc2 + let seq = printf("\]11;rgb:%02x/%02x/%02x\x07", red, green, blue) + call feedkeys(seq, 'Lx!') + call assert_equal(seq, v:termrbgresp) + call assert_equal('light', &background) + + set t_RF= t_RB= +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 7782b6a13d..51079ce760 100644 --- a/src/version.c +++ b/src/version.c @@ -724,6 +724,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1757, /**/ 1756, /**/