From: Foxe Chen Date: Thu, 27 Nov 2025 20:53:36 +0000 (+0000) Subject: patch 9.1.1932: OSC terminal response hard to detect X-Git-Tag: v9.1.1932^0 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c53150174859c34e96a65c7435743614890cd335;p=thirdparty%2Fvim.git patch 9.1.1932: OSC terminal response hard to detect Problem: OSC terminal response hard to detect Solution: Add the and pseudo keys (Foxe Chen). related: #18660 closes: #18799 Signed-off-by: Foxe Chen Signed-off-by: Christian Brabandt --- diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt index a25c313428..c09e8e744d 100644 --- a/runtime/doc/intro.txt +++ b/runtime/doc/intro.txt @@ -1,4 +1,4 @@ -*intro.txt* For Vim version 9.1. Last change: 2025 Nov 09 +*intro.txt* For Vim version 9.1. Last change: 2025 Nov 27 VIM REFERENCE MANUAL by Bram Moolenaar @@ -450,6 +450,8 @@ notation meaning equivalent decimal value(s) ~ delete 127 command sequence intro ALT-Esc 155 ** CSI when typed in the GUI ** + operating system command 157 ** + received OSC response ** end-of-line (can be , or , depends on system and 'fileformat') ** diff --git a/runtime/doc/tags b/runtime/doc/tags index 64b548a866..0e7000d283 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -3841,6 +3841,7 @@ $quote eval.txt /*$quote* motion.txt /** map.txt /** intro.txt /** + intro.txt /** scroll.txt /** scroll.txt /** map.txt /** @@ -3961,6 +3962,7 @@ $quote eval.txt /*$quote* term.txt /** -xterm term.txt /*-xterm* term.txt /** + intro.txt /** term.txt /** term.txt /** = change.txt /*=* diff --git a/src/evalfunc.c b/src/evalfunc.c index e770321eaf..eca95bbcfd 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -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; diff --git a/src/getchar.c b/src/getchar.c index 3219fd2cef..a7b9741bd3 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -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; diff --git a/src/globals.h b/src/globals.h index 7e72ea744e..f412ab5fc2 100644 --- a/src/globals.h +++ b/src/globals.h @@ -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 key should be propogated from vgetc() +EXTERN int allow_osc_key INIT(= 0); diff --git a/src/keymap.h b/src/keymap.h index e993e0999a..b3be60c48d 100644 --- a/src/keymap.h +++ b/src/keymap.h @@ -280,6 +280,7 @@ enum key_extra , KE_SID = 106 // 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) diff --git a/src/misc2.c b/src/misc2.c index 8380e745c9..fcbf0dd1cd 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -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}, diff --git a/src/term.c b/src/term.c index c317ca6012..d3939ef4d7 100644 --- a/src/term.c +++ b/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. diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim index ffe3576ff0..5c30f5a8d1 100644 --- a/src/testdir/test_termcodes.vim +++ b/src/testdir/test_termcodes.vim @@ -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("\]12;" .. data .. "\x07", 'Lx!') - call assert_equal("\]12;" .. data .. "\x07", v:termosc) + call feedkeys("\]12;" .. data .. "\\\", 'Lx!') + call assert_equal("\]12;" .. data .. "\\\", v:termosc) " Test small OSC responses - call feedkeys("\]15;hello world!\07", 'Lx!') + call feedkeys("\]15;hello world!\x07", 'Lx!') call assert_equal("\]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) != "\" + 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, "\:call Test()\") + call TermWait(buf) + call term_sendkeys(buf, "\]52;hello;\\\") + 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 diff --git a/src/version.c b/src/version.c index 75095d126d..38609746c2 100644 --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1932, /**/ 1931, /**/