Skip to content

Commit b07589e

Browse files
authored
Improve reliability of VT responses (#17786)
* Repurposes `_sendInputToConnection` to send output to the connection no matter whether the terminal is read-only or not. Now `SendInput` is the function responsible for the UI handling. * Buffers responses in a VT string into a single string before sending it as a response all at once. This reduces the chances for the UI thread to insert cursor positions and similar into the input pipe, because we're not constantly unlocking the terminal lock anymore for every response. The only way now that unrelated inputs are inserted into the input pipe is because the VT requests (e.g. DA1, DSR, etc.) are broken up across >1 reads. This also fixes VT responses in read-only panes. Closes #17775 ## Validation Steps Performed * Repeatedly run `echo ^[[c` in cmd. DA1 responses don't stack & always stay the same ✅ * Run nvim in WSL. Doesn't deadlock when pasting 1MB. ✅ * Run the repro from #17775, which requests a ton of OSC 4 (color palette) responses. Jiggle the cursor on top of the window. Responses never get split up. ✅
1 parent 7d790c7 commit b07589e

File tree

3 files changed

+26
-22
lines changed

3 files changed

+26
-22
lines changed

src/cascadia/TerminalControl/ControlCore.cpp

+25-21
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
9898
Connection(connection);
9999

100100
_terminal->SetWriteInputCallback([this](std::wstring_view wstr) {
101-
_sendInputToConnection(wstr);
101+
_pendingResponses.append(wstr);
102102
});
103103

104104
// GH#8969: pre-seed working directory to prevent potential races
@@ -419,6 +419,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
419419
// Return Value:
420420
// - <none>
421421
void ControlCore::_sendInputToConnection(std::wstring_view wstr)
422+
{
423+
_connection.WriteInput(winrt_wstring_to_array_view(wstr));
424+
}
425+
426+
// Method Description:
427+
// - Writes the given sequence as input to the active terminal connection,
428+
// Arguments:
429+
// - wstr: the string of characters to write to the terminal connection.
430+
// Return Value:
431+
// - <none>
432+
void ControlCore::SendInput(const std::wstring_view wstr)
422433
{
423434
if (wstr.empty())
424435
{
@@ -435,21 +446,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
435446
}
436447
else
437448
{
438-
_connection.WriteInput(winrt_wstring_to_array_view(wstr));
449+
_sendInputToConnection(wstr);
439450
}
440451
}
441452

442-
// Method Description:
443-
// - Writes the given sequence as input to the active terminal connection,
444-
// Arguments:
445-
// - wstr: the string of characters to write to the terminal connection.
446-
// Return Value:
447-
// - <none>
448-
void ControlCore::SendInput(const std::wstring_view wstr)
449-
{
450-
_sendInputToConnection(wstr);
451-
}
452-
453453
bool ControlCore::SendCharEvent(const wchar_t ch,
454454
const WORD scanCode,
455455
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers)
@@ -485,7 +485,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
485485
}
486486
if (out)
487487
{
488-
_sendInputToConnection(*out);
488+
SendInput(*out);
489489
return true;
490490
}
491491
return false;
@@ -643,7 +643,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
643643
}
644644
if (out)
645645
{
646-
_sendInputToConnection(*out);
646+
SendInput(*out);
647647
return true;
648648
}
649649
return false;
@@ -662,7 +662,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
662662
}
663663
if (out)
664664
{
665-
_sendInputToConnection(*out);
665+
SendInput(*out);
666666
return true;
667667
}
668668
return false;
@@ -1412,7 +1412,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
14121412
}
14131413

14141414
// It's important to not hold the terminal lock while calling this function as sending the data may take a long time.
1415-
_sendInputToConnection(filtered);
1415+
SendInput(filtered);
14161416

14171417
const auto lock = _terminal->LockForWriting();
14181418
_terminal->ClearSelection();
@@ -2107,7 +2107,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
21072107
// Sending input requires that we're unlocked, because
21082108
// writing the input pipe may block indefinitely.
21092109
const auto suspension = _terminal->SuspendLock();
2110-
_sendInputToConnection(buffer);
2110+
SendInput(buffer);
21112111
}
21122112
}
21132113
}
@@ -2164,6 +2164,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
21642164
_terminal->Write(hstr);
21652165
}
21662166

2167+
if (!_pendingResponses.empty())
2168+
{
2169+
_sendInputToConnection(_pendingResponses);
2170+
_pendingResponses.clear();
2171+
}
2172+
21672173
// Start the throttled update of where our hyperlinks are.
21682174
const auto shared = _shared.lock_shared();
21692175
if (shared->outputIdle)
@@ -2480,9 +2486,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
24802486
}
24812487
if (out && !out->empty())
24822488
{
2483-
// _sendInputToConnection() asserts that we aren't in focus mode,
2484-
// but window focus events are always fine to send.
2485-
_connection.WriteInput(winrt_wstring_to_array_view(*out));
2489+
_sendInputToConnection(*out);
24862490
}
24872491
}
24882492

src/cascadia/TerminalControl/ControlCore.h

+1
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
319319
winrt::com_ptr<ControlSettings> _settings{ nullptr };
320320

321321
std::shared_ptr<::Microsoft::Terminal::Core::Terminal> _terminal{ nullptr };
322+
std::wstring _pendingResponses;
322323

323324
// NOTE: _renderEngine must be ordered before _renderer.
324325
//

src/cascadia/TerminalCore/TerminalApi.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ void Terminal::ReturnResponse(const std::wstring_view response)
2424
{
2525
if (_pfnWriteInput && !response.empty())
2626
{
27-
const auto suspension = _readWriteLock.suspend();
2827
_pfnWriteInput(response);
2928
}
3029
}

0 commit comments

Comments
 (0)