mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
What if the connection wrote its output as a utf-8 array?
This commit is contained in:
parent
224ac9de47
commit
db65c42f2c
@ -120,17 +120,18 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
return ConnectionState::Failed;
|
||||
}
|
||||
|
||||
void DebugTapConnection::_OutputHandler(const std::wstring_view str)
|
||||
void DebugTapConnection::_OutputHandler(const std::string_view str)
|
||||
{
|
||||
auto output = til::visualize_control_codes(str);
|
||||
(void)str;
|
||||
//auto output = til::visualize_control_codes(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;)
|
||||
{
|
||||
output.insert(++lfPos, L"\r\n");
|
||||
}
|
||||
TerminalOutput.raise(output);
|
||||
//for (size_t lfPos = 0; (lfPos = output.find(L'\x0A', lfPos)) != std::wstring::npos;)
|
||||
//{
|
||||
//output.insert(++lfPos, L"\r\n");
|
||||
//}
|
||||
//TerminalOutput.raise(output);
|
||||
}
|
||||
|
||||
// Called by the DebugInputTapConnection to print user input
|
||||
@ -138,7 +139,8 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
{
|
||||
auto clean{ til::visualize_control_codes(str) };
|
||||
auto formatted{ wil::str_printf<std::wstring>(L"\x1b[91m%ls\x1b[m", clean.data()) };
|
||||
TerminalOutput.raise(formatted);
|
||||
(void)formatted;
|
||||
//TerminalOutput.raise(formatted);
|
||||
}
|
||||
|
||||
// Wire us up so that we can forward input through
|
||||
|
||||
@ -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 std::string_view str);
|
||||
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection::TerminalOutput_revoker _outputRevoker;
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection::StateChanged_revoker _stateChangedRevoker;
|
||||
|
||||
@ -96,7 +96,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// - str: the string to write.
|
||||
void AzureConnection::_WriteStringWithNewline(const std::wstring_view str)
|
||||
{
|
||||
TerminalOutput.raise(str + L"\r\n");
|
||||
_dhSend16(str + L"\r\n");
|
||||
}
|
||||
|
||||
// Method description:
|
||||
@ -112,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(_colorize(91, til::u8u16(std::string{ runtimeException.what() })));
|
||||
_dhSend16(_colorize(91, til::u8u16(std::string{ runtimeException.what() })));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@ -162,13 +162,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
_currentInputMode = mode;
|
||||
|
||||
TerminalOutput.raise(L"> \x1b[92m"); // Make prompted user input green
|
||||
_dhSend16(L"> \x1b[92m"); // Make prompted user input green
|
||||
|
||||
_inputEvent.wait(inputLock, [this, mode]() {
|
||||
return _currentInputMode != mode || _isStateAtOrBeyond(ConnectionState::Closing);
|
||||
});
|
||||
|
||||
TerminalOutput.raise(L"\x1b[m");
|
||||
_dhSend16(L"\x1b[m");
|
||||
|
||||
if (_isStateAtOrBeyond(ConnectionState::Closing))
|
||||
{
|
||||
@ -211,19 +211,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
|
||||
_dhSend16(L"\x08 \x08"); // overstrike the character with a space
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TerminalOutput.raise(data); // echo back
|
||||
_dhSend16(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.
|
||||
_dhSend16(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;
|
||||
@ -415,21 +415,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(_u16Str);
|
||||
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(_buffer.data()), read });
|
||||
break;
|
||||
}
|
||||
case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE:
|
||||
@ -772,7 +764,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");
|
||||
_dhSend16(L"\r\n");
|
||||
|
||||
//// Step 8: connecting to said terminal
|
||||
{
|
||||
|
||||
@ -103,6 +103,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
std::array<char, 4096> _buffer{};
|
||||
|
||||
static winrt::hstring _ParsePreferredShellType(const winrt::Windows::Data::Json::JsonObject& settingsResponse);
|
||||
|
||||
template<typename B>
|
||||
void _dhSend16(B&& b)
|
||||
{
|
||||
auto eight = til::u16u8(b);
|
||||
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(eight.c_str()), static_cast<uint32_t>(eight.size()) });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -478,28 +478,28 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
// 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);
|
||||
_dhSend16(failureText);
|
||||
|
||||
// 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);
|
||||
_dhSend16(L"\r\n");
|
||||
_dhSend16(badPathText);
|
||||
}
|
||||
// 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);
|
||||
_dhSend16(L"\r\n");
|
||||
_dhSend16(elevationText);
|
||||
}
|
||||
// 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);
|
||||
_dhSend16(L"\r\n");
|
||||
_dhSend16(fileNotFoundText);
|
||||
}
|
||||
|
||||
_transitionToState(ConnectionState::Failed);
|
||||
@ -520,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(msg);
|
||||
_dhSend16(msg);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@ -745,11 +745,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).
|
||||
@ -760,7 +761,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)
|
||||
{
|
||||
@ -772,7 +773,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)
|
||||
{
|
||||
@ -792,7 +793,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
try
|
||||
{
|
||||
TerminalOutput.raise(wstr);
|
||||
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(lastBuffer), lastRead });
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@ -832,8 +833,7 @@ 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));
|
||||
std::swap(thisBuffer, lastBuffer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -103,6 +103,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
} _startupInfo{};
|
||||
|
||||
DWORD _OutputThread();
|
||||
template<typename B>
|
||||
void _dhSend16(B&& b)
|
||||
{
|
||||
auto eight = til::u16u8(b);
|
||||
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(eight.c_str()), static_cast<uint32_t>(eight.size()) });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
prettyPrint << wch;
|
||||
}
|
||||
}
|
||||
TerminalOutput.raise(prettyPrint.str());
|
||||
(void)prettyPrint;
|
||||
//TerminalOutput.raise(prettyPrint.str());
|
||||
}
|
||||
|
||||
void EchoConnection::Resize(uint32_t /*rows*/, uint32_t /*columns*/) noexcept
|
||||
|
||||
@ -13,7 +13,7 @@ namespace Microsoft.Terminal.TerminalConnection
|
||||
Failed
|
||||
};
|
||||
|
||||
delegate void TerminalOutputHandler(String output);
|
||||
delegate void TerminalOutputHandler(UInt8[] output);
|
||||
|
||||
interface ITerminalConnection
|
||||
{
|
||||
|
||||
@ -2221,13 +2221,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 hstring& hstr)
|
||||
void ControlCore::_connectionOutputHandler(const winrt::array_view<const uint8_t>& data)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::wstring u16out;
|
||||
(void)til::u8u16(std::string_view{reinterpret_cast<const char*>(data.data()), data.size()}, u16out, _u8State);
|
||||
|
||||
{
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
_terminal->Write(hstr);
|
||||
_terminal->Write(u16out);
|
||||
}
|
||||
|
||||
if (!_pendingResponses.empty())
|
||||
|
||||
@ -348,7 +348,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void _raiseReadOnlyWarning();
|
||||
void _updateAntiAliasingMode();
|
||||
void _connectionOutputHandler(const hstring& hstr);
|
||||
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);
|
||||
@ -457,6 +457,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TerminalConnection::ITerminalConnection::StateChanged_revoker _connectionStateChangedRevoker;
|
||||
TerminalConnection::ITerminalConnection _connection{ nullptr };
|
||||
|
||||
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\"\xd83c\xdf2f!\"\x1b[1D\x1b[m"
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@ -31,7 +31,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void PreviewConnection::Start() noexcept
|
||||
{
|
||||
// Send the preview text
|
||||
TerminalOutput.raise(fmt::format(PreviewText, _displayPowerlineGlyphs ? PromptTextPowerline : PromptTextPlain));
|
||||
auto e = fmt::format(PreviewText, _displayPowerlineGlyphs ? PromptTextPowerline : PromptTextPlain);
|
||||
//auto e = til::u16u8(s);
|
||||
TerminalOutput.raise(winrt::array_view{ reinterpret_cast<const uint8_t*>(e.c_str()), static_cast<uint32_t>(e.size()) });
|
||||
}
|
||||
|
||||
void PreviewConnection::Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/) noexcept
|
||||
|
||||
@ -81,3 +81,13 @@ std::wstring RS_fmt_impl(std::wstring_view key, Args&&... args)
|
||||
const auto format = GetLibraryResourceString(key);
|
||||
return fmt::format(fmt::runtime(std::wstring_view{ format }), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#define RS_A_fmt(x, ...) RS_A_fmt_impl(USES_RESOURCE(x), __VA_ARGS__)
|
||||
|
||||
template<typename... Args>
|
||||
std::string RS_A_fmt_impl(std::wstring_view key, Args&&... args)
|
||||
{
|
||||
const auto format = GetLibraryResourceString(key);
|
||||
auto format8 = til::u16u8(std::wstring_view{ format });
|
||||
return fmt::format(fmt::runtime(std::string_view{ format8 }), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user