This commit is contained in:
Leonard Hecker 2025-12-02 23:47:24 +01:00
parent ef23e6676c
commit a804faedda
21 changed files with 397 additions and 325 deletions

View File

@ -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<const char16_t> 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<std::wstring>(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

View File

@ -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<const char16_t> str);
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection::TerminalOutput_revoker _outputRevoker;
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection::StateChanged_revoker _stateChangedRevoker;

View File

@ -24,44 +24,71 @@ using namespace winrt::Windows::UI::Core;
static const int PaneBorderSize = 2;
static const int StaticMenuCount = 4; // "Separator" "Settings" "Command Palette" "About"
static std::wstring_view tokenize_field(std::wstring_view& remaining)
{
const auto beg = remaining.find_first_not_of(L' ');
const auto end = remaining.find_first_of(L' ', beg);
const auto field = til::safe_slice_abs(remaining, beg, end);
remaining = til::safe_slice_abs(remaining, end, std::wstring_view::npos);
return field;
}
enum class IdentifierType : wchar_t
{
Invalid = 0,
Session = '@',
Window = '$',
Pane = '%',
};
struct Identifier
{
IdentifierType type;
int64_t value;
};
static Identifier tokenize_identifier(std::wstring_view& remaining)
{
Identifier result = {
.type = IdentifierType::Invalid,
.value = -1,
};
const auto field = tokenize_field(remaining);
if (field.empty())
{
return result;
}
const auto type = field.front();
const auto idStr = field.substr(1);
const auto id = til::parse_signed<int64_t>(idStr, 10);
if (!id)
{
return result;
}
switch (field.front())
{
case L'@':
result.type = IdentifierType::Session;
break;
case L'$':
result.type = IdentifierType::Window;
break;
case L'%':
result.type = IdentifierType::Pane;
break;
default:
return result;
}
result.value = *id;
return result;
}
namespace winrt::TerminalApp::implementation
{
const std::wregex TmuxControl::REG_BEGIN{ L"^%begin (\\d+) (\\d+) (\\d+)$" };
const std::wregex TmuxControl::REG_END{ L"^%end (\\d+) (\\d+) (\\d+)$" };
const std::wregex TmuxControl::REG_ERROR{ L"^%error (\\d+) (\\d+) (\\d+)$" };
const std::wregex TmuxControl::REG_CLIENT_SESSION_CHANGED{ L"^%client-session-changed (\\S+) \\$(\\d+) (\\S)+$" };
const std::wregex TmuxControl::REG_CLIENT_DETACHED{ L"^%client-detached (\\S+)$" };
const std::wregex TmuxControl::REG_CONFIG_ERROR{ L"^%config-error (\\S+)$" };
const std::wregex TmuxControl::REG_CONTINUE{ L"^%continue %(\\d+)$" };
const std::wregex TmuxControl::REG_DETACH{ L"^\033$" };
const std::wregex TmuxControl::REG_EXIT{ L"^%exit$" };
const std::wregex TmuxControl::REG_EXTENDED_OUTPUT{ L"^%extended-output %(\\d+) (\\S+)$" };
const std::wregex TmuxControl::REG_LAYOUT_CHANGED{ L"^%layout-change @(\\d+) ([\\da-fA-F]{4}),(\\S+)( \\S+)*$" };
const std::wregex TmuxControl::REG_MESSAGE{ L"^%message (\\S+)$" };
const std::wregex TmuxControl::REG_OUTPUT{ L"^%output %(\\d+) (.+)$" };
const std::wregex TmuxControl::REG_PANE_MODE_CHANGED{ L"^%pane-mode-changed %(\\d+)$" };
const std::wregex TmuxControl::REG_PASTE_BUFFER_CHANGED{ L"^%paste-buffer-changed (\\S+)$" };
const std::wregex TmuxControl::REG_PASTE_BUFFER_DELETED{ L"^%paste-buffer-deleted (\\S+)$" };
const std::wregex TmuxControl::REG_PAUSE{ L"^%pause %(\\d+)$" };
const std::wregex TmuxControl::REG_SESSION_CHANGED{ L"^%"
L"session-changed \\$(\\d+) (\\S+)$" };
const std::wregex TmuxControl::REG_SESSION_RENAMED{ L"^%"
L"session-renamed (\\S+)$" };
const std::wregex TmuxControl::REG_SESSION_WINDOW_CHANGED{ L"^%"
L"session-window-changed @(\\d+) (\\d+)$" };
const std::wregex TmuxControl::REG_SESSIONS_CHANGED{ L"^%"
L"sessions-changed$" };
const std::wregex TmuxControl::REG_SUBSCRIPTION_CHANGED{ L"^%"
L"subscription-changed (\\S+)$" };
const std::wregex TmuxControl::REG_UNLINKED_WINDOW_ADD{ L"^%unlinked-window-add @(\\d+)$" };
const std::wregex TmuxControl::REG_UNLINKED_WINDOW_CLOSE{ L"^%unlinked-window-close @(\\d+)$" };
const std::wregex TmuxControl::REG_UNLINKED_WINDOW_RENAMED{ L"^%unlinked-window-renamed @(\\d+)$" };
const std::wregex TmuxControl::REG_WINDOW_ADD{ L"^%window-add @(\\d+)$" };
const std::wregex TmuxControl::REG_WINDOW_CLOSE{ L"^%window-close @(\\d+)$" };
const std::wregex TmuxControl::REG_WINDOW_PANE_CHANGED{ L"^%window-pane-changed @(\\d+) %(\\d+)$" };
const std::wregex TmuxControl::REG_WINDOW_RENAMED{ L"^%window-renamed @(\\d+) (\\S+)$" };
TmuxControl::TmuxControl(TerminalPage& page) :
_page(page)
{
@ -155,7 +182,7 @@ namespace winrt::TerminalApp::implementation
void TmuxControl::_AttachSession()
{
_state = ATTACHING;
_state = State::ATTACHING;
_SetupProfile();
@ -175,7 +202,7 @@ namespace winrt::TerminalApp::implementation
_terminalWidth = (int)((x - _thickness.Left - _thickness.Right) / fontSize.Width);
_terminalHeight = (int)((y - _thickness.Top - _thickness.Bottom) / fontSize.Height);
_SetOption(std::format(L"default-size {}x{}", _terminalWidth, _terminalHeight));
_SetOption(fmt::format(FMT_COMPILE(L"default-size {}x{}"), _terminalWidth, _terminalHeight));
for (auto& w : _attachedWindows)
{
_ResizeWindow(w.first, _terminalWidth, _terminalHeight);
@ -203,15 +230,16 @@ namespace winrt::TerminalApp::implementation
void TmuxControl::_DetachSession()
{
if (_state == INIT)
if (_state == State::INIT)
{
_inUse = false;
return;
}
_state = INIT;
_state = State::INIT;
_cmdQueue.clear();
_dcsBuffer.clear();
_cmdState = READY;
_cmdState = CommandState::READY;
std::vector<TerminalApp::Tab> tabs;
for (auto& w : _attachedWindows)
@ -297,9 +325,10 @@ namespace winrt::TerminalApp::implementation
textBlock.Inlines().Append(Documents::LineBreak{});
textBlock.Inlines().Append(newPaneRun);
_newTabMenu.Text(RS_(L"NewTmuxControlTab/Text"));
Controls::ToolTipService::SetToolTip(_newTabMenu, box_value(textBlock));
Controls::FontIcon newTabIcon{};
_newTabMenu.Text(RS_(L"NewTmuxControlTab/Text"));
Controls::FontIcon newTabIcon;
newTabIcon.Glyph(L"\xF714");
newTabIcon.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons,Segoe MDL2 Assets" });
_newTabMenu.Icon(newTabIcon);
@ -374,58 +403,60 @@ namespace winrt::TerminalApp::implementation
return;
}
auto DecodeOutput = [](const std::wstring& in, std::wstring& out) {
auto it = in.begin();
while (it != in.end())
{
wchar_t c = *it;
if (c == L'\\')
{
++it;
c = 0;
for (int i = 0; i < 3 && it != in.end(); ++i, ++it)
{
if (*it < L'0' || *it > L'7')
{
c = L'?';
break;
}
c = c * 8 + (*it - L'0');
}
out.push_back(c);
continue;
}
if (!search->second.initialized)
{
search->second.control.Initialized([this, paneId, text](auto& /*i*/, auto& /*e*/) {
_SendOutput(paneId, text);
});
return;
}
if (c == L'\n')
std::wstring out;
auto it = text.begin();
const auto end = text.end();
while (it != end)
{
// Find start of any potential \xxx sequence
const auto start = std::find(it, end, L'\\');
// Copy any regular text
out.append(it, start);
it = start;
if (it == end)
{
break;
}
// Process any \xxx sequences
while (it != end && *it == L'\\')
{
wchar_t c = 0;
int i = 0;
while (i < 3 && it != end)
{
out.push_back(L'\r');
if (*it < L'0' || *it > L'7')
{
c = L'?';
break;
}
c = c * 8 + (*it - L'0');
++i;
++it;
}
out.push_back(c);
++it;
}
};
auto& c = search->second.control;
if (search->second.initialized)
{
std::wstring out = L"";
DecodeOutput(text, out);
c.SendOutput(out);
}
else
{
std::wstring res(text);
c.Initialized([this, paneId, res](auto& /*i*/, auto& /*e*/) {
_SendOutput(paneId, res);
});
}
search->second.connection.WriteOutput(winrt_wstring_to_array_view(out));
}
void TmuxControl::_Output(int paneId, const std::wstring& result)
{
if (_state != ATTACHED)
if (_state != State::ATTACHED)
{
return;
}
@ -435,13 +466,13 @@ namespace winrt::TerminalApp::implementation
void TmuxControl::_CloseWindow(int windowId)
{
auto search = _attachedWindows.find(windowId);
const auto search = _attachedWindows.find(windowId);
if (search == _attachedWindows.end())
{
return;
}
TerminalApp::Tab t = search->second;
const auto t = search->second;
_attachedWindows.erase(search);
t.Shutdown();
@ -532,9 +563,7 @@ namespace winrt::TerminalApp::implementation
}
auto newSize = originSize / 2;
auto splitSize = _ComputeSplitSize(originSize - newSize, originSize, direction);
auto newPane = _NewPane(windowId, newPaneId);
auto [origin, newGuy] = tab.try_as<Tab>()->SplitPane(direction, splitSize, newPane);
@ -560,8 +589,8 @@ namespace winrt::TerminalApp::implementation
search->second.initialized = true;
});
connection.TerminalInput([this, paneId](auto keys) {
std::wstring out{ keys };
connection.TerminalInput([this, paneId](const winrt::array_view<const char16_t> keys) {
std::wstring out{ winrt_array_to_wstring_view(keys) };
_SendKey(paneId, out);
});
@ -582,7 +611,7 @@ namespace winrt::TerminalApp::implementation
});
control.SizeChanged([this, paneId, control](auto, const Xaml::SizeChangedEventArgs& args) {
if (_state != ATTACHED)
if (_state != State::ATTACHED)
{
return;
}
@ -601,7 +630,7 @@ namespace winrt::TerminalApp::implementation
_KillPane(paneId);
});
_attachedPanes.insert({ paneId, { windowId, paneId, control } });
_attachedPanes.insert({ paneId, { windowId, paneId, control, connection } });
return pane;
}
@ -815,41 +844,40 @@ namespace winrt::TerminalApp::implementation
{
switch (e.type)
{
case ATTACH:
case EventType::ATTACH:
_AttachSession();
break;
case DETACH:
case EventType::DETACH:
_DetachSession();
break;
case LAYOUT_CHANGED:
case EventType::LAYOUT_CHANGED:
_DiscoverPanes(_sessionId, e.windowId, false);
break;
case OUTPUT:
case EventType::OUTPUT:
_Output(e.paneId, e.response);
break;
// Commands response
case RESPONSE:
case EventType::RESPONSE:
_CommandHandler(e.response);
break;
case SESSION_CHANGED:
case EventType::SESSION_CHANGED:
_sessionId = e.sessionId;
_SetOption(std::format(L"default-size {}x{}", _terminalWidth, _terminalHeight));
_SetOption(fmt::format(FMT_COMPILE(L"default-size {}x{}"), _terminalWidth, _terminalHeight));
_DiscoverWindows(_sessionId);
break;
case WINDOW_ADD:
case EventType::WINDOW_ADD:
_DiscoverPanes(_sessionId, e.windowId, true);
break;
case WINDOW_CLOSE:
case UNLINKED_WINDOW_CLOSE:
case EventType::WINDOW_CLOSE:
case EventType::UNLINKED_WINDOW_CLOSE:
_CloseWindow(e.windowId);
break;
case WINDOW_PANE_CHANGED:
case EventType::WINDOW_PANE_CHANGED:
_SplitPaneFinalize(e.windowId, e.paneId);
break;
case WINDOW_RENAMED:
case EventType::WINDOW_RENAMED:
_RenameWindow(e.windowId, e.response);
break;
default:
break;
}
@ -860,98 +888,143 @@ namespace winrt::TerminalApp::implementation
void TmuxControl::_Parse(const std::wstring& line)
{
static const std::wregex REG_LAYOUT_CHANGED{ L"^%layout-change @(\\d+) ([\\da-fA-F]{4}),(\\S+)( \\S+)*$" };
static const std::wregex REG_OUTPUT{ L"^%output %(\\d+) (.+)$" };
static const std::wregex REG_SESSION_CHANGED{ L"^%session-changed \\$(\\d+) (\\S+)$" };
static const std::wregex REG_WINDOW_ADD{ L"^%window-add @(\\d+)$" };
static const std::wregex REG_WINDOW_CLOSE{ L"^%window-close @(\\d+)$" };
static const std::wregex REG_WINDOW_PANE_CHANGED{ L"^%window-pane-changed @(\\d+) %(\\d+)$" };
static const std::wregex REG_WINDOW_RENAMED{ L"^%window-renamed @(\\d+) (\\S+)$" };
static const std::wregex REG_UNLINKED_WINDOW_CLOSE{ L"^%unlinked-window-close @(\\d+)$" };
std::wsmatch matches;
std::wstring_view remaining{ line };
const auto type = tokenize_field(remaining);
// Tmux generic rules
if (std::regex_match(line, REG_BEGIN))
if (til::equals(type, L"%begin"))
{
_event.type = BEGIN;
_event.type = EventType::BEGIN;
}
else if (std::regex_match(line, REG_END))
else if (til::equals(type, L"%end"))
{
if (_state == INIT)
if (_state == State::INIT)
{
_event.type = ATTACH;
_event.type = EventType::ATTACH;
}
else
{
_event.type = RESPONSE;
_event.type = EventType::RESPONSE;
}
}
else if (std::regex_match(line, REG_ERROR))
else if (til::equals(type, L"%error"))
{
// Remove the extra '\n' we added
_Print(std::wstring(_event.response.begin(), _event.response.end() - 1));
_event.response.pop_back(); // Remove the extra '\n' we added
_Print(_event.response);
_event.response.clear();
_event.type = NOTHING;
_event.type = EventType::NOTHING;
}
// tmux specific rules
else if (std::regex_match(line, REG_DETACH))
else if (til::equals(type, L"\033"))
{
_event.type = DETACH;
_event.type = EventType::DETACH;
}
else if (std::regex_match(line, matches, REG_LAYOUT_CHANGED))
else if (til::equals(type, L"%layout-change"))
{
_event.windowId = std::stoi(matches.str(1));
_event.type = LAYOUT_CHANGED;
const auto id = tokenize_identifier(remaining);
if (id.type == IdentifierType::Window)
{
_event.windowId = id.value;
_event.type = EventType::LAYOUT_CHANGED;
}
}
else if (std::regex_match(line, matches, REG_OUTPUT))
else if (til::equals(type, L"%output"))
{
_event.paneId = std::stoi(matches.str(1));
_event.response = matches.str(2);
_event.type = OUTPUT;
const auto id = tokenize_identifier(remaining);
if (id.type == IdentifierType::Pane)
{
const auto payload = til::safe_slice_abs(remaining, 1, std::wstring_view::npos);
_event.paneId = id.value;
_event.response = payload;
_event.type = EventType::OUTPUT;
}
}
else if (std::regex_match(line, matches, REG_SESSION_CHANGED))
else if (til::equals(type, L"%session-changed"))
{
_event.type = SESSION_CHANGED;
_event.sessionId = std::stoi(matches.str(1));
const auto id = tokenize_identifier(remaining);
if (id.type == IdentifierType::Session)
{
_event.type = EventType::SESSION_CHANGED;
_event.sessionId = id.value;
}
}
else if (std::regex_match(line, matches, REG_WINDOW_ADD))
else if (til::equals(type, L"%window-add"))
{
_event.windowId = std::stoi(matches.str(1));
_event.type = WINDOW_ADD;
const auto id = tokenize_identifier(remaining);
if (id.type == IdentifierType::Window)
{
_event.windowId = id.value;
_event.type = EventType::WINDOW_ADD;
}
}
else if (std::regex_match(line, matches, REG_WINDOW_CLOSE))
else if (til::equals(type, L"%window-close"))
{
_event.type = WINDOW_CLOSE;
_event.windowId = std::stoi(matches.str(1));
const auto id = tokenize_identifier(remaining);
if (id.type == IdentifierType::Window)
{
_event.windowId = id.value;
_event.type = EventType::WINDOW_CLOSE;
}
}
else if (std::regex_match(line, matches, REG_WINDOW_PANE_CHANGED))
else if (til::equals(type, L"%window-pane-changed"))
{
_event.type = WINDOW_PANE_CHANGED;
_event.windowId = std::stoi(matches.str(1));
_event.paneId = std::stoi(matches.str(2));
const auto windowId = tokenize_identifier(remaining);
const auto paneId = tokenize_identifier(remaining);
if (windowId.type == IdentifierType::Window && paneId.type == IdentifierType::Pane)
{
_event.type = EventType::WINDOW_PANE_CHANGED;
_event.windowId = windowId.value;
_event.paneId = paneId.value;
}
}
else if (std::regex_match(line, matches, REG_WINDOW_RENAMED))
else if (til::equals(type, L"%window-renamed"))
{
_event.windowId = std::stoi(matches.str(1));
_event.response = matches.str(2);
_event.type = WINDOW_RENAMED;
const auto id = tokenize_identifier(remaining);
if (id.type == IdentifierType::Window)
{
const auto name = til::safe_slice_abs(remaining, 1, std::wstring_view::npos);
_event.windowId = id.value;
_event.response = name;
_event.type = EventType::WINDOW_RENAMED;
}
}
else if (std::regex_match(line, matches, REG_UNLINKED_WINDOW_CLOSE))
else if (til::equals(type, L"%unlinked-window-close"))
{
_event.type = UNLINKED_WINDOW_CLOSE;
_event.windowId = std::stoi(matches.str(1));
const auto id = tokenize_identifier(remaining);
if (id.type == IdentifierType::Window)
{
_event.type = EventType::UNLINKED_WINDOW_CLOSE;
_event.windowId = id.value;
}
}
else
{
if (_event.type == BEGIN)
if (_event.type == EventType::BEGIN)
{
_event.response += line + L'\n';
}
else
{
// Other events that we don't care, do nothing
_event.type = NOTHING;
_event.type = EventType::NOTHING;
}
}
if (_event.type != BEGIN && _event.type != NOTHING)
if (_event.type != EventType::BEGIN && _event.type != EventType::NOTHING)
{
auto& e = _event;
_dispatcherQueue.TryEnqueue([this, e]() {
_EventHandler(e);
_dispatcherQueue.TryEnqueue([this]() {
_EventHandler(_event);
});
_event.response.clear();
}
@ -962,7 +1035,7 @@ namespace winrt::TerminalApp::implementation
// From tmux to controller through the dcs. parse it per line.
bool TmuxControl::_Advance(wchar_t ch)
{
std::wstring buffer = L"";
std::wstring buffer;
switch (ch)
{
@ -998,7 +1071,7 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::AttachDone::GetCommand()
{
return std::wstring(std::format(L"list-session\n"));
return std::wstring(L"list-session\n");
}
bool TmuxControl::AttachDone::ResultHandler(const std::wstring& /*result*/, TmuxControl& tmux)
@ -1010,7 +1083,7 @@ namespace winrt::TerminalApp::implementation
}
else
{
tmux._state = ATTACHED;
tmux._state = State::ATTACHED;
}
return true;
@ -1029,7 +1102,7 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::CapturePane::GetCommand()
{
return std::wstring(std::format(L"capture-pane -p -t %{} -e -C -S {}\n", this->paneId, this->history * -1));
return std::wstring(fmt::format(FMT_COMPILE(L"capture-pane -p -t %{} -e -C -S {}\n"), this->paneId, this->history * -1));
}
bool TmuxControl::CapturePane::ResultHandler(const std::wstring& result, TmuxControl& tmux)
@ -1038,14 +1111,14 @@ namespace winrt::TerminalApp::implementation
std::wstring output = result;
output.pop_back();
// Put the cursor to right position
output += std::format(L"\033[{};{}H", this->cursorY + 1, this->cursorX + 1);
output += fmt::format(FMT_COMPILE(L"\033[{};{}H"), this->cursorY + 1, this->cursorX + 1);
tmux._SendOutput(this->paneId, output);
return true;
}
void TmuxControl::_DiscoverPanes(int sessionId, int windowId, bool newWindow)
{
if (_state != ATTACHED)
if (_state != State::ATTACHED)
{
return;
}
@ -1061,16 +1134,16 @@ namespace winrt::TerminalApp::implementation
{
if (!this->newWindow)
{
return std::wstring(std::format(L"list-panes -s -F '"
L"#{{pane_id}} #{{window_name}}"
L"' -t ${}\n",
return std::wstring(fmt::format(FMT_COMPILE(L"list-panes -s -F '"
L"#{{pane_id}} #{{window_name}}"
L"' -t ${}\n"),
this->sessionId));
}
else
{
return std::wstring(std::format(L"list-panes -F '"
L"#{{pane_id}} #{{window_name}}"
L"' -t @{}\n",
return std::wstring(fmt::format(FMT_COMPILE(L"list-panes -F '"
L"#{{pane_id}} #{{window_name}}"
L"' -t @{}\n"),
this->windowId));
}
}
@ -1137,9 +1210,9 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::DiscoverWindows::GetCommand()
{
return std::wstring(std::format(L"list-windows -F '"
L"#{{window_id}}"
L"' -t ${}\n",
return std::wstring(fmt::format(FMT_COMPILE(L"list-windows -F '"
L"#{{window_id}}"
L"' -t ${}\n"),
this->sessionId));
}
@ -1183,7 +1256,7 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::KillPane::GetCommand()
{
return std::wstring(std::format(L"kill-pane -t %{}\n", this->paneId));
return std::wstring(fmt::format(FMT_COMPILE(L"kill-pane -t %{}\n"), this->paneId));
}
void TmuxControl::_KillWindow(int windowId)
@ -1202,7 +1275,7 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::KillWindow::GetCommand()
{
return std::wstring(std::format(L"kill-window -t @{}\n", this->windowId));
return std::wstring(fmt::format(FMT_COMPILE(L"kill-window -t @{}\n"), this->windowId));
}
void TmuxControl::_ListPanes(int windowId, int history)
@ -1216,11 +1289,11 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::ListPanes::GetCommand()
{
return std::wstring(std::format(L"list-panes -F '"
L"#{{session_id}} #{{window_id}} #{{pane_id}} "
L"#{{cursor_x}} #{{cursor_y}} "
L"#{{pane_active}}"
L"' -t @{}\n",
return std::wstring(fmt::format(FMT_COMPILE(L"list-panes -F '"
L"#{{session_id}} #{{window_id}} #{{pane_id}} "
L"#{{cursor_x}} #{{cursor_y}} "
L"#{{pane_active}}"
L"' -t @{}\n"),
this->windowId));
}
@ -1269,14 +1342,14 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::ListWindow::GetCommand()
{
return std::wstring(std::format(L"list-windows -F '"
L"#{{session_id}} #{{window_id}} "
L"#{{window_width}} #{{window_height}} "
L"#{{window_active}} "
L"#{{window_layout}} "
L"#{{window_name}} "
L"#{{history_limit}}"
L"' -t ${}\n",
return std::wstring(fmt::format(FMT_COMPILE(L"list-windows -F '"
L"#{{session_id}} #{{window_id}} "
L"#{{window_width}} #{{window_height}} "
L"#{{window_active}} "
L"#{{window_layout}} "
L"#{{window_name}} "
L"#{{history_limit}}"
L"' -t ${}\n"),
this->sessionId));
}
@ -1344,7 +1417,7 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::ResizePane::GetCommand()
{
return std::wstring(std::format(L"resize-pane -x {} -y {} -t %{}\n", this->width, this->height, this->paneId));
return std::wstring(fmt::format(FMT_COMPILE(L"resize-pane -x {} -y {} -t %{}\n"), this->width, this->height, this->paneId));
}
void TmuxControl::_ResizeWindow(int windowId, int width, int height)
@ -1359,7 +1432,7 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::ResizeWindow::GetCommand()
{
return std::wstring(std::format(L"resize-window -x {} -y {} -t @{}\n", this->width, this->height, this->windowId));
return std::wstring(fmt::format(FMT_COMPILE(L"resize-window -x {} -y {} -t @{}\n"), this->width, this->height, this->windowId));
}
void TmuxControl::_SelectPane(int paneId)
@ -1372,7 +1445,7 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::SelectPane::GetCommand()
{
return std::wstring(std::format(L"select-pane -t %{}\n", this->paneId));
return std::wstring(fmt::format(FMT_COMPILE(L"select-pane -t %{}\n"), this->paneId));
}
void TmuxControl::_SelectWindow(int windowId)
@ -1385,7 +1458,7 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::SelectWindow::GetCommand()
{
return std::wstring(std::format(L"select-window -t @{}\n", this->windowId));
return std::wstring(fmt::format(FMT_COMPILE(L"select-window -t @{}\n"), this->windowId));
}
void TmuxControl::_SendKey(int paneId, const std::wstring keys)
@ -1400,13 +1473,13 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::SendKey::GetCommand()
{
std::wstring out = L"";
std::wstring out;
for (auto& c : this->keys)
{
out += std::format(L"{:#x} ", c);
out += fmt::format(FMT_COMPILE(L"{:#x} "), c);
}
return std::wstring(std::format(L"send-key -t %{} {}\n", this->paneId, out));
return std::wstring(fmt::format(FMT_COMPILE(L"send-key -t %{} {}\n"), this->paneId, out));
}
void TmuxControl::_SetOption(const std::wstring& option)
@ -1419,7 +1492,7 @@ namespace winrt::TerminalApp::implementation
std::wstring TmuxControl::SetOption::GetCommand()
{
return std::wstring(std::format(L"set-option {}\n", this->option));
return std::wstring(fmt::format(FMT_COMPILE(L"set-option {}\n"), this->option));
}
void TmuxControl::_SplitPane(std::shared_ptr<Pane> pane, SplitDirection direction)
@ -1460,23 +1533,23 @@ namespace winrt::TerminalApp::implementation
{
if (this->direction == SplitDirection::Right)
{
return std::wstring(std::format(L"split-window -h -t %{}\n", this->paneId));
return std::wstring(fmt::format(FMT_COMPILE(L"split-window -h -t %{}\n"), this->paneId));
}
else
{
return std::wstring(std::format(L"split-window -v -t %{}\n", this->paneId));
return std::wstring(fmt::format(FMT_COMPILE(L"split-window -v -t %{}\n"), this->paneId));
}
}
// From controller to tmux
void TmuxControl::_CommandHandler(const std::wstring& result)
{
if (_cmdState == WAITING && _cmdQueue.size() > 0)
if (_cmdState == CommandState::WAITING && _cmdQueue.size() > 0)
{
auto cmd = _cmdQueue.front().get();
cmd->ResultHandler(result, *this);
_cmdQueue.pop_front();
_cmdState = READY;
_cmdState = CommandState::READY;
}
}
@ -1487,14 +1560,14 @@ namespace winrt::TerminalApp::implementation
void TmuxControl::_ScheduleCommand()
{
if (_cmdState != READY)
if (_cmdState != CommandState::READY)
{
return;
}
if (_cmdQueue.size() > 0)
{
_cmdState = WAITING;
_cmdState = CommandState::WAITING;
auto cmd = _cmdQueue.front().get();
auto cmdStr = cmd->GetCommand();

View File

@ -28,51 +28,20 @@ namespace winrt::TerminalApp::implementation
void SplitPane(const winrt::com_ptr<Tab>& tab, SplitDirection direction);
private:
static const std::wregex REG_BEGIN;
static const std::wregex REG_END;
static const std::wregex REG_ERROR;
static const std::wregex REG_CLIENT_SESSION_CHANGED;
static const std::wregex REG_CLIENT_DETACHED;
static const std::wregex REG_CONFIG_ERROR;
static const std::wregex REG_CONTINUE;
static const std::wregex REG_DETACH;
static const std::wregex REG_EXIT;
static const std::wregex REG_EXTENDED_OUTPUT;
static const std::wregex REG_LAYOUT_CHANGED;
static const std::wregex REG_MESSAGE;
static const std::wregex REG_OUTPUT;
static const std::wregex REG_PANE_MODE_CHANGED;
static const std::wregex REG_PASTE_BUFFER_CHANGED;
static const std::wregex REG_PASTE_BUFFER_DELETED;
static const std::wregex REG_PAUSE;
static const std::wregex REG_SESSION_CHANGED;
static const std::wregex REG_SESSION_RENAMED;
static const std::wregex REG_SESSION_WINDOW_CHANGED;
static const std::wregex REG_SESSIONS_CHANGED;
static const std::wregex REG_SUBSCRIPTION_CHANGED;
static const std::wregex REG_UNLINKED_WINDOW_ADD;
static const std::wregex REG_UNLINKED_WINDOW_CLOSE;
static const std::wregex REG_UNLINKED_WINDOW_RENAMED;
static const std::wregex REG_WINDOW_ADD;
static const std::wregex REG_WINDOW_CLOSE;
static const std::wregex REG_WINDOW_PANE_CHANGED;
static const std::wregex REG_WINDOW_RENAMED;
enum State : int
enum class State : int
{
INIT,
ATTACHING,
ATTACHED,
} _state{ INIT };
};
enum CommandState : int
enum class CommandState : int
{
READY,
WAITING,
} _cmdState{ READY };
};
enum EventType : int
enum class EventType : int
{
BEGIN,
END,
@ -80,29 +49,12 @@ namespace winrt::TerminalApp::implementation
ATTACH,
DETACH,
CLIENT_SESSION_CHANGED,
CLIENT_DETACHED,
CONFIG_ERROR,
CONTINUE,
EXIT,
EXTENDED_OUTPUT,
LAYOUT_CHANGED,
NOTHING,
MESSAGE,
OUTPUT,
PANE_MODE_CHANGED,
PASTE_BUFFER_CHANGED,
PASTE_BUFFER_DELETED,
PAUSE,
RESPONSE,
SESSION_CHANGED,
SESSION_RENAMED,
SESSION_WINDOW_CHANGED,
SESSIONS_CHANGED,
SUBSCRIPTION_CHANGED,
UNLINKED_WINDOW_ADD,
UNLINKED_WINDOW_CLOSE,
UNLINKED_WINDOW_RENAMED,
WINDOW_ADD,
WINDOW_CLOSE,
WINDOW_PANE_CHANGED,
@ -111,13 +63,13 @@ namespace winrt::TerminalApp::implementation
struct Event
{
EventType type{ NOTHING };
EventType type{ EventType::NOTHING };
int sessionId{ -1 };
int windowId{ -1 };
int paneId{ -1 };
std::wstring response;
} _event;
};
// Command structs
struct Command
@ -321,6 +273,7 @@ namespace winrt::TerminalApp::implementation
int windowId;
int paneId;
winrt::Microsoft::Terminal::Control::TermControl control;
winrt::Microsoft::Terminal::TerminalConnection::TmuxConnection connection;
bool initialized{ false };
};
@ -373,8 +326,11 @@ namespace winrt::TerminalApp::implementation
void _ScheduleCommand();
// Private variables
State _state{ State::INIT };
CommandState _cmdState{ CommandState::READY };
Event _event;
TerminalPage& _page;
winrt::Microsoft::Terminal::Settings::Model::Profile _profile;
winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr };
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
TerminalApp::Tab _controlTab{ nullptr };
winrt::Windows::System::DispatcherQueue _dispatcherQueue{ nullptr };
@ -383,7 +339,7 @@ namespace winrt::TerminalApp::implementation
winrt::event_token _windowSizeChangedRevoker;
winrt::event_token _newTabClickRevoker;
::winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _newTabMenu{};
::winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _newTabMenu;
std::vector<wchar_t> _dcsBuffer;
std::deque<std::unique_ptr<TmuxControl::Command>> _cmdQueue;

View File

@ -95,9 +95,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:
@ -113,7 +119,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 (...)
{
@ -163,13 +169,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))
{
@ -212,19 +218,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;
@ -430,7 +436,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:
@ -773,7 +779,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
{

View File

@ -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);

View File

@ -478,31 +478,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.
@ -521,7 +518,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();
}
@ -793,7 +790,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
try
{
TerminalOutput.raise(wstr);
TerminalOutput.raise(winrt_wstring_to_array_view(wstr));
}
CATCH_LOG();
}

View File

@ -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

View File

@ -13,7 +13,7 @@ namespace Microsoft.Terminal.TerminalConnection
Failed
};
delegate void TerminalOutputHandler(String output);
delegate void TerminalOutputHandler(Char[] output);
interface ITerminalConnection
{

View File

@ -11,19 +11,17 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
TmuxConnection::TmuxConnection() noexcept = default;
void TmuxConnection::Initialize(const Windows::Foundation::Collections::ValueSet&) const noexcept
{
}
void TmuxConnection::Start() noexcept
{
}
void TmuxConnection::WriteInput(const winrt::array_view<const char16_t> buffer)
{
const auto data = winrt_array_to_wstring_view(buffer);
std::wstringstream prettyPrint;
for (const auto& wch : data)
{
prettyPrint << wch;
}
TerminalInput.raise(prettyPrint.str());
TerminalInput.raise(buffer);
}
void TmuxConnection::Resize(uint32_t /*rows*/, uint32_t /*columns*/) noexcept
@ -33,4 +31,22 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
void TmuxConnection::Close() noexcept
{
}
winrt::guid TmuxConnection::SessionId() const noexcept
{
return {};
}
ConnectionState TmuxConnection::State() const noexcept
{
return ConnectionState::Connected;
}
void TmuxConnection::WriteOutput(const winrt::array_view<const char16_t> wstr)
{
if (!wstr.empty())
{
TerminalOutput.raise(wstr);
}
}
}

View File

@ -7,25 +7,30 @@
namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
struct TmuxConnection : DummyConnectionT<TmuxConnection>
struct TmuxConnection : TmuxConnectionT<TmuxConnection>
{
TmuxConnection() noexcept;
// ---- ITerminalConnection methods ----
void Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/) const noexcept;
void Start() noexcept;
void WriteInput(const winrt::array_view<const char16_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::event<TerminalOutputHandler> TerminalInput;
til::typed_event<ITerminalConnection, IInspectable> StateChanged;
bool _rawMode{ false };
winrt::guid SessionId() const noexcept;
ConnectionState State() const noexcept;
// ---- TmuxConnection methods ----
void WriteOutput(const winrt::array_view<const char16_t> wstr);
til::event<TerminalOutputHandler> TerminalInput;
};
}

View File

@ -9,6 +9,8 @@ namespace Microsoft.Terminal.TerminalConnection
runtimeclass TmuxConnection : ITerminalConnection
{
TmuxConnection();
void WriteOutput(Char[] data);
event TerminalOutputHandler TerminalInput;
};
}

View File

@ -495,17 +495,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void ControlCore::SendOutput(const std::wstring_view wstr)
{
if (wstr.empty())
{
return;
}
auto lock = _terminal->LockForWriting();
_terminal->Write(wstr);
}
bool ControlCore::SendCharEvent(const wchar_t ch,
const WORD scanCode,
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers)
@ -2238,13 +2227,13 @@ 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 char16_t> str)
{
try
{
{
const auto lock = _terminal->LockForWriting();
_terminal->Write(hstr);
_terminal->Write(winrt_array_to_wstring_view(str));
}
if (!_pendingResponses.empty())

View File

@ -126,7 +126,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
til::color BackgroundColor() const;
void SendInput(std::wstring_view wstr);
void SendOutput(std::wstring_view wstr);
void PasteText(const winrt::hstring& hstr);
bool CopySelectionToClipboard(bool singleLine, bool withControlSequences, const CopyFormat formats);
void SelectAll();
@ -354,7 +353,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _raiseReadOnlyWarning();
void _updateAntiAliasingMode();
void _connectionOutputHandler(const hstring& hstr);
void _connectionOutputHandler(winrt::array_view<const char16_t> str);
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);

View File

@ -131,7 +131,6 @@ namespace Microsoft.Terminal.Control
Int16 scanCode,
Microsoft.Terminal.Core.ControlKeyStates modifiers);
void SendInput(String text);
void SendOutput(String text);
void PasteText(String text);
void SelectAll();
void ClearSelection();

View File

@ -903,10 +903,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
RawWriteString(wstr);
}
void TermControl::SendOutput(const winrt::hstring& wstr)
{
_core.SendOutput(wstr);
}
void TermControl::ClearBuffer(Control::ClearBufferType clearType)
{
_core.ClearBuffer(clearType);

View File

@ -130,7 +130,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::Windows::Foundation::Size GetFontSize() const;
void SendInput(const winrt::hstring& input);
void SendOutput(const winrt::hstring& input);
void ClearBuffer(Control::ClearBufferType clearType);
void ToggleShaderEffects();

View File

@ -127,7 +127,6 @@ namespace Microsoft.Terminal.Control
void ToggleShaderEffects();
void SendInput(String input);
void SendOutput(String input);
Boolean RawWriteKeyEvent(UInt16 vkey, UInt16 scanCode, Microsoft.Terminal.Core.ControlKeyStates modifiers, Boolean keyDown);
Boolean RawWriteChar(Char character, UInt16 scanCode, Microsoft.Terminal.Core.ControlKeyStates modifiers);
void RawWriteString(String text);

View File

@ -29,10 +29,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
@ -51,7 +52,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
}
void PreviewConnection::DisplayPowerlineGlyphs(bool d) noexcept
void PreviewConnection::DisplayPowerlineGlyphs(bool d)
{
if (_displayPowerlineGlyphs != d)
{

View File

@ -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<const char16_t> 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; }

View File

@ -168,7 +168,41 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
template<typename T, typename Traits>
bool equals(const std::basic_string_view<T, Traits>& lhs, const std::basic_string_view<T, Traits>& rhs) noexcept
{
return lhs.size() == rhs.size() && __builtin_memcmp(lhs.data(), rhs.data(), lhs.size() * sizeof(T)) == 0;
// MSVC can only optimize 1 pattern into a bunch of simple comparison instructions:
// size1 == size2 && memcmp(data1, data2, size1/2) == 0
// If you introduce a `* sizeof(T)` into the size parameter to memcmp,
// it'll refuse to inline the memcmp call, resulting in much worse codegen.
// As a trade-off we multiply both sizes by sizeof(T) in advance.
// The extra addition instruction is comparatively very cheap.
const auto ls = lhs.size() * sizeof(T);
const auto rs = rhs.size() * sizeof(T);
return ls == rs && __builtin_memcmp(lhs.data(), rhs.data(), ls) == 0;
}
inline bool equals(const std::string_view& lhs, const std::string_view& rhs) noexcept
{
return equals<>(lhs, rhs);
}
inline bool equals(const std::wstring_view& lhs, const std::wstring_view& rhs) noexcept
{
return equals<>(lhs, rhs);
}
// An extra overload that undoes the quirk in the main equals() implementation.
// It's not really needed, except for being neat. This function in particular
// is often the best, easy way to do something like:
// match str {
// "foo" => ...,
// "bar" => ...,
// }
// with:
// if (til::equals(str, "foo")) { ... }
// else if (til::equals(str, "bar")) { ... }
template<typename T, typename Traits, size_t N>
constexpr bool equals(const std::basic_string_view<T, Traits>& lhs, const T (&rhs)[N]) noexcept
{
return lhs.size() == (N - 1) && __builtin_memcmp(lhs.data(), rhs, (N - 1) * sizeof(T)) == 0;
}
// Just like _memicmp, but without annoying locales.