mirror of
https://github.com/vim/vim.git
synced 2025-12-10 18:46:57 -05:00
patch 9.1.1932: OSC terminal response hard to detect
Problem: OSC terminal response hard to detect
Solution: Add the <OSC> and <xOSC> pseudo keys
(Foxe Chen).
related: #18660
closes: #18799
Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
b217ffbef2
commit
c531501748
@ -5150,7 +5150,9 @@ f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
++ex_normal_busy;
|
||||
++in_feedkeys;
|
||||
}
|
||||
++allow_osc_key;
|
||||
exec_normal(TRUE, lowlevel, TRUE);
|
||||
--allow_osc_key;
|
||||
if (!dangerous)
|
||||
{
|
||||
--ex_normal_busy;
|
||||
|
||||
@ -1977,6 +1977,9 @@ vgetc(void)
|
||||
}
|
||||
c = TO_SPECIAL(c2, c);
|
||||
|
||||
if (allow_osc_key == 0 && c == K_OSC)
|
||||
continue;
|
||||
|
||||
// K_ESC is used to avoid ambiguity with the single Esc
|
||||
// character that might be the start of an escape sequence.
|
||||
// Convert it back to a single Esc here.
|
||||
@ -2452,6 +2455,7 @@ getchar_common(typval_T *argvars, typval_T *rettv, int allow_number)
|
||||
|
||||
++no_mapping;
|
||||
++allow_keys;
|
||||
++allow_osc_key;
|
||||
if (!simplify)
|
||||
++no_reduce_keys;
|
||||
for (;;)
|
||||
@ -2479,6 +2483,7 @@ getchar_common(typval_T *argvars, typval_T *rettv, int allow_number)
|
||||
}
|
||||
--no_mapping;
|
||||
--allow_keys;
|
||||
--allow_osc_key;
|
||||
if (!simplify)
|
||||
--no_reduce_keys;
|
||||
|
||||
|
||||
@ -2124,3 +2124,6 @@ INIT(= CLIENTSERVER_METHOD_NONE);
|
||||
// Path to socket of last client that communicated with us
|
||||
EXTERN char_u *client_socket INIT(= NULL);
|
||||
#endif
|
||||
|
||||
// If the <xOSC> key should be propogated from vgetc()
|
||||
EXTERN int allow_osc_key INIT(= 0);
|
||||
|
||||
@ -280,6 +280,7 @@ enum key_extra
|
||||
, KE_SID = 106 // <SID> special key, followed by {nr};
|
||||
, KE_ESC = 107 // used for K_ESC
|
||||
, KE_WILD = 108 // triggers wildmode completion
|
||||
, KE_OSC = 109 // finished OSC sequence
|
||||
};
|
||||
|
||||
/*
|
||||
@ -478,6 +479,7 @@ enum key_extra
|
||||
#define K_MOUSERIGHT TERMCAP2KEY(KS_EXTRA, KE_MOUSERIGHT)
|
||||
|
||||
#define K_CSI TERMCAP2KEY(KS_EXTRA, KE_CSI)
|
||||
#define K_OSC TERMCAP2KEY(KS_EXTRA, KE_OSC)
|
||||
#define K_SNR TERMCAP2KEY(KS_EXTRA, KE_SNR)
|
||||
#define K_PLUG TERMCAP2KEY(KS_EXTRA, KE_PLUG)
|
||||
#define K_CMDWIN TERMCAP2KEY(KS_EXTRA, KE_CMDWIN)
|
||||
|
||||
@ -1053,6 +1053,7 @@ static struct key_name_entry
|
||||
{TRUE, NL, STRING_INIT("NewLine"), TRUE},
|
||||
{TRUE, NL, STRING_INIT("NL"), FALSE},
|
||||
{TRUE, K_ZERO, STRING_INIT("Nul"), FALSE},
|
||||
{TRUE, OSC, STRING_INIT("OSC"), FALSE},
|
||||
{TRUE, K_PAGEDOWN, STRING_INIT("PageDown"), FALSE},
|
||||
{TRUE, K_PAGEUP, STRING_INIT("PageUp"), FALSE},
|
||||
{TRUE, K_PE, STRING_INIT("PasteEnd"), FALSE},
|
||||
@ -1111,6 +1112,7 @@ static struct key_name_entry
|
||||
{TRUE, K_XF4, STRING_INIT("xF4"), FALSE},
|
||||
{TRUE, K_XHOME, STRING_INIT("xHome"), FALSE},
|
||||
{TRUE, K_XLEFT, STRING_INIT("xLeft"), FALSE},
|
||||
{TRUE, K_OSC, STRING_INIT("xOSC"), FALSE},
|
||||
{TRUE, K_XRIGHT, STRING_INIT("xRight"), FALSE},
|
||||
{TRUE, K_XUP, STRING_INIT("xUp"), FALSE},
|
||||
{TRUE, K_ZEND, STRING_INIT("zEnd"), FALSE},
|
||||
|
||||
28
src/term.c
28
src/term.c
@ -5921,6 +5921,9 @@ handle_osc(char_u *tp, int len, char_u *key_name, int *slen)
|
||||
// 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.
|
||||
|
||||
// We can't use the previous buffer since we transferred ownership of it
|
||||
// to the vim var.
|
||||
ga_init2(&osc_state.buf, 1, 1024);
|
||||
#ifdef ELAPSED_FUNC
|
||||
ELAPSED_INIT(osc_state.start_tv);
|
||||
@ -5933,7 +5936,6 @@ handle_osc(char_u *tp, int len, char_u *key_name, int *slen)
|
||||
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.
|
||||
@ -5945,6 +5947,8 @@ handle_osc(char_u *tp, int len, char_u *key_name, int *slen)
|
||||
{
|
||||
osc_state.processing = FALSE;
|
||||
|
||||
key_name[1] = (int)KE_OSC;
|
||||
|
||||
ga_concat_len(&osc_state.buf, tp, i + 1 + (tp[i] == ESC));
|
||||
ga_append(&osc_state.buf, NUL);
|
||||
*slen = i + 1 + (tp[i] == ESC);
|
||||
@ -5962,6 +5966,8 @@ handle_osc(char_u *tp, int len, char_u *key_name, int *slen)
|
||||
return OK;
|
||||
}
|
||||
|
||||
key_name[1] = (int)KE_IGNORE;
|
||||
|
||||
#ifdef ELAPSED_FUNC
|
||||
if (ELAPSED_FUNC(osc_state.start_tv) >= p_ost)
|
||||
{
|
||||
@ -6167,9 +6173,15 @@ check_termcode(
|
||||
}
|
||||
|
||||
if (osc_state.processing)
|
||||
{
|
||||
// Still processing OSC response data, go straight to handler
|
||||
// function.
|
||||
tp[len] = NUL;
|
||||
key_name[0] = NUL;
|
||||
key_name[1] = NUL;
|
||||
modifiers = 0;
|
||||
goto handle_osc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip this position if the character does not appear as the first
|
||||
@ -6690,12 +6702,8 @@ handle_osc:
|
||||
*/
|
||||
key = handle_x_keys(TERMCAP2KEY(key_name[0], key_name[1]));
|
||||
|
||||
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);
|
||||
// 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);
|
||||
@ -6708,8 +6716,10 @@ handle_osc:
|
||||
else
|
||||
string[new_slen++] = key_name[1];
|
||||
}
|
||||
else if (new_slen == 0 && key_name[0] == KS_EXTRA
|
||||
&& key_name[1] == KE_IGNORE)
|
||||
else if (osc_state.processing ||
|
||||
(new_slen == 0
|
||||
&& key_name[0] == KS_EXTRA
|
||||
&& key_name[1] == KE_IGNORE))
|
||||
{
|
||||
// Do not put K_IGNORE into the buffer, do return KEYLEN_REMOVED
|
||||
// to indicate what happened.
|
||||
|
||||
@ -2847,14 +2847,38 @@ 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)
|
||||
call feedkeys("\<Esc>]12;" .. data .. "\<Esc>\\", 'Lx!')
|
||||
call assert_equal("\<Esc>]12;" .. data .. "\<Esc>\\", v:termosc)
|
||||
|
||||
" Test small OSC responses
|
||||
call feedkeys("\<Esc>]15;hello world!\07", 'Lx!')
|
||||
call feedkeys("\<Esc>]15;hello world!\x07", 'Lx!')
|
||||
call assert_equal("\<Esc>]15;hello world!\x07", v:termosc)
|
||||
endfunc
|
||||
|
||||
" Test if xOSC key is emitted.
|
||||
func Test_term_response_xosc_key()
|
||||
CheckRunVimInTerminal
|
||||
|
||||
let lines =<< trim END
|
||||
func Test()
|
||||
while getcharstr(-1) != "\<xOSC>"
|
||||
endwhile
|
||||
call writefile(["done"], 'XTestResult')
|
||||
endfunc
|
||||
END
|
||||
call writefile(lines, 'XTest', 'D')
|
||||
defer delete('XTestResult')
|
||||
|
||||
let buf = RunVimInTerminal("-S XTest", {'rows': 10})
|
||||
call TermWait(buf)
|
||||
call term_sendkeys(buf, "\<Esc>:call Test()\<CR>")
|
||||
call TermWait(buf)
|
||||
call term_sendkeys(buf, "\<Esc>]52;hello;\<Esc>\\")
|
||||
call TermWait(buf)
|
||||
call WaitForAssert({-> assert_equal(["done"], readfile('XTestResult'))})
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
" This only checks if the sequence is recognized.
|
||||
func Test_term_rgb_response()
|
||||
set t_RF=x
|
||||
|
||||
@ -729,6 +729,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1932,
|
||||
/**/
|
||||
1931,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user