Skip to content

Commit db65c42

Browse files
committed
What if the connection wrote its output as a utf-8 array?
1 parent 224ac9d commit db65c42

File tree

12 files changed

+87
-62
lines changed

12 files changed

+87
-62
lines changed

src/cascadia/TerminalApp/DebugTapConnection.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,25 +120,27 @@ namespace winrt::Microsoft::TerminalApp::implementation
120120
return ConnectionState::Failed;
121121
}
122122

123-
void DebugTapConnection::_OutputHandler(const std::wstring_view str)
123+
void DebugTapConnection::_OutputHandler(const std::string_view str)
124124
{
125-
auto output = til::visualize_control_codes(str);
125+
(void)str;
126+
//auto output = til::visualize_control_codes(str);
126127
// To make the output easier to read, we introduce a line break whenever
127128
// an LF control is encountered. But at this point, the LF would have
128129
// been converted to U+240A (␊), so that's what we need to search for.
129-
for (size_t lfPos = 0; (lfPos = output.find(L'\u240A', lfPos)) != std::wstring::npos;)
130-
{
131-
output.insert(++lfPos, L"\r\n");
132-
}
133-
TerminalOutput.raise(output);
130+
//for (size_t lfPos = 0; (lfPos = output.find(L'\x0A', lfPos)) != std::wstring::npos;)
131+
//{
132+
//output.insert(++lfPos, L"\r\n");
133+
//}
134+
//TerminalOutput.raise(output);
134135
}
135136

136137
// Called by the DebugInputTapConnection to print user input
137138
void DebugTapConnection::_PrintInput(const std::wstring_view str)
138139
{
139140
auto clean{ til::visualize_control_codes(str) };
140141
auto formatted{ wil::str_printf<std::wstring>(L"\x1b[91m%ls\x1b[m", clean.data()) };
141-
TerminalOutput.raise(formatted);
142+
(void)formatted;
143+
//TerminalOutput.raise(formatted);
142144
}
143145

144146
// Wire us up so that we can forward input through

src/cascadia/TerminalApp/DebugTapConnection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ namespace winrt::Microsoft::TerminalApp::implementation
3131

3232
private:
3333
void _PrintInput(const std::wstring_view data);
34-
void _OutputHandler(const std::wstring_view str);
34+
void _OutputHandler(const std::string_view str);
3535

3636
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection::TerminalOutput_revoker _outputRevoker;
3737
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection::StateChanged_revoker _stateChangedRevoker;

src/cascadia/TerminalConnection/AzureConnection.cpp

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
9696
// - str: the string to write.
9797
void AzureConnection::_WriteStringWithNewline(const std::wstring_view str)
9898
{
99-
TerminalOutput.raise(str + L"\r\n");
99+
_dhSend16(str + L"\r\n");
100100
}
101101

102102
// Method description:
@@ -112,7 +112,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
112112
catch (const std::exception& runtimeException)
113113
{
114114
// This also catches the AzureException, which has a .what()
115-
TerminalOutput.raise(_colorize(91, til::u8u16(std::string{ runtimeException.what() })));
115+
_dhSend16(_colorize(91, til::u8u16(std::string{ runtimeException.what() })));
116116
}
117117
catch (...)
118118
{
@@ -162,13 +162,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
162162

163163
_currentInputMode = mode;
164164

165-
TerminalOutput.raise(L"> \x1b[92m"); // Make prompted user input green
165+
_dhSend16(L"> \x1b[92m"); // Make prompted user input green
166166

167167
_inputEvent.wait(inputLock, [this, mode]() {
168168
return _currentInputMode != mode || _isStateAtOrBeyond(ConnectionState::Closing);
169169
});
170170

171-
TerminalOutput.raise(L"\x1b[m");
171+
_dhSend16(L"\x1b[m");
172172

173173
if (_isStateAtOrBeyond(ConnectionState::Closing))
174174
{
@@ -211,19 +211,19 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
211211
if (_userInput.size() > 0)
212212
{
213213
_userInput.pop_back();
214-
TerminalOutput.raise(L"\x08 \x08"); // overstrike the character with a space
214+
_dhSend16(L"\x08 \x08"); // overstrike the character with a space
215215
}
216216
}
217217
else
218218
{
219-
TerminalOutput.raise(data); // echo back
219+
_dhSend16(data); // echo back
220220

221221
switch (_currentInputMode)
222222
{
223223
case InputMode::Line:
224224
if (data.size() > 0 && gsl::at(data, 0) == UNICODE_CARRIAGERETURN)
225225
{
226-
TerminalOutput.raise(L"\r\n"); // we probably got a \r, so we need to advance to the next line.
226+
_dhSend16(L"\r\n"); // we probably got a \r, so we need to advance to the next line.
227227
_currentInputMode = InputMode::None; // toggling the mode indicates completion
228228
_inputEvent.notify_one();
229229
break;
@@ -415,21 +415,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
415415
case WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE:
416416
case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE:
417417
{
418-
const auto result{ til::u8u16(std::string_view{ _buffer.data(), read }, _u16Str, _u8State) };
419-
if (FAILED(result))
420-
{
421-
// EXIT POINT
422-
_transitionToState(ConnectionState::Failed);
423-
return gsl::narrow<DWORD>(result);
424-
}
425-
426-
if (_u16Str.empty())
418+
if (read == 0)
427419
{
428420
continue;
429421
}
430422

431423
// Pass the output to our registered event handlers
432-
TerminalOutput.raise(_u16Str);
424+
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(_buffer.data()), read });
433425
break;
434426
}
435427
case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE:
@@ -772,7 +764,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
772764
const auto shellType = _ParsePreferredShellType(settingsResponse);
773765
_WriteStringWithNewline(RS_(L"AzureRequestingTerminal"));
774766
const auto socketUri = _GetTerminal(shellType);
775-
TerminalOutput.raise(L"\r\n");
767+
_dhSend16(L"\r\n");
776768

777769
//// Step 8: connecting to said terminal
778770
{

src/cascadia/TerminalConnection/AzureConnection.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
103103
std::array<char, 4096> _buffer{};
104104

105105
static winrt::hstring _ParsePreferredShellType(const winrt::Windows::Data::Json::JsonObject& settingsResponse);
106+
107+
template<typename B>
108+
void _dhSend16(B&& b)
109+
{
110+
auto eight = til::u16u8(b);
111+
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(eight.c_str()), static_cast<uint32_t>(eight.size()) });
112+
}
106113
};
107114
}
108115

