Skip to content

Commit c531501

Browse files
64-bitmanchrisbra
authored andcommitted
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 <[email protected]> Signed-off-by: Christian Brabandt <[email protected]>
1 parent b217ffb commit c531501

File tree

10 files changed

+67
-13
lines changed

10 files changed

+67
-13
lines changed

runtime/doc/intro.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*intro.txt* For Vim version 9.1. Last change: 2025 Nov 09
1+
*intro.txt* For Vim version 9.1. Last change: 2025 Nov 27
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -450,6 +450,8 @@ notation meaning equivalent decimal value(s) ~
450450
<Del> delete 127
451451
<CSI> command sequence intro ALT-Esc 155 *<CSI>*
452452
<xCSI> CSI when typed in the GUI *<xCSI>*
453+
<OSC> operating system command 157 *<OSC>*
454+
<xOSC> received OSC response *<xOSC>*
453455

454456
<EOL> end-of-line (can be <CR>, <NL> or <CR><NL>,
455457
depends on system and 'fileformat') *<EOL>*

runtime/doc/tags

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3841,6 +3841,7 @@ $quote eval.txt /*$quote*
38413841
<NL> motion.txt /*<NL>*
38423842
<Nop> map.txt /*<Nop>*
38433843
<Nul> intro.txt /*<Nul>*
3844+
<OSC> intro.txt /*<OSC>*
38443845
<PageDown> scroll.txt /*<PageDown>*
38453846
<PageUp> scroll.txt /*<PageUp>*
38463847
<Plug> map.txt /*<Plug>*
@@ -3961,6 +3962,7 @@ $quote eval.txt /*$quote*
39613962
<xHome> term.txt /*<xHome>*
39623963
<xHome>-xterm term.txt /*<xHome>-xterm*
39633964
<xLeft> term.txt /*<xLeft>*
3965+
<xOSC> intro.txt /*<xOSC>*
39643966
<xRight> term.txt /*<xRight>*
39653967
<xUp> term.txt /*<xUp>*
39663968
= change.txt /*=*

src/evalfunc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5150,7 +5150,9 @@ f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
51505150
++ex_normal_busy;
51515151
++in_feedkeys;
51525152
}
5153+
++allow_osc_key;
51535154
exec_normal(TRUE, lowlevel, TRUE);
5155+
--allow_osc_key;
51545156
if (!dangerous)
51555157
{
51565158
--ex_normal_busy;

src/getchar.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1977,6 +1977,9 @@ vgetc(void)
19771977
}
19781978
c = TO_SPECIAL(c2, c);
19791979

1980+
if (allow_osc_key == 0 && c == K_OSC)
1981+
continue;
1982+
19801983
// K_ESC is used to avoid ambiguity with the single Esc
19811984
// character that might be the start of an escape sequence.
19821985
// Convert it back to a single Esc here.
@@ -2452,6 +2455,7 @@ getchar_common(typval_T *argvars, typval_T *rettv, int allow_number)
24522455

24532456
++no_mapping;
24542457
++allow_keys;
2458+
++allow_osc_key;
24552459
if (!simplify)
24562460
++no_reduce_keys;
24572461
for (;;)
@@ -2479,6 +2483,7 @@ getchar_common(typval_T *argvars, typval_T *rettv, int allow_number)
24792483
}
24802484
--no_mapping;
24812485
--allow_keys;
2486+
--allow_osc_key;
24822487
if (!simplify)
24832488
--no_reduce_keys;
24842489

src/globals.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2124,3 +2124,6 @@ INIT(= CLIENTSERVER_METHOD_NONE);
21242124
// Path to socket of last client that communicated with us
21252125
EXTERN char_u *client_socket INIT(= NULL);
21262126
#endif
2127+
2128+
// If the <xOSC> key should be propogated from vgetc()
2129+
EXTERN int allow_osc_key INIT(= 0);

src/keymap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ enum key_extra
280280
, KE_SID = 106 // <SID> special key, followed by {nr};
281281
, KE_ESC = 107 // used for K_ESC
282282
, KE_WILD = 108 // triggers wildmode completion
283+
, KE_OSC = 109 // finished OSC sequence
283284
};
284285

285286
/*
@@ -478,6 +479,7 @@ enum key_extra
478479
#define K_MOUSERIGHT TERMCAP2KEY(KS_EXTRA, KE_MOUSERIGHT)
479480

480481
#define K_CSI TERMCAP2KEY(KS_EXTRA, KE_CSI)
482+
#define K_OSC TERMCAP2KEY(KS_EXTRA, KE_OSC)
481483
#define K_SNR TERMCAP2KEY(KS_EXTRA, KE_SNR)
482484
#define K_PLUG TERMCAP2KEY(KS_EXTRA, KE_PLUG)
483485
#define K_CMDWIN TERMCAP2KEY(KS_EXTRA, KE_CMDWIN)

src/misc2.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,7 @@ static struct key_name_entry
10531053
{TRUE, NL, STRING_INIT("NewLine"), TRUE},
10541054
{TRUE, NL, STRING_INIT("NL"), FALSE},
10551055
{TRUE, K_ZERO, STRING_INIT("Nul"), FALSE},
1056+
{TRUE, OSC, STRING_INIT("OSC"), FALSE},
10561057
{TRUE, K_PAGEDOWN, STRING_INIT("PageDown"), FALSE},
10571058
{TRUE, K_PAGEUP, STRING_INIT("PageUp"), FALSE},
10581059
{TRUE, K_PE, STRING_INIT("PasteEnd"), FALSE},
@@ -1111,6 +1112,7 @@ static struct key_name_entry
11111112
{TRUE, K_XF4, STRING_INIT("xF4"), FALSE},
11121113
{TRUE, K_XHOME, STRING_INIT("xHome"), FALSE},
11131114
{TRUE, K_XLEFT, STRING_INIT("xLeft"), FALSE},
1115+
{TRUE, K_OSC, STRING_INIT("xOSC"), FALSE},
11141116
{TRUE, K_XRIGHT, STRING_INIT("xRight"), FALSE},
11151117
{TRUE, K_XUP, STRING_INIT("xUp"), FALSE},
11161118
{TRUE, K_ZEND, STRING_INIT("zEnd"), FALSE},

src/term.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5921,6 +5921,9 @@ handle_osc(char_u *tp, int len, char_u *key_name, int *slen)
59215921
// The whole OSC response may be larger than the typeahead buffer.
59225922
// To handle this, keep reading data in and out of the typeahead
59235923
// buffer until we read an OSC terminator or timeout.
5924+
5925+
// We can't use the previous buffer since we transferred ownership of it
5926+
// to the vim var.
59245927
ga_init2(&osc_state.buf, 1, 1024);
59255928
#ifdef ELAPSED_FUNC
59265929
ELAPSED_INIT(osc_state.start_tv);
@@ -5933,7 +5936,6 @@ handle_osc(char_u *tp, int len, char_u *key_name, int *slen)
59335936
last_char = ((char_u *)osc_state.buf.ga_data)[osc_state.buf.ga_len - 1];
59345937

59355938
key_name[0] = (int)KS_EXTRA;
5936-
key_name[1] = (int)KE_IGNORE;
59375939

59385940
// Read data and append to buffer. If we reach a terminator, then
59395941
// finally set the vim var.
@@ -5945,6 +5947,8 @@ handle_osc(char_u *tp, int len, char_u *key_name, int *slen)
59455947
{
59465948
osc_state.processing = FALSE;
59475949

5950+
key_name[1] = (int)KE_OSC;
5951+
59485952
ga_concat_len(&osc_state.buf, tp, i + 1 + (tp[i] == ESC));
59495953
ga_append(&osc_state.buf, NUL);
59505954
*slen = i + 1 + (tp[i] == ESC);
@@ -5962,6 +5966,8 @@ handle_osc(char_u *tp, int len, char_u *key_name, int *slen)
59625966
return OK;
59635967
}
59645968

5969+
key_name[1] = (int)KE_IGNORE;
5970+
59655971
#ifdef ELAPSED_FUNC
59665972
if (ELAPSED_FUNC(osc_state.start_tv) >= p_ost)
59675973
{
@@ -6167,9 +6173,15 @@ check_termcode(
61676173
}
61686174

61696175
if (osc_state.processing)
6176+
{
61706177
// Still processing OSC response data, go straight to handler
61716178
// function.
6179+
tp[len] = NUL;
6180+
key_name[0] = NUL;
6181+
key_name[1] = NUL;
6182+
modifiers = 0;
61726183
goto handle_osc;
6184+
}
61736185

61746186
/*
61756187
* Skip this position if the character does not appear as the first
@@ -6690,12 +6702,8 @@ check_termcode(
66906702
*/
66916703
key = handle_x_keys(TERMCAP2KEY(key_name[0], key_name[1]));
66926704

