mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
wip
This commit is contained in:
parent
ef23e6676c
commit
a804faedda
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -13,7 +13,7 @@ namespace Microsoft.Terminal.TerminalConnection
|
||||
Failed
|
||||
};
|
||||
|
||||
delegate void TerminalOutputHandler(String output);
|
||||
delegate void TerminalOutputHandler(Char[] output);
|
||||
|
||||
interface ITerminalConnection
|
||||
{
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,8 @@ namespace Microsoft.Terminal.TerminalConnection
|
||||
runtimeclass TmuxConnection : ITerminalConnection
|
||||
{
|
||||
TmuxConnection();
|
||||
|
||||
void WriteOutput(Char[] data);
|
||||
event TerminalOutputHandler TerminalInput;
|
||||
};
|
||||
}
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user