patch 9.1.1703: Cannot react to terminal OSC responses

Problem:  Cannot react to terminal OSC responses
Solution: Allow TermResponseAll to be triggered by Terminal OSC
          responses (Foxe Chen)

fixes: #14995
closes: #17975

Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Foxe Chen
2025-08-27 21:15:47 +02:00
committed by Christian Brabandt
parent 7f380259cf
commit 1f51bbc3b9
30 changed files with 404 additions and 303 deletions

View File

@ -3793,3 +3793,5 @@ EXTERN char e_socket_server_failed_connecting[]
EXTERN char e_socket_server_unavailable[]
INIT(= N_("E1567: Cannot start socket server, socket path is unavailable"));
#endif
EXTERN char e_osc_response_timed_out[]
INIT(= N_("E1568: OSC command response timed out: %.*s"));

View File

@ -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, VV_RO},
{VV_NAME("termrbgresp", VAR_STRING), NULL, VV_RO},
{VV_NAME("termrfgresp", VAR_STRING), NULL, 0},
{VV_NAME("termrbgresp", VAR_STRING), NULL, 0},
{VV_NAME("termu7resp", VAR_STRING), NULL, VV_RO},
{VV_NAME("termstyleresp", VAR_STRING), NULL, VV_RO},
{VV_NAME("termblinkresp", VAR_STRING), NULL, VV_RO},
@ -166,6 +166,7 @@ static struct vimvar
{VV_NAME("wayland_display", VAR_STRING), NULL, VV_RO},
{VV_NAME("clipmethod", VAR_STRING), NULL, VV_RO},
{VV_NAME("termda1", VAR_STRING), NULL, VV_RO},
{VV_NAME("termosc", VAR_STRING), NULL, VV_RO},
};
// shorthand
@ -2910,6 +2911,17 @@ set_vim_var_string(
vimvars[idx].vv_str = vim_strnsave(val, len);
}
void
set_vim_var_string_direct(
int idx,
char_u *val)
{
clear_tv(&vimvars[idx].vv_di.di_tv);
vimvars[idx].vv_tv_type = VAR_STRING;
vimvars[idx].vv_str = val;
}
/*
* Set List v: variable to "val".
*/

View File

@ -82,7 +82,13 @@ static int KeyNoremap = 0; // remapping flags
// typebuf.tb_buf has three parts: room in front (for result of mappings), the
// middle for typeahead and room for new characters (which needs to be 3 *
// MAXMAPLEN for the Amiga).
#ifdef FEAT_NORMAL
// Add extra space to handle large OSC responses in bigger chunks (improve
// performance)
#define TYPELEN_INIT (5 * (MAXMAPLEN + 3) + 2048)
#else // Tiny version
#define TYPELEN_INIT (5 * (MAXMAPLEN + 3))
#endif
static char_u typebuf_init[TYPELEN_INIT]; // initial typebuf.tb_buf
static char_u noremapbuf_init[TYPELEN_INIT]; // initial typebuf.tb_noremap

View File

@ -883,8 +883,6 @@ 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

View File

