terminal/src/renderer/vt/WinTelnetEngine.cpp
Mike Griese dec5c11e19
Add support for passing through extended text attributes, like… (#2917)
## Summary of the Pull Request
Adds support for Italics, Blinking, Invisible, CrossedOut text, THROUGH CONPTY. This does **NOT** add support for those styles to conhost or the terminal.

We will store these "Extended Text Attributes" in a `TextAttribute`. When we go to render a line, we'll see if the state has changed from our previous state, and if so, we'll appropriately toggle that state with VT. Boldness has been moved from a `bool` to a single bit in these flags.

Technically, now that these are stored in the buffer, we only need to make changes to the renderers to be able to support them. That's not being done as a part of this PR however.

## References
See also #2915 and #2916, which are some follow-up tasks from this fix. I thought them too risky for 20H1.

## PR Checklist
* [x] Closes #2554
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated


<hr>

* store text with extended attributes too

* Plumb attributes through all the renderers

* parse extended attrs, though we're not renderering them right

* Render these states correctly

* Add a very extensive test

* Cleanup for PR

* a block of PR feedback

* add 512 test cases

* Fix the build

* Fix @carlos-zamora's suggestions

* @miniksa's PR feedback
2019-10-04 15:53:54 -05:00

117 lines
4.9 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "WinTelnetEngine.hpp"
#include "..\..\inc\conattrs.hpp"
#pragma hdrstop
using namespace Microsoft::Console;
using namespace Microsoft::Console::Render;
using namespace Microsoft::Console::Types;
WinTelnetEngine::WinTelnetEngine(_In_ wil::unique_hfile hPipe,
wil::shared_event shutdownEvent,
const IDefaultColorProvider& colorProvider,
const Viewport initialViewport,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable) :
VtEngine(std::move(hPipe), shutdownEvent, colorProvider, initialViewport),
_ColorTable(ColorTable),
_cColorTable(cColorTable)
{
}
// Routine Description:
// - Write a VT sequence to change the current colors of text. Only writes
// 16-color attributes.
// Arguments:
// - colorForeground: The RGB Color to use to paint the foreground text.
// - colorBackground: The RGB Color to use to paint the background of the text.
// - legacyColorAttribute: A console attributes bit field specifying the brush
// colors we should use.
// - extendedAttrs - extended text attributes (italic, underline, etc.) to use.
// - isSettingDefaultBrushes: indicates if we should change the background color of
// the window. Unused for VT
// Return Value:
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
[[nodiscard]] HRESULT WinTelnetEngine::UpdateDrawingBrushes(const COLORREF colorForeground,
const COLORREF colorBackground,
const WORD /*legacyColorAttribute*/,
const ExtendedAttributes extendedAttrs,
const bool /*isSettingDefaultBrushes*/) noexcept
{
return VtEngine::_16ColorUpdateDrawingBrushes(colorForeground,
colorBackground,
WI_IsFlagSet(extendedAttrs, ExtendedAttributes::Bold),
_ColorTable,
_cColorTable);
}
// Routine Description:
// - Write a VT sequence to move the cursor to the specified coordinates. We
// also store the last place we left the cursor for future optimizations.
// Arguments:
// - coord: location to move the cursor to.
// Return Value:
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
[[nodiscard]] HRESULT WinTelnetEngine::_MoveCursor(COORD const coord) noexcept
{
HRESULT hr = S_OK;
// don't try and be clever about moving the cursor.
// Always just use the full sequence
if (coord.X != _lastText.X || coord.Y != _lastText.Y)
{
hr = _CursorPosition(coord);
if (SUCCEEDED(hr))
{
_lastText = coord;
}
}
return hr;
}
// Routine Description:
// - Scrolls the existing data on the in-memory frame by the scroll region
// deltas we have collectively received through the Invalidate methods
// since the last time this was called.
// Because win-telnet doesn't know how to do anything smart in response to
// scrolling, we do nothing.
// Arguments:
// - <none>
// Return Value:
// - S_OK
[[nodiscard]] HRESULT WinTelnetEngine::ScrollFrame() noexcept
{
// win-telnet doesn't know anything about scroll vt sequences
// every frame, we're repainitng everything, always.
return S_OK;
}
// Routine Description:
// - Notifies us that the console is attempting to scroll the existing screen
// area
// Arguments:
// - pcoordDelta - Pointer to character dimension (COORD) of the distance the
// console would like us to move while scrolling.
// Return Value:
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
[[nodiscard]] HRESULT WinTelnetEngine::InvalidateScroll(const COORD* const /*pcoordDelta*/) noexcept
{
// win-telnet assumes the client doesn't know anything about inserting or
// deleting lines.
// So instead, just invalidate the entire viewport. Every line is going to
// have to move.
return InvalidateAll();
}
// Method Description:
// - Wrapper for ITerminalOutputConnection. Write an ascii-only string to the pipe.
// Arguments:
// - wstr - wstring of text to be written
// Return Value:
// - S_OK or suitable HRESULT error from either conversion or writing pipe.
[[nodiscard]] HRESULT WinTelnetEngine::WriteTerminalW(_In_ const std::wstring& wstr) noexcept
{
return VtEngine::_WriteTerminalAscii(wstr);
}