terminal/src/cascadia/TerminalApp/DebugTapConnection.cpp
Carlos Zamora 2608e94822
Introduce TerminalSettingsModel project (#7667)
Introduces a new TerminalSettingsModel (TSM) project. This project is
responsible for (de)serializing and exposing Windows Terminal's settings
as WinRT objects.

## References
#885: TSM epic
#1564: Settings UI is dependent on this for data binding and settings access
#6904: TSM Spec

In the process of ripping out TSM from TerminalApp, a few other changes
were made to make this possible:
1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was
   moved to `CascadiaSettings`
   - These are defined as static functions. They also no longer check if
     `AppLogic::Current()` is nullptr.
2. `enum LaunchMode` was moved from TerminalApp to TSM
3. `AzureConnectionType` and `TelnetConnectionType` were moved from the
   profile generators to their respective TerminalConnections
4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are
   exposed as `hstring` instead of `std::filesystem::path`
5. `Command::ExpandCommands()` was exposed via the IDL
   - This required some of the warnings to be saved to an `IVector`
     instead of `std::vector`, among some other small changes.
6. The localization resources had to be split into two halves.
   - Resource file linked in init.cpp. Verified at runtime thanks to the
     StaticResourceLoader.
7. Added constructors to some `ActionArgs`
8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to
   `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp.

A large amount of work includes moving to the new namespace
(`TerminalApp` --> `Microsoft::Terminal::Settings::Model`).

Fixing the tests had its own complications. Testing required us to split
up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a
non-local test variant can be found in #7743.

Closes #885
2020-10-06 09:56:59 -07:00

127 lines
5 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "DebugTapConnection.h"
using namespace ::winrt::Microsoft::Terminal::TerminalConnection;
using namespace ::winrt::Windows::Foundation;
namespace winrt::Microsoft::TerminalApp::implementation
{
// DebugInputTapConnection is an implementation detail of DebugTapConnection.
// It wraps the _actual_ connection so it can hook WriteInput and forward it
// into the actual debug panel.
class DebugInputTapConnection : public winrt::implements<DebugInputTapConnection, ITerminalConnection>
{
public:
DebugInputTapConnection(winrt::com_ptr<DebugTapConnection> pairedTap, ITerminalConnection wrappedConnection) :
_pairedTap{ pairedTap },
_wrappedConnection{ std::move(wrappedConnection) }
{
}
~DebugInputTapConnection() = default;
void Start()
{
_wrappedConnection.Start();
}
void WriteInput(hstring const& data)
{
_pairedTap->_PrintInput(data);
_wrappedConnection.WriteInput(data);
}
void Resize(uint32_t rows, uint32_t columns) { _wrappedConnection.Resize(rows, columns); }
void Close() { _wrappedConnection.Close(); }
winrt::event_token TerminalOutput(TerminalOutputHandler const& args) { return _wrappedConnection.TerminalOutput(args); };
void TerminalOutput(winrt::event_token const& token) noexcept { _wrappedConnection.TerminalOutput(token); };
winrt::event_token StateChanged(TypedEventHandler<ITerminalConnection, IInspectable> const& handler) { return _wrappedConnection.StateChanged(handler); };
void StateChanged(winrt::event_token const& token) noexcept { _wrappedConnection.StateChanged(token); };
ConnectionState State() const noexcept { return _wrappedConnection.State(); }
private:
winrt::com_ptr<DebugTapConnection> _pairedTap;
ITerminalConnection _wrappedConnection;
};
DebugTapConnection::DebugTapConnection(ITerminalConnection wrappedConnection)
{
_outputRevoker = wrappedConnection.TerminalOutput(winrt::auto_revoke, { this, &DebugTapConnection::_OutputHandler });
_stateChangedRevoker = wrappedConnection.StateChanged(winrt::auto_revoke, [this](auto&& /*s*/, auto&& /*e*/) {
_StateChangedHandlers(*this, nullptr);
});
_wrappedConnection = wrappedConnection;
}
DebugTapConnection::~DebugTapConnection()
{
}
void DebugTapConnection::Start()
{
// presume the wrapped connection is started.
}
void DebugTapConnection::WriteInput(hstring const& data)
{
// If the user types into the tap side, forward it to the input side
if (auto strongInput{ _inputSide.get() })
{
auto inputAsTap{ winrt::get_self<DebugInputTapConnection>(strongInput) };
inputAsTap->WriteInput(data);
}
}
void DebugTapConnection::Resize(uint32_t /*rows*/, uint32_t /*columns*/)
{
// no resize events are propagated
}
void DebugTapConnection::Close()
{
_outputRevoker.revoke();
_stateChangedRevoker.revoke();
_wrappedConnection = nullptr;
}
ConnectionState DebugTapConnection::State() const noexcept
{
if (auto strongConnection{ _wrappedConnection.get() })
{
return strongConnection.State();
}
return ConnectionState::Failed;
}
void DebugTapConnection::_OutputHandler(const hstring str)
{
_TerminalOutputHandlers(til::visualize_control_codes(str));
}
// Called by the DebugInputTapConnection to print user input
void DebugTapConnection::_PrintInput(const hstring& str)
{
auto clean{ til::visualize_control_codes(str) };
auto formatted{ wil::str_printf<std::wstring>(L"\x1b[91m%ls\x1b[m", clean.data()) };
_TerminalOutputHandlers(formatted);
}
// Wire us up so that we can forward input through
void DebugTapConnection::SetInputTap(const Microsoft::Terminal::TerminalConnection::ITerminalConnection& inputTap)
{
_inputSide = inputTap;
}
}
// Function Description
// - Takes one connection and returns two connections:
// 1. One that can be used in place of the original connection (wrapped)
// 2. One that will print raw VT sequences sent into and received _from_ the original connection.
std::tuple<ITerminalConnection, ITerminalConnection> OpenDebugTapConnection(ITerminalConnection baseConnection)
{
using namespace winrt::Microsoft::TerminalApp::implementation;
auto debugSide{ winrt::make_self<DebugTapConnection>(baseConnection) };
auto inputSide{ winrt::make_self<DebugInputTapConnection>(debugSide, baseConnection) };
debugSide->SetInputTap(*inputSide);
std::tuple<ITerminalConnection, ITerminalConnection> p{ *inputSide, *debugSide };
return p;
}