@ -3905,6 +3905,21 @@ did_set_numberwidth(optset_T *args UNUSED)
}
#endif
/*
* Process the updated 'osctimeoutlen' option value.
*/
char *
did_set_osctimeoutlen(optset_T *args)
{
if (p_ost < 0)
{
p_ost = args->os_oldval.number;
return e_argument_must_be_positive;
}
return NULL;
}
/*
* Process the updated 'paste' option value. Called after p_paste was set or
* reset. When 'paste' is set or reset also change other options.

View File

@ -828,6 +828,7 @@ EXTERN char_u *p_nf; // 'nrformats'
#if defined(MSWIN)
EXTERN int p_odev; // 'opendevice'
#endif
EXTERN long p_ost; // 'osctimeoutlen'
EXTERN char_u *p_opfunc; // 'operatorfunc'
EXTERN char_u *p_para; // 'paragraphs'
EXTERN int p_paste; // 'paste'

View File

@ -1926,6 +1926,9 @@ static struct vimoption options[] =
{"optimize", "opt", P_BOOL|P_VI_DEF,
(char_u *)NULL, PV_NONE, NULL, NULL,
{(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
{"osctimeoutlen", "ost", P_NUM|P_VI_DEF,
(char_u *)&p_ost, PV_NONE, did_set_osctimeoutlen, NULL,
{(char_u *)1000, (char_u *)0L} SCTX_INIT},
{"osfiletype", "oft", P_STRING|P_ALLOCED|P_VI_DEF,
(char_u *)NULL, PV_NONE, NULL, NULL,
{(char_u *)0L, (char_u *)0L} SCTX_INIT},

9
src/po/vim.pot generated
View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Vim\n"
"Report-Msgid-Bugs-To: vim-dev@vim.org\n"
"POT-Creation-Date: 2025-08-23 16:16+0200\n"
"POT-Creation-Date: 2025-08-27 19:10+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -8832,6 +8832,10 @@ msgstr ""
msgid "E1567: Cannot start socket server, socket path is unavailable"
msgstr ""
#, c-format
msgid "E1568: OSC command response timed out: %.*s"
msgstr ""
#. type of cmdline window or 0
#. result of cmdline window or 0
#. buffer of cmdline window or NULL
@ -9691,6 +9695,9 @@ msgstr ""
msgid "restore the screen contents when exiting Vim"
msgstr ""
msgid "timeout used for terminal OSC responses"
msgstr ""
msgid "using the mouse"
msgstr ""

View File

@ -51,6 +51,7 @@ void set_vcount(long count, long count1, int set_prevcount);
void save_vimvars(vimvars_save_T *vvsave);
void restore_vimvars(vimvars_save_T *vvsave);
void set_vim_var_string(int idx, char_u *val, int len);
void set_vim_var_string_direct(int idx, char_u *val);
void set_vim_var_list(int idx, list_T *val);
void set_vim_var_dict(int idx, dict_T *val);
void set_argv_var(char **argv, int argc);

View File

@ -58,6 +58,7 @@ char *did_set_modified(optset_T *args);
char *did_set_mousehide(optset_T *args);
char *did_set_number_relativenumber(optset_T *args);
char *did_set_numberwidth(optset_T *args);
char *did_set_osctimeoutlen(optset_T *args);
char *did_set_paste(optset_T *args);
char *did_set_previewwindow(optset_T *args);
char *did_set_pyxversion(optset_T *args);

View File

@ -59,7 +59,6 @@ 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);

View File

@ -20,6 +20,9 @@ void f_timer_pause(typval_T *argvars, typval_T *rettv);
void f_timer_start(typval_T *argvars, typval_T *rettv);
void f_timer_stop(typval_T *argvars, typval_T *rettv);
void f_timer_stopall(typval_T *argvars, typval_T *rettv);
#if defined(MSWIN) || defined(__MINGW32__)
int gettimeofday(struct timeval *tv, char *dummy);
#endif
void time_push(void *tv_rel, void *tv_start);
void time_pop(void *tp);
void time_msg(char *mesg, void *tv_start);

View File

@ -1290,6 +1290,19 @@ typedef struct
#endif
} tasave_T;
// Holds state for current OSC response.
typedef struct
{
int processing; // If we are in the middle of an OSC response
char_u start_char; // First char in the OSC response
garray_T buf; // Buffer holding the OSC response, to be
// placed in the "v:termosc" vim var.
struct timeval start; // Set at the beginning of an OSC response.
// Used to timeout after a set amount of
// time.
} oscstate_T;
/*
* Used for conversion of terminal I/O and script files.
*/

View File