6693-
if (osc_state.processing)
6694-
// We don't want to add anything to the typeahead buffer.
6695-
new_slen = 0;
6696-
else
6697-
// Add any modifier codes to our string.
6698-
new_slen = modifiers2keycode(modifiers, &key, string);
6705+
// Add any modifier codes to our string.
6706+
new_slen = modifiers2keycode(modifiers, &key, string);
66996707

67006708
// Finally, add the special key code to our string
67016709
key_name[0] = KEY2TERMCAP0(key);
@@ -6708,8 +6716,10 @@ check_termcode(
67086716
else
67096717
string[new_slen++] = key_name[1];
67106718
}
6711-
else if (new_slen == 0 && key_name[0] == KS_EXTRA
6712-
&& key_name[1] == KE_IGNORE)
6719+
else if (osc_state.processing ||
6720+
(new_slen == 0
6721+
&& key_name[0] == KS_EXTRA
6722+
&& key_name[1] == KE_IGNORE))
67136723
{
67146724
// Do not put K_IGNORE into the buffer, do return KEYLEN_REMOVED
67156725
// to indicate what happened.

src/testdir/test_termcodes.vim

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2847,14 +2847,38 @@ func Test_term_response_osc()
28472847
" Test if large OSC responses (that must be processed in chunks) are handled
28482848
let data = repeat('a', 3000)
28492849

2850-
call feedkeys("\<Esc>]12;" .. data .. "\x07", 'Lx!')
2851-
call assert_equal("\<Esc>]12;" .. data .. "\x07", v:termosc)
2850+
call feedkeys("\<Esc>]12;" .. data .. "\<Esc>\\", 'Lx!')
2851+
call assert_equal("\<Esc>]12;" .. data .. "\<Esc>\\", v:termosc)
28522852

28532853
" Test small OSC responses
2854-
call feedkeys("\<Esc>]15;hello world!\07", 'Lx!')
2854+
call feedkeys("\<Esc>]15;hello world!\x07", 'Lx!')
28552855
call assert_equal("\<Esc>]15;hello world!\x07", v:termosc)
28562856
endfunc
28572857

2858+
" Test if xOSC key is emitted.
2859+
func Test_term_response_xosc_key()
2860+
CheckRunVimInTerminal
2861+
2862+
let lines =<< trim END
2863+
func Test()
2864+
while getcharstr(-1) != "\<xOSC>"
2865+
endwhile
2866+
call writefile(["done"], 'XTestResult')
2867+
endfunc
2868+
END
2869+
call writefile(lines, 'XTest', 'D')
2870+
defer delete('XTestResult')
2871+
2872+
let buf = RunVimInTerminal("-S XTest", {'rows': 10})
2873+
call TermWait(buf)
2874+
call term_sendkeys(buf, "\<Esc>:call Test()\<CR>")
2875+
call TermWait(buf)
2876+
call term_sendkeys(buf, "\<Esc>]52;hello;\<Esc>\\")
2877+
call TermWait(buf)
2878+
call WaitForAssert({-> assert_equal(["done"], readfile('XTestResult'))})
2879+
call StopVimInTerminal(buf)
2880+
endfunc
2881+
28582882
" This only checks if the sequence is recognized.
28592883
func Test_term_rgb_response()
28602884
set t_RF=x

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,8 @@ static char *(features[]) =
729729

730730
static int included_patches[] =
731731
{ /* Add new patch number below this line */
732+
/**/
733+
1932,
732734
/**/
733735
1931,
734736
/**/

0 commit comments

Comments
 (0)