src/cascadia/TerminalConnection/ConptyConnection.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -478,28 +478,28 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
478478

479479
// GH#11556 - make sure to format the error code to this string as an UNSIGNED int
480480
const auto failureText = RS_fmt(L"ProcessFailedToLaunch", _formatStatus(hr), _commandline);
481-
TerminalOutput.raise(failureText);
481+
_dhSend16(failureText);
482482

483483
// If the path was invalid, let's present an informative message to the user
484484
if (hr == HRESULT_FROM_WIN32(ERROR_DIRECTORY))
485485
{
486486
const auto badPathText = RS_fmt(L"BadPathText", _startingDirectory);
487-
TerminalOutput.raise(L"\r\n");
488-
TerminalOutput.raise(badPathText);
487+
_dhSend16(L"\r\n");
488+
_dhSend16(badPathText);
489489
}
490490
// If the requested action requires elevation, display appropriate message
491491
else if (hr == HRESULT_FROM_WIN32(ERROR_ELEVATION_REQUIRED))
492492
{
493493
const auto elevationText = RS_(L"ElevationRequired");
494-
TerminalOutput.raise(L"\r\n");
495-
TerminalOutput.raise(elevationText);
494+
_dhSend16(L"\r\n");
495+
_dhSend16(elevationText);
496496
}
497497
// If the requested executable was not found, display appropriate message
498498
else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
499499
{
500500
const auto fileNotFoundText = RS_(L"FileNotFound");
501-
TerminalOutput.raise(L"\r\n");
502-
TerminalOutput.raise(fileNotFoundText);
501+
_dhSend16(L"\r\n");
502+
_dhSend16(fileNotFoundText);
503503
}
504504

505505
_transitionToState(ConnectionState::Failed);
@@ -520,7 +520,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
520520
const auto msg1 = RS_fmt(L"ProcessExited", _formatStatus(status));
521521
const auto msg2 = RS_(L"CtrlDToClose");
522522
const auto msg = fmt::format(FMT_COMPILE(L"\r\n{}\r\n{}\r\n"), msg1, msg2);
523-
TerminalOutput.raise(msg);
523+
_dhSend16(msg);
524524
}
525525
CATCH_LOG();
526526
}
@@ -745,11 +745,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
745745
const wil::unique_event overlappedEvent{ CreateEventExW(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS) };
746746
OVERLAPPED overlapped{ .hEvent = overlappedEvent.get() };
747747
bool overlappedPending = false;
748-
char buffer[128 * 1024];
749-
DWORD read = 0;
750748

751-
til::u8state u8State;
752-
std::wstring wstr;
749+
char buffer[128 * 1024], buffer2[128*1024];
750+
char* thisBuffer = buffer;
751+
DWORD read = 0;
752+
char* lastBuffer = buffer2;
753+
DWORD lastRead = 0;
753754