@ -116,19 +116,6 @@ 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;
@ -143,10 +130,6 @@ 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,
@ -4192,49 +4175,6 @@ 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
/*
@ -5740,105 +5680,89 @@ handle_csi(
return 0;
}
static oscstate_T osc_state;
/*
* Handle an OSC sequence, fore/background color response from the terminal:
*
* {lead}{code};rgb:{rrrr}/{gggg}/{bbbb}{tail}
* or {lead}{code};rgb:{rr}/{gg}/{bb}{tail}
*
* {code} is 10 for foreground, 11 for background
* {lead} can be <Esc>] or OSC
* {tail} can be '\007', <Esc>\ or STERM.
*
* Consume any code that starts with "{lead}11;", it's also
* possible that "rgba" is following.
* Handles any OSC sequence and places the result in "v:termosc". Note that the
* OSC identifier and terminator character(s) will not be placed in the final
* result. Returns OK on success and FAIL on failure.
*/
static int
handle_osc(char_u *tp, char_u *argp, int len, char_u *key_name, int *slen)
handle_osc(char_u *tp, int len, char_u *key_name, int *slen)
{
int i, j;
struct timeval now;
char_u last_char;
j = 1 + (tp[0] == ESC);
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 (tp[i] == '\007' || (tp[0] == OSC ? tp[i] == STERM
: (tp[i] == ESC && i + 1 < len && tp[i + 1] == '\\')))
{
int is_bg = argp[1] == '1';
int is_4digit = i - j >= 21 && tp[j + 11] == '/'
&& tp[j + 16] == '/';
if (i - j >= 15 && STRNCMP(tp + j + 3, "rgb:", 4) == 0
&& (is_4digit
|| (tp[j + 9] == '/' && tp[j + 12] == '/')))
{
char_u *tp_r = tp + j + 7;
char_u *tp_g = tp + j + (is_4digit ? 12 : 10);
char_u *tp_b = tp + 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
}
// got finished code: consume it
key_name[0] = (int)KS_EXTRA;
key_name[1] = (int)KE_IGNORE;
*slen = i + 1 + (tp[i] == ESC);
#ifdef FEAT_EVAL
set_vim_var_string(is_bg ? VV_TERMRBGRESP
: VV_TERMRFGRESP, tp, *slen);
#endif
apply_autocmds(EVENT_TERMRESPONSEALL,
is_bg ? (char_u *)"background" : (char_u *)"foreground", NULL, FALSE, curbuf);
break;
}
if (i == len)
if (!osc_state.processing)
{
LOG_TR1("not enough characters for RB");
int cur;
LOG_TRN("Received OSC response: %s", (char*)tp);
// Check if it is a valid OSC sequence, and consume it. OSC format
// consists of:
// <idenfitifer><data><terminator>
// <identifier> is either <Esc>] or an OSC character
// <terminator> can be '\007', <Esc>\ or STERM.
cur = 1 + (tp[0] == ESC);
if (len < cur + 1 + (tp[0] != OSC)) // Include terminator as well
return FAIL;
// The whole OSC response may be larger than the typeahead buffer.
// To handle this, keep reading data in and out of the typeahead
// buffer until we read an OSC terminator or timeout.
ga_init2(&osc_state.buf, 1, 1024);
gettimeofday(&osc_state.start, NULL);
osc_state.processing = TRUE;
osc_state.start_char = tp[0];
last_char = 0;
}
else
last_char = ((char_u *)osc_state.buf.ga_data)[osc_state.buf.ga_len - 1];
key_name[0] = (int)KS_EXTRA;
key_name[1] = (int)KE_IGNORE;
// Read data and append to buffer. If we reach a terminator, then
// finally set the vim var.
for (int i = 0; i < len; i++)
if (tp[i] == '\007' || (osc_state.start_char == OSC ? tp[i] == STERM
: ((tp[i] == ESC && i + 1 < len && tp[i + 1] == '\\')
|| (i == 0 && tp[i] == '\\' && last_char == ESC)
)))
{
osc_state.processing = FALSE;
ga_concat_len(&osc_state.buf, tp, i + 1 + (tp[i] == ESC));
ga_append(&osc_state.buf, NUL);
*slen = i + 1 + (tp[i] == ESC);
#ifdef FEAT_EVAL
set_vim_var_string_direct(VV_TERMOSC, osc_state.buf.ga_data);
#endif
apply_autocmds(EVENT_TERMRESPONSEALL, (char_u *)"osc",
NULL, FALSE, curbuf);
return OK;
}
// Check if timeout has been reached
gettimeofday(&now, NULL);
if ((now.tv_sec * 1000000 + now.tv_usec) -
(osc_state.start.tv_sec * 1000000 + osc_state.start.tv_usec)
>= p_ost * 1000)
{
semsg(_(e_osc_response_timed_out), osc_state.buf.ga_len,
osc_state.buf.ga_data);
ga_clear(&osc_state.buf);
osc_state.processing = FALSE;
return FAIL;
}
ga_concat(&osc_state.buf, tp);
*slen = len; // Consume everything
return OK;
}
@ -6028,6 +5952,11 @@ check_termcode(
continue;
}
if (osc_state.processing)
// Still processing OSC response data, go straight to handler
// function.
goto handle_osc;
/*
* Skip this position if the character does not appear as the first
* character in term_strings. This speeds up a lot, since most
@ -6300,13 +6229,11 @@ check_termcode(
}
}
// Check for fore/background color response from the terminal,
// starting} with <Esc>] or OSC
else if ((*T_RBG != NUL || *T_RFG != NUL)
&& ((tp[0] == ESC && len >= 2 && tp[1] == ']')
|| tp[0] == OSC))
// Check for OSC responses from terminal
else if ((tp[0] == ESC && len >= 2 && tp[1] == ']') || tp[0] == OSC)
{
if (handle_osc(tp, argp, len, key_name, &slen) == FAIL)
handle_osc:
if (handle_osc(tp, len, key_name, &slen) == FAIL)
return -1;
}
@ -6549,10 +6476,12 @@ check_termcode(
*/
key = handle_x_keys(TERMCAP2KEY(key_name[0], key_name[1]));
/*
* Add any modifier codes to our string.
*/
new_slen = modifiers2keycode(modifiers, &key, string);
if (osc_state.processing)
// We don't want to add anything to the typeahead buffer.
new_slen = 0;
else
// Add any modifier codes to our string.
new_slen = modifiers2keycode(modifiers, &key, string);
// Finally, add the special key code to our string
key_name[0] = KEY2TERMCAP0(key);
@ -6592,18 +6521,28 @@ check_termcode(
}
#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)
{
if (rfg_status.tr_progress != STATUS_GOT)
return;
*r = fg_r;
*g = fg_g;
*b = fg_b;
term_get_color(get_vim_var_str(VV_TERMRFGRESP), r, g, b);
}
/*
@ -6612,12 +6551,7 @@ 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)
{
if (rbg_status.tr_progress != STATUS_GOT)
return;
*r = bg_r;
*g = bg_g;
*b = bg_b;
term_get_color(get_vim_var_str(VV_TERMRBGRESP), r, g, b);
}
#endif

View File

@ -252,6 +252,7 @@ NEW_TESTS = \
test_plugin_tohtml \
test_plugin_tutor \
test_plugin_zip \
test_plugin_colorresp \
test_plus_arg_edit \
test_popup \
test_popupwin \
@ -525,6 +526,7 @@ 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 \

View File

@ -0,0 +1,74 @@
" 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("\<Esc>]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("\<Esc>]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("\<Esc>]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("\<Esc>]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("\<Esc>]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("\<Esc>]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

View File

@ -1632,74 +1632,6 @@ func Test_mouse_termcodes()
%bw!
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("\<Esc>]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("\<Esc>]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("\<Esc>]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("\<Esc>]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("\<Esc>]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("\<Esc>]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
" This only checks if the sequence is recognized.
" This must be after other tests, because it has side effects to xterm
" properties.
@ -2808,4 +2740,17 @@ func Test_da1_handling()
call assert_equal("\<Esc>[?62,52;c", v:termda1)
endfunc
" Test if OSC terminal responses are captured correctly
func Test_term_response_osc()
" Test if large OSC responses (that must be processed in chunks) are handled
let data = repeat('a', 3000)
call feedkeys("\<Esc>]12;" .. data .. "\x07", 'Lx!')
call assert_equal("\<Esc>]12;" .. data .. "\x07", v:termosc)
" Test small OSC responses
call feedkeys("\<Esc>]15;hello world!\07", 'Lx!')
call assert_equal("\<Esc>]15;hello world!\x07", v:termosc)
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -116,6 +116,7 @@ let test_values = {
\ 'winminwidth': [[0, 1, 10], [-1]],
\ 'winwidth': [[1, 10, 999], [-1, 0]],
\ 'wltimeoutlen': [[1, 10, 999],[-1]],
\ 'osctimeoutlen': [[0, 1, 8, 9999], [-1]],
\
"\ string options
\ 'ambiwidth': [['', 'single', 'double'], ['xxx']],

View File

@ -127,6 +127,20 @@ get_ctime(time_t thetime, int add_newline)
return buf;
}
#if defined(MSWIN) || defined(__MINGW32__)
/*
* Windows doesn't have gettimeofday(), although it does have struct timeval.
*/
int
gettimeofday(struct timeval *tv, char *dummy UNUSED)
{
long t = clock();
tv->tv_sec = t / CLOCKS_PER_SEC;
tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 / CLOCKS_PER_SEC;
return 0;
}
#endif
#if defined(FEAT_EVAL) || defined(PROTO)
#if defined(MACOS_X)
@ -947,20 +961,6 @@ f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
# if defined(STARTUPTIME) || defined(PROTO)
static struct timeval prev_timeval;
# ifdef MSWIN
/*
* Windows doesn't have gettimeofday(), although it does have struct timeval.
*/
static int
gettimeofday(struct timeval *tv, char *dummy UNUSED)
{
long t = clock();
tv->tv_sec = t / CLOCKS_PER_SEC;
tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 / CLOCKS_PER_SEC;
return 0;
}
# endif
/*
* Save the previous time before doing something that could nest.
* set "*tv_rel" to the time elapsed so far.

View File

@ -724,6 +724,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1703,
/**/
1702,
/**/

View File

@ -2240,7 +2240,8 @@ typedef int sock_T;
#define VV_WAYLAND_DISPLAY 112
#define VV_CLIPMETHOD 113
#define VV_TERMDA1 114
#define VV_LEN 115 // number of v: vars
#define VV_TERMOSC 115
#define VV_LEN 116 // number of v: vars
// used for v_number in VAR_BOOL and VAR_SPECIAL
#define VVAL_FALSE 0L // VAR_BOOL