mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-06 22:29:43 +00:00
Compare commits
11 Commits
dev/lhecke
...
dev/duhowe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd2a396b5e | ||
|
|
9c46e34a3f | ||
|
|
b2d54c146a | ||
|
|
4fdb3fafb2 | ||
|
|
5bfbbbd7a2 | ||
|
|
7bb324d047 | ||
|
|
3d5342d60d | ||
|
|
48603ac834 | ||
|
|
faa5f8b08b | ||
|
|
3f48fe6760 | ||
|
|
db65c42f2c |
@@ -39,9 +39,9 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
|
||||
_wrappedConnection.Start();
|
||||
}
|
||||
void WriteInput(const winrt::array_view<const char16_t> buffer)
|
||||
void WriteInput(const winrt::array_view<const uint8_t> buffer)
|
||||
{
|
||||
_pairedTap->_PrintInput(winrt_array_to_wstring_view(buffer));
|
||||
_pairedTap->_PrintInput(winrt_array_to_string_view(buffer));
|
||||
_wrappedConnection.WriteInput(buffer);
|
||||
}
|
||||
void Resize(uint32_t rows, uint32_t columns) { _wrappedConnection.Resize(rows, columns); }
|
||||
@@ -80,7 +80,7 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
_start.count_down();
|
||||
}
|
||||
|
||||
void DebugTapConnection::WriteInput(const winrt::array_view<const char16_t> buffer)
|
||||
void DebugTapConnection::WriteInput(const winrt::array_view<const uint8_t> buffer)
|
||||
{
|
||||
// If the user types into the tap side, forward it to the input side
|
||||
if (auto strongInput{ _inputSide.get() })
|
||||
@@ -120,25 +120,44 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
return ConnectionState::Failed;
|
||||
}
|
||||
|
||||
void DebugTapConnection::_OutputHandler(const winrt::array_view<const char16_t> str)
|
||||
void DebugTapConnection::_OutputHandler(const winrt::array_view<const uint8_t>& str)
|
||||
{
|
||||
auto output = til::visualize_control_codes(winrt_array_to_wstring_view(str));
|
||||
// To make the output easier to read, we introduce a line break whenever
|
||||
// an LF control is encountered. But at this point, the LF would have
|
||||
// been converted to U+240A (␊), so that's what we need to search for.
|
||||
for (size_t lfPos = 0; (lfPos = output.find(L'\u240A', lfPos)) != std::wstring::npos;)
|
||||
uint8_t buffer[5] = { 0xe2, 0x90, 0x00, '\r', '\n' };
|
||||
uint32_t i = 0, s = 0;
|
||||
while (i < str.size())
|
||||
{
|
||||
output.insert(++lfPos, L"\r\n");
|
||||
while (i < str.size() && str[i] > 0x20 && str[i] != 0x7f)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
if (i > s)
|
||||
{
|
||||
TerminalOutput.raise(winrt::array_view{ str.data() + s, (i - s) });
|
||||
s = i;
|
||||
}
|
||||
if (i >= str.size())
|
||||
break;
|
||||
auto ch = str[i];
|
||||
if (ch == '\x20')
|
||||
buffer[2] = 0xA3;
|
||||
else if (ch == '\x7f')
|
||||
buffer[2] = 0xA1;
|
||||
else
|
||||
buffer[2] = 0x80 | ch;
|
||||
// If we encountered a LF, emit the extra \r\n from the buffer to pretty print it.
|
||||
TerminalOutput.raise(winrt::array_view{ buffer, ch == '\x0a' ? 5u : 3u });
|
||||
++i;
|
||||
++s;
|
||||
}
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(output));
|
||||
}
|
||||
|
||||
// Called by the DebugInputTapConnection to print user input
|
||||
void DebugTapConnection::_PrintInput(const std::wstring_view str)
|
||||
void DebugTapConnection::_PrintInput(const std::string_view str)
|
||||
{
|
||||
auto clean{ til::visualize_control_codes(str) };
|
||||
auto formatted{ wil::str_printf<std::wstring>(L"\x1b[91m%ls\x1b[m", clean.data()) };
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(formatted));
|
||||
static constexpr std::string_view buffer{ "\x1b[91m\x1b[m" }; // two escape sequences we need to write, back to back
|
||||
TerminalOutput.raise(winrt_u8string_to_array_view(buffer.substr(0,5)));
|
||||
_OutputHandler(winrt_u8string_to_array_view(str));
|
||||
TerminalOutput.raise(winrt_u8string_to_array_view(buffer.substr(5)));
|
||||
}
|
||||
|
||||
// Wire us up so that we can forward input through
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
void Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/){};
|
||||
~DebugTapConnection();
|
||||
void Start();
|
||||
void WriteInput(const winrt::array_view<const char16_t> data);
|
||||
void WriteInput(const winrt::array_view<const uint8_t> data);
|
||||
void Resize(uint32_t rows, uint32_t columns);
|
||||
void Close();
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
til::typed_event<winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection, winrt::Windows::Foundation::IInspectable> StateChanged;
|
||||
|
||||
private:
|
||||
void _PrintInput(const std::wstring_view data);
|
||||
void _OutputHandler(const winrt::array_view<const char16_t> str);
|
||||
void _PrintInput(const std::string_view data);
|
||||
void _OutputHandler(const winrt::array_view<const uint8_t>& str);
|
||||
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection::TerminalOutput_revoker _outputRevoker;
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection::StateChanged_revoker _stateChangedRevoker;
|
||||
|
||||
@@ -94,15 +94,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// - helper that will write an unterminated string (generally, from a resource) to the output stream.
|
||||
// Arguments:
|
||||
// - str: the string to write.
|
||||
void AzureConnection::_WriteStringWithNewline(std::wstring str)
|
||||
{
|
||||
str.append(L"\r\n");
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(str));
|
||||
}
|
||||
|
||||
void AzureConnection::_WriteStringWithNewline(const std::wstring_view str)
|
||||
{
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(str + L"\r\n"));
|
||||
WriteUtf16Output(str + L"\r\n");
|
||||
}
|
||||
|
||||
// Method description:
|
||||
@@ -118,7 +112,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
catch (const std::exception& runtimeException)
|
||||
{
|
||||
// This also catches the AzureException, which has a .what()
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(_colorize(91, til::u8u16(std::string{ runtimeException.what() }))));
|
||||
WriteUtf16Output(_colorize(91, til::u8u16(std::string{ runtimeException.what() })));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -157,7 +151,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
_transitionToState(ConnectionState::Connecting);
|
||||
}
|
||||
|
||||
std::optional<std::wstring> AzureConnection::_ReadUserInput(InputMode mode)
|
||||
std::optional<std::string> AzureConnection::_ReadUserInput(InputMode mode)
|
||||
{
|
||||
std::unique_lock<std::mutex> inputLock{ _inputMutex };
|
||||
|
||||
@@ -168,20 +162,20 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
_currentInputMode = mode;
|
||||
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(L"> \x1b[92m")); // Make prompted user input green
|
||||
WriteUtf8Output("> \x1b[92m"); // Make prompted user input green
|
||||
|
||||
_inputEvent.wait(inputLock, [this, mode]() {
|
||||
return _currentInputMode != mode || _isStateAtOrBeyond(ConnectionState::Closing);
|
||||
});
|
||||
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(L"\x1b[m"));
|
||||
WriteUtf8Output("\x1b[m");
|
||||
|
||||
if (_isStateAtOrBeyond(ConnectionState::Closing))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::wstring readInput{};
|
||||
std::string readInput{};
|
||||
_userInput.swap(readInput);
|
||||
return readInput;
|
||||
}
|
||||
@@ -191,12 +185,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// - handles the different possible inputs in the different states
|
||||
// Arguments:
|
||||
// the user's input
|
||||
void AzureConnection::WriteInput(const winrt::array_view<const char16_t> buffer)
|
||||
void AzureConnection::WriteInput(const winrt::array_view<const uint8_t> buffer)
|
||||
{
|
||||
_writeInput(winrt_array_to_wstring_view(buffer));
|
||||
_writeInput(winrt_array_to_string_view(buffer));
|
||||
}
|
||||
|
||||
void AzureConnection::_writeInput(const std::wstring_view data)
|
||||
void AzureConnection::_writeInput(const std::string_view data)
|
||||
{
|
||||
// We read input while connected AND connecting.
|
||||
if (!_isStateOneOf(ConnectionState::Connected, ConnectionState::Connecting))
|
||||
@@ -206,8 +200,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
if (_state == AzureState::TermConnected)
|
||||
{
|
||||
auto buff{ winrt::to_string(data) };
|
||||
WinHttpWebSocketSend(_webSocket.get(), WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE, buff.data(), gsl::narrow<DWORD>(buff.size()));
|
||||
WinHttpWebSocketSend(_webSocket.get(), WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE, const_cast<char*>(data.data()), gsl::narrow<DWORD>(data.size()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -217,19 +210,19 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
if (_userInput.size() > 0)
|
||||
{
|
||||
_userInput.pop_back();
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(L"\x08 \x08")); // overstrike the character with a space
|
||||
WriteUtf8Output("\x08 \x08"); // overstrike the character with a space
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(data)); // echo back
|
||||
WriteUtf8Output(data); // echo back
|
||||
|
||||
switch (_currentInputMode)
|
||||
{
|
||||
case InputMode::Line:
|
||||
if (data.size() > 0 && gsl::at(data, 0) == UNICODE_CARRIAGERETURN)
|
||||
{
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(L"\r\n")); // we probably got a \r, so we need to advance to the next line.
|
||||
WriteUtf8Output("\r\n"); // we probably got a \r, so we need to advance to the next line.
|
||||
_currentInputMode = InputMode::None; // toggling the mode indicates completion
|
||||
_inputEvent.notify_one();
|
||||
break;
|
||||
@@ -421,21 +414,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
case WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE:
|
||||
case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE:
|
||||
{
|
||||
const auto result{ til::u8u16(std::string_view{ _buffer.data(), read }, _u16Str, _u8State) };
|
||||
if (FAILED(result))
|
||||
{
|
||||
// EXIT POINT
|
||||
_transitionToState(ConnectionState::Failed);
|
||||
return gsl::narrow<DWORD>(result);
|
||||
}
|
||||
|
||||
if (_u16Str.empty())
|
||||
if (read == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Pass the output to our registered event handlers
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(_u16Str));
|
||||
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(_buffer.data()), read });
|
||||
break;
|
||||
}
|
||||
case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE:
|
||||
@@ -532,14 +517,14 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
|
||||
const auto& tenantSelection = maybeTenantSelection.value();
|
||||
if (tenantSelection == RS_(L"AzureUserEntry_RemoveStored"))
|
||||
if (tenantSelection == RS_A(L"AzureUserEntry_RemoveStored"))
|
||||
{
|
||||
// User wants to remove the stored settings
|
||||
_RemoveCredentials();
|
||||
_state = AzureState::DeviceFlow;
|
||||
return;
|
||||
}
|
||||
else if (tenantSelection == RS_(L"AzureUserEntry_NewLogin"))
|
||||
else if (tenantSelection == RS_A(L"AzureUserEntry_NewLogin"))
|
||||
{
|
||||
// User wants to login with a different account
|
||||
_state = AzureState::DeviceFlow;
|
||||
@@ -720,13 +705,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
|
||||
const auto& storeCredentials = maybeStoreCredentials.value();
|
||||
if (storeCredentials == RS_(L"AzureUserEntry_Yes"))
|
||||
if (storeCredentials == RS_A(L"AzureUserEntry_Yes"))
|
||||
{
|
||||
_StoreCredential();
|
||||
_WriteStringWithNewline(RS_(L"AzureTokensStored"));
|
||||
break;
|
||||
}
|
||||
else if (storeCredentials == RS_(L"AzureUserEntry_No"))
|
||||
else if (storeCredentials == RS_A(L"AzureUserEntry_No"))
|
||||
{
|
||||
break; // we're done, but the user wants nothing.
|
||||
}
|
||||
@@ -778,7 +763,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const auto shellType = _ParsePreferredShellType(settingsResponse);
|
||||
_WriteStringWithNewline(RS_(L"AzureRequestingTerminal"));
|
||||
const auto socketUri = _GetTerminal(shellType);
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(L"\r\n"));
|
||||
WriteUtf16Output(L"\r\n");
|
||||
|
||||
//// Step 8: connecting to said terminal
|
||||
{
|
||||
@@ -810,7 +795,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
_state = AzureState::TermConnected;
|
||||
|
||||
std::wstring queuedUserInput{};
|
||||
std::string queuedUserInput{};
|
||||
std::swap(_userInput, queuedUserInput);
|
||||
if (queuedUserInput.size() > 0)
|
||||
{
|
||||
|
||||
@@ -22,12 +22,10 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
void Initialize(const Windows::Foundation::Collections::ValueSet& settings);
|
||||
|
||||
void Start();
|
||||
void WriteInput(const winrt::array_view<const char16_t> buffer);
|
||||
void WriteInput(const winrt::array_view<const uint8_t> buffer);
|
||||
void Resize(uint32_t rows, uint32_t columns);
|
||||
void Close();
|
||||
|
||||
til::event<TerminalOutputHandler> TerminalOutput;
|
||||
|
||||
private:
|
||||
til::CoordType _initialRows{};
|
||||
til::CoordType _initialCols{};
|
||||
@@ -66,8 +64,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
std::vector<::Microsoft::Terminal::Azure::Tenant> _tenantList;
|
||||
std::optional<::Microsoft::Terminal::Azure::Tenant> _currentTenant;
|
||||
|
||||
void _writeInput(const std::wstring_view str);
|
||||
void _WriteStringWithNewline(std::wstring str);
|
||||
void _writeInput(const std::string_view str);
|
||||
void _WriteStringWithNewline(const std::wstring_view str);
|
||||
void _WriteCaughtExceptionRecord();
|
||||
winrt::Windows::Data::Json::JsonObject _SendRequestReturningJson(std::wstring_view uri, const winrt::Windows::Web::Http::IHttpContent& content = nullptr, winrt::Windows::Web::Http::HttpMethod method = nullptr, const winrt::Windows::Foundation::Uri referer = nullptr);
|
||||
@@ -88,19 +85,17 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
Line
|
||||
};
|
||||
InputMode _currentInputMode{ InputMode::None };
|
||||
std::wstring _userInput;
|
||||
std::string _userInput;
|
||||
std::condition_variable _inputEvent;
|
||||
std::mutex _inputMutex;
|
||||
|
||||
std::optional<std::wstring> _ReadUserInput(InputMode mode);
|
||||
std::optional<std::string> _ReadUserInput(InputMode mode);
|
||||
|
||||
winrt::Windows::Web::Http::HttpClient _httpClient{ nullptr };
|
||||
wil::unique_winhttp_hinternet _socketSessionHandle;
|
||||
wil::unique_winhttp_hinternet _socketConnectionHandle;
|
||||
wil::unique_winhttp_hinternet _webSocket;
|
||||
|
||||
til::u8state _u8State{};
|
||||
std::wstring _u16Str;
|
||||
std::array<char, 4096> _buffer{};
|
||||
|
||||
static winrt::hstring _ParsePreferredShellType(const winrt::Windows::Data::Json::JsonObject& settingsResponse);
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
|
||||
til::typed_event<ITerminalConnection, winrt::Windows::Foundation::IInspectable> StateChanged;
|
||||
til::event<TerminalOutputHandler> TerminalOutput;
|
||||
|
||||
protected:
|
||||
template<typename U>
|
||||
@@ -101,6 +102,17 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
return _isStateOneOf(ConnectionState::Connected);
|
||||
}
|
||||
|
||||
void WriteUtf16Output(std::wstring_view str)
|
||||
{
|
||||
auto converted{ til::u16u8(str) };
|
||||
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(converted.data()), static_cast<uint32_t>(converted.size()) });
|
||||
}
|
||||
|
||||
void WriteUtf8Output(std::string_view str)
|
||||
{
|
||||
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(str.data()), static_cast<uint32_t>(str.size()) });
|
||||
}
|
||||
|
||||
winrt::guid _sessionId{};
|
||||
|
||||
private:
|
||||
|
||||
@@ -477,28 +477,31 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const auto hr = wil::ResultFromCaughtException();
|
||||
|
||||
// GH#11556 - make sure to format the error code to this string as an UNSIGNED int
|
||||
auto failureText = RS_fmt(L"ProcessFailedToLaunch", _formatStatus(hr), _commandline);
|
||||
const auto failureText = RS_fmt(L"ProcessFailedToLaunch", _formatStatus(hr), _commandline);
|
||||
WriteUtf16Output(failureText);
|
||||
|
||||
// If the path was invalid, let's present an informative message to the user
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_DIRECTORY))
|
||||
{
|
||||
failureText.append(L"\r\n");
|
||||
failureText.append(RS_fmt(L"BadPathText", _startingDirectory));
|
||||
const auto badPathText = RS_fmt(L"BadPathText", _startingDirectory);
|
||||
WriteUtf16Output(L"\r\n");
|
||||
WriteUtf16Output(badPathText);
|
||||
}
|
||||
// If the requested action requires elevation, display appropriate message
|
||||
else if (hr == HRESULT_FROM_WIN32(ERROR_ELEVATION_REQUIRED))
|
||||
{
|
||||
failureText.append(L"\r\n");
|
||||
failureText.append(RS_(L"ElevationRequired"));
|
||||
const auto elevationText = RS_(L"ElevationRequired");
|
||||
WriteUtf16Output(L"\r\n");
|
||||
WriteUtf16Output(elevationText);
|
||||
}
|
||||
// If the requested executable was not found, display appropriate message
|
||||
else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
||||
{
|
||||
failureText.append(L"\r\n");
|
||||
failureText.append(RS_(L"FileNotFound"));
|
||||
const auto fileNotFoundText = RS_(L"FileNotFound");
|
||||
WriteUtf16Output(L"\r\n");
|
||||
WriteUtf16Output(fileNotFoundText);
|
||||
}
|
||||
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(failureText));
|
||||
_transitionToState(ConnectionState::Failed);
|
||||
|
||||
// Tear down any state we may have accumulated.
|
||||
@@ -517,7 +520,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const auto msg1 = RS_fmt(L"ProcessExited", _formatStatus(status));
|
||||
const auto msg2 = RS_(L"CtrlDToClose");
|
||||
const auto msg = fmt::format(FMT_COMPILE(L"\r\n{}\r\n{}\r\n"), msg1, msg2);
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(msg));
|
||||
WriteUtf16Output(msg);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -545,10 +548,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
void ConptyConnection::WriteInput(const winrt::array_view<const char16_t> buffer)
|
||||
void ConptyConnection::WriteInput(const winrt::array_view<const uint8_t> data)
|
||||
{
|
||||
const auto data = winrt_array_to_wstring_view(buffer);
|
||||
|
||||
if (!_isConnected())
|
||||
{
|
||||
return;
|
||||
@@ -572,10 +573,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED_LOG(til::u16u8(data, _writeBuffer)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Since we are using overlapped I/O, we have to store the send buffer until the work is done.
|
||||
_writeBuffer.assign(winrt_array_to_string_view(data));
|
||||
|
||||
if (!WriteFile(_pipe.get(), _writeBuffer.data(), gsl::narrow_cast<DWORD>(_writeBuffer.length()), nullptr, &_writeOverlapped))
|
||||
{
|
||||
@@ -742,11 +741,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const wil::unique_event overlappedEvent{ CreateEventExW(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS) };
|
||||
OVERLAPPED overlapped{ .hEvent = overlappedEvent.get() };
|
||||
bool overlappedPending = false;
|
||||
char buffer[128 * 1024];
|
||||
DWORD read = 0;
|
||||
|
||||
til::u8state u8State;
|
||||
std::wstring wstr;
|
||||
char buffer[128 * 1024], buffer2[128 * 1024];
|
||||
char* thisBuffer = buffer;
|
||||
DWORD read = 0;
|
||||
char* lastBuffer = buffer2;
|
||||
DWORD lastRead = 0;
|
||||
|
||||
// If we use overlapped IO We want to queue ReadFile() calls before processing the
|
||||
// string, because TerminalOutput.raise() may take a while (relatively speaking).
|
||||
@@ -757,7 +757,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// When we have a `wstr` that's ready for processing we must do so without blocking.
|
||||
// Otherwise, whatever the user typed will be delayed until the next IO operation.
|
||||
// With overlapped IO that's not a problem because the ReadFile() calls won't block.
|
||||
if (!ReadFile(_pipe.get(), &buffer[0], sizeof(buffer), &read, &overlapped))
|
||||
if (!ReadFile(_pipe.get(), thisBuffer, sizeof(buffer), &read, &overlapped))
|
||||
{
|
||||
if (GetLastError() != ERROR_IO_PENDING)
|
||||
{
|
||||
@@ -769,7 +769,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// wstr can be empty in two situations:
|
||||
// * The previous call to til::u8u16 failed.
|
||||
// * We're using overlapped IO, and it's the first iteration.
|
||||
if (!wstr.empty())
|
||||
if (lastBuffer && lastRead)
|
||||
{
|
||||
if (!_receivedFirstByte)
|
||||
{
|
||||
@@ -789,7 +789,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
try
|
||||
{
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(wstr));
|
||||
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(lastBuffer), lastRead });
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -829,8 +829,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
// If we hit a parsing error, eat it. It's bad utf-8, we can't do anything with it.
|
||||
FAILED_LOG(til::u8u16({ &buffer[0], gsl::narrow_cast<size_t>(read) }, wstr, u8State));
|
||||
// Prepare the buffers for the next loop
|
||||
std::swap(thisBuffer, lastBuffer);
|
||||
std::swap(read, lastRead);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
static safe_void_coroutine final_release(std::unique_ptr<ConptyConnection> connection);
|
||||
|
||||
void Start();
|
||||
void WriteInput(const winrt::array_view<const char16_t> buffer);
|
||||
void WriteInput(const winrt::array_view<const uint8_t> buffer);
|
||||
void Resize(uint32_t rows, uint32_t columns);
|
||||
void ResetSize();
|
||||
void Close() noexcept;
|
||||
@@ -52,8 +52,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
const winrt::guid& guid,
|
||||
const winrt::guid& profileGuid);
|
||||
|
||||
til::event<TerminalOutputHandler> TerminalOutput;
|
||||
|
||||
private:
|
||||
static void closePseudoConsoleAsync(HPCON hPC) noexcept;
|
||||
static HRESULT NewHandoff(HANDLE* in, HANDLE* out, HANDLE signal, HANDLE reference, HANDLE server, HANDLE client, const TERMINAL_STARTUP_INFO* startupInfo) noexcept;
|
||||
|
||||
@@ -13,28 +13,29 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
void EchoConnection::Start() noexcept
|
||||
{
|
||||
_transitionToState(ConnectionState::Connected);
|
||||
}
|
||||
|
||||
void EchoConnection::WriteInput(const winrt::array_view<const char16_t> buffer)
|
||||
void EchoConnection::WriteInput(const winrt::array_view<const uint8_t> buffer)
|
||||
{
|
||||
const auto data = winrt_array_to_wstring_view(buffer);
|
||||
std::wstringstream prettyPrint;
|
||||
for (const auto& wch : data)
|
||||
const auto data = winrt_array_to_string_view(buffer);
|
||||
std::stringstream prettyPrint;
|
||||
for (const auto& ch : data)
|
||||
{
|
||||
if (wch < 0x20)
|
||||
if (ch < 0x20)
|
||||
{
|
||||
prettyPrint << L"^" << gsl::narrow_cast<wchar_t>(wch + 0x40);
|
||||
prettyPrint << "^" << gsl::narrow_cast<char>(ch + 0x40);
|
||||
}
|
||||
else if (wch == 0x7f)
|
||||
else if (ch == 0x7f)
|
||||
{
|
||||
prettyPrint << L"0x7f";
|
||||
prettyPrint << "0x7f";
|
||||
}
|
||||
else
|
||||
{
|
||||
prettyPrint << wch;
|
||||
prettyPrint << ch;
|
||||
}
|
||||
}
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(prettyPrint.str()));
|
||||
WriteUtf8Output(prettyPrint.str());
|
||||
}
|
||||
|
||||
void EchoConnection::Resize(uint32_t /*rows*/, uint32_t /*columns*/) noexcept
|
||||
|
||||
@@ -4,25 +4,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "EchoConnection.g.h"
|
||||
#include "BaseTerminalConnection.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
{
|
||||
struct EchoConnection : EchoConnectionT<EchoConnection>
|
||||
struct EchoConnection : EchoConnectionT<EchoConnection>, BaseTerminalConnection<EchoConnection>
|
||||
{
|
||||
EchoConnection() noexcept;
|
||||
|
||||
void Start() noexcept;
|
||||
void WriteInput(const winrt::array_view<const char16_t> buffer);
|
||||
void WriteInput(const winrt::array_view<const uint8_t> buffer);
|
||||
void Resize(uint32_t rows, uint32_t columns) noexcept;
|
||||
void Close() noexcept;
|
||||
|
||||
void Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/) const noexcept {};
|
||||
|
||||
winrt::guid SessionId() const noexcept { return {}; }
|
||||
ConnectionState State() const noexcept { return ConnectionState::Connected; }
|
||||
|
||||
til::event<TerminalOutputHandler> TerminalOutput;
|
||||
til::typed_event<ITerminalConnection, IInspectable> StateChanged;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@ namespace Microsoft.Terminal.TerminalConnection
|
||||
Failed
|
||||
};
|
||||
|
||||
delegate void TerminalOutputHandler(Char[] output);
|
||||
delegate void TerminalOutputHandler(UInt8[] output);
|
||||
|
||||
interface ITerminalConnection
|
||||
{
|
||||
void Initialize(Windows.Foundation.Collections.ValueSet settings);
|
||||
|
||||
void Start();
|
||||
void WriteInput(Char[] data);
|
||||
void WriteInput(UInt8[] data);
|
||||
void Resize(UInt32 rows, UInt32 columns);
|
||||
void Close();
|
||||
|
||||
|
||||
@@ -476,7 +476,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
if (_connection)
|
||||
{
|
||||
_connection.WriteInput(winrt_wstring_to_array_view(wstr));
|
||||
const auto utf8String{ til::u16u8(wstr) };
|
||||
_connection.WriteInput(winrt_u8string_to_array_view(utf8String));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2236,13 +2237,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto noticeArgs = winrt::make<NoticeEventArgs>(NoticeLevel::Info, RS_(L"TermControlReadOnly"));
|
||||
RaiseNotice.raise(*this, std::move(noticeArgs));
|
||||
}
|
||||
void ControlCore::_connectionOutputHandler(const winrt::array_view<const char16_t> str)
|
||||
void ControlCore::_connectionOutputHandler(const winrt::array_view<const uint8_t>& data)
|
||||
{
|
||||
try
|
||||
{
|
||||
FAILED_LOG(til::u8u16(winrt_array_to_string_view(data), _u16ConversionBuffer, _u8State));
|
||||
|
||||
if (!_u16ConversionBuffer.empty()) [[likely]]
|
||||
{
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
_terminal->Write(winrt_array_to_wstring_view(str));
|
||||
_terminal->Write(_u16ConversionBuffer);
|
||||
}
|
||||
|
||||
if (!_pendingResponses.empty())
|
||||
|
||||
@@ -349,7 +349,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void _raiseReadOnlyWarning();
|
||||
void _updateAntiAliasingMode();
|
||||
void _connectionOutputHandler(winrt::array_view<const char16_t> str);
|
||||
void _connectionOutputHandler(const winrt::array_view<const uint8_t>& data);
|
||||
void _connectionStateChangedHandler(const TerminalConnection::ITerminalConnection&, const Windows::Foundation::IInspectable&);
|
||||
void _updateHoveredCell(const std::optional<til::point> terminalPosition);
|
||||
void _setOpacity(const float opacity, const bool focused = true);
|
||||
@@ -459,6 +459,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TerminalConnection::ITerminalConnection::StateChanged_revoker _connectionStateChangedRevoker;
|
||||
TerminalConnection::ITerminalConnection _connection{ nullptr };
|
||||
|
||||
std::wstring _u16ConversionBuffer;
|
||||
til::u8state _u8State;
|
||||
|
||||
friend class ControlUnitTests::ControlCoreTests;
|
||||
friend class ControlUnitTests::ControlInteractivityTests;
|
||||
bool _inUnitTests{ false };
|
||||
|
||||
@@ -7,20 +7,20 @@
|
||||
using namespace ::winrt::Microsoft::Terminal::TerminalConnection;
|
||||
using namespace ::winrt::Windows::Foundation;
|
||||
|
||||
static constexpr std::wstring_view PromptTextPlain{ L"C:\\> " };
|
||||
static constexpr std::wstring_view PromptTextPowerline{ L"\x1b[49;34m\xe0b6\x1b[1;97;44m C:\\ \x1b[m\x1b[46;34m\xe0b8\x1b[49;36m\xe0b8\x1b[m " };
|
||||
static constexpr std::u8string_view PromptTextPlain{ u8"C:\\> " };
|
||||
static constexpr std::u8string_view PromptTextPowerline{ u8"\x1b[49;34m\xe0b6\x1b[1;97;44m C:\\ \x1b[m\x1b[46;34m\xe0b8\x1b[49;36m\xe0b8\x1b[m " };
|
||||
|
||||
// clang-format off
|
||||
static constexpr std::wstring_view PreviewText{
|
||||
L"\x001b"
|
||||
L"c" // Hard Reset (RIS); on separate lines to avoid becoming 0x01BC
|
||||
L"Windows Terminal\r\n"
|
||||
L"{0}\x1b[93m" L"git\x1b[m diff \x1b[90m-w\x1b[m\r\n"
|
||||
L"\x1b[1m" L"diff --git a/win b/win\x1b[m\r\n"
|
||||
L"\x1b[36m@@ -1 +1 @@\x1b[m\r\n"
|
||||
L"\x1b[31m- Windows Console\x1b[m\r\n"
|
||||
L"\x1b[32m+ Windows Terminal!\x1b[m\r\n"
|
||||
L"{0}\x1b[93mWrite-Host \x1b[36m\"\xd83c\xdf2f!\"\x1b[1D\x1b[m"
|
||||
static constexpr std::u8string_view PreviewText{
|
||||
u8"\x001b"
|
||||
u8"c" // Hard Reset (RIS); on separate lines to avoid becoming 0x01BC
|
||||
u8"Windows Terminal\r\n"
|
||||
u8"{0}\x1b[93m" u8"git\x1b[m diff \x1b[90m-w\x1b[m\r\n"
|
||||
u8"\x1b[1m" u8"diff --git a/win b/win\x1b[m\r\n"
|
||||
u8"\x1b[36m@@ -1 +1 @@\x1b[m\r\n"
|
||||
u8"\x1b[31m- Windows Console\x1b[m\r\n"
|
||||
u8"\x1b[32m+ Windows Terminal!\x1b[m\r\n"
|
||||
u8"{0}\x1b[93mWrite-Host \x1b[36m\"🌯!\"\x1b[1D\x1b[m"
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -32,14 +32,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
const auto prompt = _displayPowerlineGlyphs ? PromptTextPowerline : PromptTextPlain;
|
||||
const auto text = fmt::format(FMT_COMPILE(PreviewText), prompt);
|
||||
TerminalOutput.raise(winrt_wstring_to_array_view(text));
|
||||
TerminalOutput.raise(winrt_u8string_to_array_view(text));
|
||||
}
|
||||
|
||||
void PreviewConnection::Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void PreviewConnection::WriteInput(const winrt::array_view<const char16_t> /*data*/)
|
||||
void PreviewConnection::WriteInput(const winrt::array_view<const uint8_t> /*data*/)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Initialize(const Windows::Foundation::Collections::ValueSet& settings) noexcept;
|
||||
void Start();
|
||||
void WriteInput(const winrt::array_view<const char16_t> buffer);
|
||||
void WriteInput(const winrt::array_view<const uint8_t> buffer);
|
||||
void Resize(uint32_t rows, uint32_t columns) noexcept;
|
||||
void Close() noexcept;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace ControlUnitTests
|
||||
|
||||
void Initialize(const winrt::Windows::Foundation::Collections::ValueSet& /*settings*/){};
|
||||
void Start() noexcept {};
|
||||
void WriteInput(const winrt::array_view<const char16_t> data)
|
||||
void WriteInput(const winrt::array_view<const uint8_t> data)
|
||||
{
|
||||
TerminalOutput.raise(data);
|
||||
}
|
||||
|
||||
@@ -298,6 +298,28 @@ inline std::wstring_view winrt_array_to_wstring_view(const winrt::array_view<con
|
||||
return { reinterpret_cast<const wchar_t*>(str.data()), str.size() };
|
||||
}
|
||||
|
||||
template<typename T, typename CharTraits>
|
||||
requires(sizeof(T) == 1)
|
||||
inline winrt::array_view<const uint8_t> winrt_u8string_to_array_view(const std::basic_string_view<T, CharTraits>& str)
|
||||
{
|
||||
#pragma warning(suppress : 26490) // Don't use reinterpret_cast (type.1).
|
||||
return winrt::array_view<const uint8_t>{ reinterpret_cast<const uint8_t*>(str.data()), gsl::narrow<uint32_t>(str.size()) };
|
||||
}
|
||||
|
||||
template<typename T, typename CharTraits, typename Allocator>
|
||||
requires(sizeof(T) == 1)
|
||||
inline winrt::array_view<const uint8_t> winrt_u8string_to_array_view(const std::basic_string<T, CharTraits, Allocator>& str)
|
||||
{
|
||||
#pragma warning(suppress : 26490) // Don't use reinterpret_cast (type.1).
|
||||
return winrt_u8string_to_array_view(std::basic_string_view<T, CharTraits>{ str });
|
||||
}
|
||||
|
||||
inline std::string_view winrt_array_to_string_view(const winrt::array_view<const uint8_t>& str) noexcept
|
||||
{
|
||||
#pragma warning(suppress : 26490) // Don't use reinterpret_cast (type.1).
|
||||
return { reinterpret_cast<const char*>(str.data()), str.size() };
|
||||
}
|
||||
|
||||
// This is a helper method for deserializing a SAFEARRAY of
|
||||
// COM objects and converting it to a vector that
|
||||
// owns the extracted COM objects
|
||||
|
||||
Reference in New Issue
Block a user