754755
// If we use overlapped IO We want to queue ReadFile() calls before processing the
755756
// string, because TerminalOutput.raise() may take a while (relatively speaking).
@@ -760,7 +761,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
760761
// When we have a `wstr` that's ready for processing we must do so without blocking.
761762
// Otherwise, whatever the user typed will be delayed until the next IO operation.
762763
// With overlapped IO that's not a problem because the ReadFile() calls won't block.
763-
if (!ReadFile(_pipe.get(), &buffer[0], sizeof(buffer), &read, &overlapped))
764+
if (!ReadFile(_pipe.get(), thisBuffer, sizeof(buffer), &read, &overlapped))
764765
{
765766
if (GetLastError() != ERROR_IO_PENDING)
766767
{
@@ -772,7 +773,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
772773
// wstr can be empty in two situations:
773774
// * The previous call to til::u8u16 failed.
774775
// * We're using overlapped IO, and it's the first iteration.
775-
if (!wstr.empty())
776+
if (lastBuffer && lastRead)
776777
{
777778
if (!_receivedFirstByte)
778779
{
@@ -792,7 +793,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
792793

793794
try
794795
{
795-
TerminalOutput.raise(wstr);
796+
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(lastBuffer), lastRead });
796797
}
797798
CATCH_LOG();
798799
}
@@ -832,8 +833,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
832833
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
833834
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
834835

835-
// If we hit a parsing error, eat it. It's bad utf-8, we can't do anything with it.
836-
FAILED_LOG(til::u8u16({ &buffer[0], gsl::narrow_cast<size_t>(read) }, wstr, u8State));
836+
std::swap(thisBuffer, lastBuffer);
837837
}
838838

839839
return 0;

src/cascadia/TerminalConnection/ConptyConnection.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
103103
} _startupInfo{};
104104

105105
DWORD _OutputThread();
106+
template<typename B>
107+
void _dhSend16(B&& b)
108+
{
109+
auto eight = til::u16u8(b);
110+
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(eight.c_str()), static_cast<uint32_t>(eight.size()) });
111+
}
106112
};
107113
}
108114

src/cascadia/TerminalConnection/EchoConnection.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
3434
prettyPrint << wch;
3535
}
3636
}
37-
TerminalOutput.raise(prettyPrint.str());
37+
(void)prettyPrint;
38+
//TerminalOutput.raise(prettyPrint.str());
3839
}
3940

4041
void EchoConnection::Resize(uint32_t /*rows*/, uint32_t /*columns*/) noexcept

src/cascadia/TerminalConnection/ITerminalConnection.idl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace Microsoft.Terminal.TerminalConnection
1313
Failed
1414
};
1515

16-
delegate void TerminalOutputHandler(String output);
16+
delegate void TerminalOutputHandler(UInt8[] output);
1717

1818
interface ITerminalConnection
1919
{

src/cascadia/TerminalControl/ControlCore.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2221,13 +2221,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
22212221
auto noticeArgs = winrt::make<NoticeEventArgs>(NoticeLevel::Info, RS_(L"TermControlReadOnly"));
22222222
RaiseNotice.raise(*this, std::move(noticeArgs));
22232223
}
2224-
void ControlCore::_connectionOutputHandler(const hstring& hstr)
2224+
void ControlCore::_connectionOutputHandler(const winrt::array_view<const uint8_t>& data)
22252225
{
22262226
try
22272227
{
2228+
std::wstring u16out;
2229+
(void)til::u8u16(std::string_view{reinterpret_cast<const char*>(data.data()), data.size()}, u16out, _u8State);
2230+
22282231
{
22292232
const auto lock = _terminal->LockForWriting();
2230-
_terminal->Write(hstr);
2233+
_terminal->Write(u16out);
22312234
}
22322235

22332236
if (!_pendingResponses.empty())

src/cascadia/TerminalControl/ControlCore.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
348348

349349
void _raiseReadOnlyWarning();
350350
void _updateAntiAliasingMode();
351-
void _connectionOutputHandler(const hstring& hstr);
351+
void _connectionOutputHandler(const winrt::array_view<const uint8_t>& data);
352352
void _connectionStateChangedHandler(const TerminalConnection::ITerminalConnection&, const Windows::Foundation::IInspectable&);
353353
void _updateHoveredCell(const std::optional<til::point> terminalPosition);
354354
void _setOpacity(const float opacity, const bool focused = true);
@@ -457,6 +457,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
457457
TerminalConnection::ITerminalConnection::StateChanged_revoker _connectionStateChangedRevoker;
458458
TerminalConnection::ITerminalConnection _connection{ nullptr };
459459

460+
til::u8state _u8State;
461+
460462
friend class ControlUnitTests::ControlCoreTests;
461463
friend class ControlUnitTests::ControlInteractivityTests;
462464
bool _inUnitTests{ false };

0 commit comments

Comments
 (0)