diff --git a/src/cascadia/TerminalApp/DebugTapConnection.cpp b/src/cascadia/TerminalApp/DebugTapConnection.cpp index 41416c3b98..7cfa19b5a0 100644 --- a/src/cascadia/TerminalApp/DebugTapConnection.cpp +++ b/src/cascadia/TerminalApp/DebugTapConnection.cpp @@ -120,9 +120,9 @@ namespace winrt::Microsoft::TerminalApp::implementation return ConnectionState::Failed; } - void DebugTapConnection::_OutputHandler(const std::wstring_view str) + void DebugTapConnection::_OutputHandler(const winrt::array_view str) { - auto output = til::visualize_control_codes(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. @@ -130,7 +130,7 @@ namespace winrt::Microsoft::TerminalApp::implementation { output.insert(++lfPos, L"\r\n"); } - TerminalOutput.raise(output); + TerminalOutput.raise(winrt_wstring_to_array_view(output)); } // Called by the DebugInputTapConnection to print user input @@ -138,7 +138,7 @@ namespace winrt::Microsoft::TerminalApp::implementation { auto clean{ til::visualize_control_codes(str) }; auto formatted{ wil::str_printf(L"\x1b[91m%ls\x1b[m", clean.data()) }; - TerminalOutput.raise(formatted); + TerminalOutput.raise(winrt_wstring_to_array_view(formatted)); } // Wire us up so that we can forward input through diff --git a/src/cascadia/TerminalApp/DebugTapConnection.h b/src/cascadia/TerminalApp/DebugTapConnection.h index 70b607e82f..57dfbe4572 100644 --- a/src/cascadia/TerminalApp/DebugTapConnection.h +++ b/src/cascadia/TerminalApp/DebugTapConnection.h @@ -31,7 +31,7 @@ namespace winrt::Microsoft::TerminalApp::implementation private: void _PrintInput(const std::wstring_view data); - void _OutputHandler(const std::wstring_view str); + void _OutputHandler(const winrt::array_view str); winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection::TerminalOutput_revoker _outputRevoker; winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection::StateChanged_revoker _stateChangedRevoker; diff --git a/src/cascadia/TerminalConnection/AzureConnection.cpp b/src/cascadia/TerminalConnection/AzureConnection.cpp index dbc6ec9905..72208af100 100644 --- a/src/cascadia/TerminalConnection/AzureConnection.cpp +++ b/src/cascadia/TerminalConnection/AzureConnection.cpp @@ -94,9 +94,15 @@ 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(str + L"\r\n"); + TerminalOutput.raise(winrt_wstring_to_array_view(str + L"\r\n")); } // Method description: @@ -112,7 +118,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation catch (const std::exception& runtimeException) { // This also catches the AzureException, which has a .what() - TerminalOutput.raise(_colorize(91, til::u8u16(std::string{ runtimeException.what() }))); + TerminalOutput.raise(winrt_wstring_to_array_view(_colorize(91, til::u8u16(std::string{ runtimeException.what() })))); } catch (...) { @@ -162,13 +168,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation _currentInputMode = mode; - TerminalOutput.raise(L"> \x1b[92m"); // Make prompted user input green + TerminalOutput.raise(winrt_wstring_to_array_view(L"> \x1b[92m")); // Make prompted user input green _inputEvent.wait(inputLock, [this, mode]() { return _currentInputMode != mode || _isStateAtOrBeyond(ConnectionState::Closing); }); - TerminalOutput.raise(L"\x1b[m"); + TerminalOutput.raise(winrt_wstring_to_array_view(L"\x1b[m")); if (_isStateAtOrBeyond(ConnectionState::Closing)) { @@ -211,19 +217,19 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation if (_userInput.size() > 0) { _userInput.pop_back(); - TerminalOutput.raise(L"\x08 \x08"); // overstrike the character with a space + TerminalOutput.raise(winrt_wstring_to_array_view(L"\x08 \x08")); // overstrike the character with a space } } else { - TerminalOutput.raise(data); // echo back + TerminalOutput.raise(winrt_wstring_to_array_view(data)); // echo back switch (_currentInputMode) { case InputMode::Line: if (data.size() > 0 && gsl::at(data, 0) == UNICODE_CARRIAGERETURN) { - TerminalOutput.raise(L"\r\n"); // we probably got a \r, so we need to advance to the next line. + TerminalOutput.raise(winrt_wstring_to_array_view(L"\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; @@ -429,7 +435,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation } // Pass the output to our registered event handlers - TerminalOutput.raise(_u16Str); + TerminalOutput.raise(winrt_wstring_to_array_view(_u16Str)); break; } case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE: @@ -772,7 +778,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation const auto shellType = _ParsePreferredShellType(settingsResponse); _WriteStringWithNewline(RS_(L"AzureRequestingTerminal")); const auto socketUri = _GetTerminal(shellType); - TerminalOutput.raise(L"\r\n"); + TerminalOutput.raise(winrt_wstring_to_array_view(L"\r\n")); //// Step 8: connecting to said terminal { diff --git a/src/cascadia/TerminalConnection/AzureConnection.h b/src/cascadia/TerminalConnection/AzureConnection.h index 3b8a092692..d1553dbfcc 100644 --- a/src/cascadia/TerminalConnection/AzureConnection.h +++ b/src/cascadia/TerminalConnection/AzureConnection.h @@ -67,6 +67,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation std::optional<::Microsoft::Terminal::Azure::Tenant> _currentTenant; void _writeInput(const std::wstring_view str); + void _WriteStringWithNewline(std::wstring 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); diff --git a/src/cascadia/TerminalConnection/ConptyConnection.cpp b/src/cascadia/TerminalConnection/ConptyConnection.cpp index 5db43c04b2..e83782ff65 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.cpp +++ b/src/cascadia/TerminalConnection/ConptyConnection.cpp @@ -477,31 +477,28 @@ 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 - const auto failureText = RS_fmt(L"ProcessFailedToLaunch", _formatStatus(hr), _commandline); - TerminalOutput.raise(failureText); + auto failureText = RS_fmt(L"ProcessFailedToLaunch", _formatStatus(hr), _commandline); // If the path was invalid, let's present an informative message to the user if (hr == HRESULT_FROM_WIN32(ERROR_DIRECTORY)) { - const auto badPathText = RS_fmt(L"BadPathText", _startingDirectory); - TerminalOutput.raise(L"\r\n"); - TerminalOutput.raise(badPathText); + failureText.append(L"\r\n"); + failureText.append(RS_fmt(L"BadPathText", _startingDirectory)); } // If the requested action requires elevation, display appropriate message else if (hr == HRESULT_FROM_WIN32(ERROR_ELEVATION_REQUIRED)) { - const auto elevationText = RS_(L"ElevationRequired"); - TerminalOutput.raise(L"\r\n"); - TerminalOutput.raise(elevationText); + failureText.append(L"\r\n"); + failureText.append(RS_(L"ElevationRequired")); } // If the requested executable was not found, display appropriate message else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) { - const auto fileNotFoundText = RS_(L"FileNotFound"); - TerminalOutput.raise(L"\r\n"); - TerminalOutput.raise(fileNotFoundText); + failureText.append(L"\r\n"); + failureText.append(RS_(L"FileNotFound")); } + TerminalOutput.raise(winrt_wstring_to_array_view(failureText)); _transitionToState(ConnectionState::Failed); // Tear down any state we may have accumulated. @@ -520,7 +517,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(msg); + TerminalOutput.raise(winrt_wstring_to_array_view(msg)); } CATCH_LOG(); } @@ -792,7 +789,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation try { - TerminalOutput.raise(wstr); + TerminalOutput.raise(winrt_wstring_to_array_view(wstr)); } CATCH_LOG(); } diff --git a/src/cascadia/TerminalConnection/EchoConnection.cpp b/src/cascadia/TerminalConnection/EchoConnection.cpp index ca28af28e5..f50433b521 100644 --- a/src/cascadia/TerminalConnection/EchoConnection.cpp +++ b/src/cascadia/TerminalConnection/EchoConnection.cpp @@ -34,7 +34,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation prettyPrint << wch; } } - TerminalOutput.raise(prettyPrint.str()); + TerminalOutput.raise(winrt_wstring_to_array_view(prettyPrint.str())); } void EchoConnection::Resize(uint32_t /*rows*/, uint32_t /*columns*/) noexcept diff --git a/src/cascadia/TerminalConnection/ITerminalConnection.idl b/src/cascadia/TerminalConnection/ITerminalConnection.idl index 275b57b2ac..d516f2038a 100644 --- a/src/cascadia/TerminalConnection/ITerminalConnection.idl +++ b/src/cascadia/TerminalConnection/ITerminalConnection.idl @@ -13,7 +13,7 @@ namespace Microsoft.Terminal.TerminalConnection Failed }; - delegate void TerminalOutputHandler(String output); + delegate void TerminalOutputHandler(Char[] output); interface ITerminalConnection { diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index be7350f11a..8815169ba4 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -10,8 +10,6 @@ #include #include -#include -#include #include "EventArgs.h" #include "../../renderer/atlas/AtlasEngine.h" @@ -2238,13 +2236,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation auto noticeArgs = winrt::make(NoticeLevel::Info, RS_(L"TermControlReadOnly")); RaiseNotice.raise(*this, std::move(noticeArgs)); } - void ControlCore::_connectionOutputHandler(const hstring& hstr) + void ControlCore::_connectionOutputHandler(const winrt::array_view str) { try { { const auto lock = _terminal->LockForWriting(); - _terminal->Write(hstr); + _terminal->Write(winrt_array_to_wstring_view(str)); } if (!_pendingResponses.empty()) diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index 112848dc6e..99f13078c9 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -349,7 +349,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation void _raiseReadOnlyWarning(); void _updateAntiAliasingMode(); - void _connectionOutputHandler(const hstring& hstr); + void _connectionOutputHandler(winrt::array_view str); void _connectionStateChangedHandler(const TerminalConnection::ITerminalConnection&, const Windows::Foundation::IInspectable&); void _updateHoveredCell(const std::optional terminalPosition); void _setOpacity(const float opacity, const bool focused = true); diff --git a/src/cascadia/TerminalSettingsEditor/PreviewConnection.cpp b/src/cascadia/TerminalSettingsEditor/PreviewConnection.cpp index cc1508cf35..aadbc60eaa 100644 --- a/src/cascadia/TerminalSettingsEditor/PreviewConnection.cpp +++ b/src/cascadia/TerminalSettingsEditor/PreviewConnection.cpp @@ -28,10 +28,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { PreviewConnection::PreviewConnection() noexcept = default; - void PreviewConnection::Start() noexcept + void PreviewConnection::Start() { - // Send the preview text - TerminalOutput.raise(fmt::format(PreviewText, _displayPowerlineGlyphs ? PromptTextPowerline : PromptTextPlain)); + const auto prompt = _displayPowerlineGlyphs ? PromptTextPowerline : PromptTextPlain; + const auto text = fmt::format(FMT_COMPILE(PreviewText), prompt); + TerminalOutput.raise(winrt_wstring_to_array_view(text)); } void PreviewConnection::Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/) noexcept @@ -50,7 +51,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { } - void PreviewConnection::DisplayPowerlineGlyphs(bool d) noexcept + void PreviewConnection::DisplayPowerlineGlyphs(bool d) { if (_displayPowerlineGlyphs != d) { diff --git a/src/cascadia/TerminalSettingsEditor/PreviewConnection.h b/src/cascadia/TerminalSettingsEditor/PreviewConnection.h index c988ff5156..427b66035a 100644 --- a/src/cascadia/TerminalSettingsEditor/PreviewConnection.h +++ b/src/cascadia/TerminalSettingsEditor/PreviewConnection.h @@ -22,12 +22,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation PreviewConnection() noexcept; void Initialize(const Windows::Foundation::Collections::ValueSet& settings) noexcept; - void Start() noexcept; + void Start(); void WriteInput(const winrt::array_view buffer); void Resize(uint32_t rows, uint32_t columns) noexcept; void Close() noexcept; - void DisplayPowerlineGlyphs(bool d) noexcept; + void DisplayPowerlineGlyphs(bool d); winrt::guid SessionId() const noexcept { return {}; } winrt::Microsoft::Terminal::TerminalConnection::ConnectionState State() const noexcept { return winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::Connected; } diff --git a/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp b/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp index 5d886064a6..8007ee5fc6 100644 --- a/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp +++ b/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp @@ -104,13 +104,14 @@ namespace ControlUnitTests auto _addInputCallback(const winrt::com_ptr& conn, std::deque& expectedOutput) { - conn->TerminalOutput([&](const hstring& hstr) { + conn->TerminalOutput([&](const winrt::array_view str) { VERIFY_IS_GREATER_THAN(expectedOutput.size(), 0u); + const auto actual = winrt_array_to_wstring_view(str); const auto expected = expectedOutput.front(); expectedOutput.pop_front(); - Log::Comment(fmt::format(L"Received: \"{}\"", TerminalCoreUnitTests::TestUtils::ReplaceEscapes(hstr.c_str())).c_str()); - Log::Comment(fmt::format(L"Expected: \"{}\"", TerminalCoreUnitTests::TestUtils::ReplaceEscapes(expected)).c_str()); - VERIFY_ARE_EQUAL(expected, hstr); + Log::Comment(fmt::format(L"Received: \"{}\"", til::visualize_nonspace_control_codes(std::wstring{ actual })).c_str()); + Log::Comment(fmt::format(L"Expected: \"{}\"", til::visualize_nonspace_control_codes(expected)).c_str()); + VERIFY_ARE_EQUAL(expected, actual); }); return std::move(wil::scope_exit([&]() { diff --git a/src/cascadia/UnitTests_Control/MockConnection.h b/src/cascadia/UnitTests_Control/MockConnection.h index 90758a4ce3..a0878ecd4c 100644 --- a/src/cascadia/UnitTests_Control/MockConnection.h +++ b/src/cascadia/UnitTests_Control/MockConnection.h @@ -18,7 +18,7 @@ namespace ControlUnitTests void Start() noexcept {}; void WriteInput(const winrt::array_view data) { - TerminalOutput.raise(winrt_array_to_wstring_view(data)); + TerminalOutput.raise(data); } void Resize(uint32_t /*rows*/, uint32_t /*columns*/) noexcept {} void Close() noexcept {} diff --git a/src/inc/TestUtils.h b/src/inc/TestUtils.h index d6e8f14659..36743f62c4 100644 --- a/src/inc/TestUtils.h +++ b/src/inc/TestUtils.h @@ -109,50 +109,6 @@ public: return iter; }; - // Function Description: - // - Replaces all escapes with the printable symbol for that escape - // character. This makes log parsing easier for debugging, as the literal - // escapes won't be written to the console output. - // Arguments: - // - str: the string to escape. - // Return Value: - // - A modified version of that string with non-printable characters replaced. - static std::string ReplaceEscapes(const std::string& str) - { - std::string escaped = str; - auto replaceFn = [&escaped](const std::string& search, const std::string& replace) { - size_t pos = escaped.find(search, 0); - while (pos != std::string::npos) - { - escaped.replace(pos, search.length(), replace); - pos = escaped.find(search, pos + replace.length()); - } - }; - replaceFn("\x1b", "^\x5b"); // ESC - replaceFn("\x08", "^\x48"); // BS - replaceFn("\x0A", "^\x4A"); // LF - replaceFn("\x0D", "^\x4D"); // CR - return escaped; - } - - // Function Description: - // - Replaces all escapes with the printable symbol for that escape - // character. This makes log parsing easier for debugging, as the literal - // escapes won't be written to the console output. - // Arguments: - // - wstr: the string to escape. - // Return Value: - // - A modified version of that string with non-printable characters replaced. - static std::wstring ReplaceEscapes(const std::wstring& wstr) - { - std::wstring escaped = wstr; - std::replace(escaped.begin(), escaped.end(), L'\x1b', L'\x241b'); // ESC - std::replace(escaped.begin(), escaped.end(), L'\x08', L'\x2408'); // BS - std::replace(escaped.begin(), escaped.end(), L'\x0A', L'\x240A'); // LF - std::replace(escaped.begin(), escaped.end(), L'\x0D', L'\x240D'); // CR - return escaped; - } - template static bool VerifyLineContains(TextBufferCellIterator& actual, T&&... expectedContent) {