Leonard Hecker cb48babe9d
Implement grapheme clusters (#16916)
First, this adds `GraphemeTableGen` which
* parses `ucd.nounihan.grouped.xml`
* computes the cluster break property for each codepoint
* computes the East Asian Width property for each codepoint
* compresses everything into a 4-stage trie
* computes a LUT of cluster break rules between 2 codepoints
* and serializes everything to C++ tables and helper functions

Next, this adds `GraphemeTestTableGen` which
* parses `GraphemeBreakTest.txt`
* splits each test into graphemes and break opportunities
* and serializes everything to a C++ table for use as unit tests

`CodepointWidthDetector.cpp` was rewritten from scratch to
* use an iterator struct (`GraphemeState`) to maintain state
* accumulate codepoints until a break opportunity arises
* accumulate the total width of a grapheme
* support 3 different measurement modes: Grapheme clusters,
  `wcswidth`-style, and a mode identical to the old conhost

With this in place the following changes were made:
* `ROW::WriteHelper::_replaceTextUnicode` now uses the new
  grapheme cluster text iterators
* The same function was modified to join new text with existing
  contents of the current cell if they join to form a cluster
* Otherwise, a ton of places were modified to funnel the selection
  of the measurement mode over from WT's settings to ConPTY

This is part of #1472

## Validation Steps Performed
* So many tests 
* https://github.com/apparebit/demicode works fantastic 
* UTF8-torture-test.txt works fantastic 
2024-06-26 18:40:27 +00:00

115 lines
4.6 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "ConptyConnection.g.h"
#include "BaseTerminalConnection.h"
#include "ITerminalHandoff.h"
#include <til/env.h>
namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
struct ConptyConnection : ConptyConnectionT<ConptyConnection>, BaseTerminalConnection<ConptyConnection>
{
ConptyConnection(const HANDLE hSig,
const HANDLE hIn,
const HANDLE hOut,
const HANDLE hRef,
const HANDLE hServerProcess,
const HANDLE hClientProcess,
const TERMINAL_STARTUP_INFO& startupInfo);
ConptyConnection() noexcept = default;
void Initialize(const Windows::Foundation::Collections::ValueSet& settings);
static winrt::fire_and_forget final_release(std::unique_ptr<ConptyConnection> connection);
void Start();
void WriteInput(const hstring& data);
void Resize(uint32_t rows, uint32_t columns);
void Close() noexcept;
void ClearBuffer();
void ShowHide(const bool show);
void ReparentWindow(const uint64_t newParent);
winrt::hstring Commandline() const;
winrt::hstring StartingTitle() const;
WORD ShowWindow() const noexcept;
static void StartInboundListener();
static void StopInboundListener();
static winrt::event_token NewConnection(const NewConnectionHandler& handler);
static void NewConnection(const winrt::event_token& token);
static Windows::Foundation::Collections::ValueSet CreateSettings(const winrt::hstring& cmdline,
const winrt::hstring& startingDirectory,
const winrt::hstring& startingTitle,
bool reloadEnvironmentVariables,
const winrt::hstring& initialEnvironment,
const Windows::Foundation::Collections::IMapView<hstring, hstring>& environmentOverrides,
uint32_t rows,
uint32_t columns,
const winrt::guid& guid,
const winrt::guid& profileGuid);
til::event<TerminalOutputHandler> TerminalOutput;
private:
static void closePseudoConsoleAsync(HPCON hPC) noexcept;
static HRESULT NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client, TERMINAL_STARTUP_INFO startupInfo) noexcept;
static winrt::hstring _commandlineFromProcess(HANDLE process);
HRESULT _LaunchAttachedClient() noexcept;
void _indicateExitWithStatus(unsigned int status) noexcept;
void _LastConPtyClientDisconnected() noexcept;
til::CoordType _rows{};
til::CoordType _cols{};
uint64_t _initialParentHwnd{ 0 };
hstring _commandline{};
hstring _startingDirectory{};
hstring _startingTitle{};
bool _initialVisibility{ true };
Windows::Foundation::Collections::ValueSet _environment{ nullptr };
hstring _clientName{}; // The name of the process hosted by this ConPTY connection (as of launch).
bool _receivedFirstByte{ false };
std::chrono::high_resolution_clock::time_point _startTime{};
wil::unique_hfile _inPipe; // The pipe for writing input to
wil::unique_hfile _outPipe; // The pipe for reading output from
wil::unique_handle _hOutputThread;
wil::unique_process_information _piClient;
wil::unique_any<HPCON, decltype(closePseudoConsoleAsync), closePseudoConsoleAsync> _hPC;
til::u8state _u8State{};
std::wstring _u16Str{};
std::array<char, 4096> _buffer{};
DWORD _flags{ 0 };
til::env _initialEnv{};
guid _profileGuid{};
struct StartupInfoFromDefTerm
{
winrt::hstring title{};
winrt::hstring iconPath{};
int32_t iconIndex{};
WORD showWindow{};
} _startupInfo{};
DWORD _OutputThread();
};
}
namespace winrt::Microsoft::Terminal::TerminalConnection::factory_implementation
{
BASIC_FACTORY(ConptyConnection);
}