Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OSC 8 support for conhost and terminal #7251

Merged
merged 35 commits into from
Sep 3, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
16720a0
osc 8 support for conhost and terminal
PankajBhojwani Aug 11, 2020
51bd477
Correctly gets buffer position on click now
PankajBhojwani Aug 11, 2020
d268322
small fixes
PankajBhojwani Aug 12, 2020
3090b1c
more small fixes
PankajBhojwani Aug 12, 2020
b81014e
Merge branch 'master' of https://github.com/microsoft/terminal into d…
PankajBhojwani Aug 12, 2020
015fb8f
tryna pass pipeline checks
PankajBhojwani Aug 12, 2020
4a74f83
send event upon hyperlink click, allow custom ids, remove obsolete re…
PankajBhojwani Aug 15, 2020
049ee61
text buffer tests
PankajBhojwani Aug 17, 2020
c18f32a
spell
PankajBhojwani Aug 17, 2020
bd74eff
output engine test
PankajBhojwani Aug 17, 2020
0327750
more tests
PankajBhojwani Aug 17, 2020
405066e
resolve conflict
PankajBhojwani Aug 17, 2020
5995275
fixes
PankajBhojwani Aug 18, 2020
409b358
some requested changes
PankajBhojwani Aug 18, 2020
dfc8771
more changes
PankajBhojwani Aug 18, 2020
c28d2a6
conflict resolution
PankajBhojwani Aug 19, 2020
8a105d7
bug fix
PankajBhojwani Aug 19, 2020
7e96737
small changes
PankajBhojwani Aug 21, 2020
e19fbe5
fixed hyperlink not working after resize
PankajBhojwani Aug 21, 2020
bc70439
fixes
PankajBhojwani Aug 21, 2020
9d65b32
noexcept
PankajBhojwani Aug 21, 2020
aefb2e0
more noexcept
PankajBhojwani Aug 21, 2020
d0de3d5
except
PankajBhojwani Aug 21, 2020
eb3cda5
optimize prune hyperlinks
PankajBhojwani Aug 21, 2020
63723e8
hyperlinks is not a recognized word??
PankajBhojwani Aug 21, 2020
01928d3
check ctrl first then shift
PankajBhojwani Aug 24, 2020
121f51c
fuzzer
PankajBhojwani Aug 24, 2020
52e5743
fix
PankajBhojwani Aug 24, 2020
d1b0e83
terminator, blank space fixes
PankajBhojwani Aug 25, 2020
82cc197
ctrl+shift when no uri updates selection
PankajBhojwani Aug 26, 2020
4ecbfc0
addressing comments
PankajBhojwani Aug 27, 2020
b75f189
SGR 0 fixes
PankajBhojwani Aug 27, 2020
5dcd706
id resolution
PankajBhojwani Aug 27, 2020
a099fc7
added roundtrip test
PankajBhojwani Aug 28, 2020
5620c01
spell
PankajBhojwani Aug 28, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/buffer/out/TextAttribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,17 @@ std::pair<COLORREF, COLORREF> TextAttribute::CalculateRgbColors(const gsl::span<
return { fg, bg };
}

// Method description:
// - Tells us whether the text is a hyperlink or not
// Return value:
// - True if it is a hyperlink, false otherwise
bool TextAttribute::IsHyperlink() const noexcept
{
// All non-hyperlink text have a default hyperlinkId of 0 while
// all hyperlink text have a non-zero hyperlinkId
return _hyperlinkId != 0;
}

TextColor TextAttribute::GetForeground() const noexcept
{
return _foreground;
Expand All @@ -122,6 +133,15 @@ TextColor TextAttribute::GetBackground() const noexcept
return _background;
}

// Method description:
// - Retrieves the hyperlink ID of the text
// Return value:
// - The hyperlink ID
SHORT TextAttribute::GetHyperlinkId() const noexcept
{
return _hyperlinkId;
}

void TextAttribute::SetForeground(const TextColor foreground) noexcept
{
_foreground = foreground;
Expand Down Expand Up @@ -174,6 +194,15 @@ void TextAttribute::SetColor(const COLORREF rgbColor, const bool fIsForeground)
}
}

// Method description:
// - Sets the hyperlink ID of the text
// Arguments:
// - id - the id we wish to set
void TextAttribute::SetHyperlinkId(SHORT id) noexcept
{
_hyperlinkId = id;
}

bool TextAttribute::IsLeadingByte() const noexcept
{
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_LEADING_BYTE);
Expand Down
17 changes: 13 additions & 4 deletions src/buffer/out/TextAttribute.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,17 @@ class TextAttribute final
_wAttrLegacy{ 0 },
_foreground{},
_background{},
_extendedAttrs{ ExtendedAttributes::Normal }
_extendedAttrs{ ExtendedAttributes::Normal },
_hyperlinkId{ 0 }
{
}

explicit constexpr TextAttribute(const WORD wLegacyAttr) noexcept :
_wAttrLegacy{ gsl::narrow_cast<WORD>(wLegacyAttr & META_ATTRS) },
_foreground{ s_LegacyIndexOrDefault(wLegacyAttr & FG_ATTRS, s_legacyDefaultForeground) },
_background{ s_LegacyIndexOrDefault((wLegacyAttr & BG_ATTRS) >> 4, s_legacyDefaultBackground) },
_extendedAttrs{ ExtendedAttributes::Normal }
_extendedAttrs{ ExtendedAttributes::Normal },
_hyperlinkId{ 0 }
{
// If we're given lead/trailing byte information with the legacy color, strip it.
WI_ClearAllFlags(_wAttrLegacy, COMMON_LVB_SBCSDBCS);
Expand All @@ -55,7 +57,8 @@ class TextAttribute final
_wAttrLegacy{ 0 },
_foreground{ rgbForeground },
_background{ rgbBackground },
_extendedAttrs{ ExtendedAttributes::Normal }
_extendedAttrs{ ExtendedAttributes::Normal },
_hyperlinkId{ 0 }
{
}

Expand Down Expand Up @@ -110,8 +113,11 @@ class TextAttribute final

ExtendedAttributes GetExtendedAttributes() const noexcept;

bool IsHyperlink() const noexcept;

TextColor GetForeground() const noexcept;
TextColor GetBackground() const noexcept;
SHORT GetHyperlinkId() const noexcept;
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
void SetForeground(const TextColor foreground) noexcept;
void SetBackground(const TextColor background) noexcept;
void SetForeground(const COLORREF rgbForeground) noexcept;
Expand All @@ -121,6 +127,7 @@ class TextAttribute final
void SetIndexedForeground256(const BYTE fgIndex) noexcept;
void SetIndexedBackground256(const BYTE bgIndex) noexcept;
void SetColor(const COLORREF rgbColor, const bool fIsForeground) noexcept;
void SetHyperlinkId(SHORT id) noexcept;

void SetDefaultForeground() noexcept;
void SetDefaultBackground() noexcept;
Expand Down Expand Up @@ -167,6 +174,8 @@ class TextAttribute final
TextColor _background;
ExtendedAttributes _extendedAttrs;

SHORT _hyperlinkId;

#ifdef UNIT_TESTING
friend class TextBufferTests;
friend class TextAttributeTests;
Expand All @@ -180,7 +189,7 @@ class TextAttribute final
// 4 for _foreground
// 4 for _background
// 1 for _extendedAttrs
static_assert(sizeof(TextAttribute) <= 11 * sizeof(BYTE), "We should only need 11B for an entire TextColor. Any more than that is just waste");
static_assert(sizeof(TextAttribute) <= 13 * sizeof(BYTE), "We should only need 13B for an entire TextAttribute. We may need to increment this in the future as we add additional attributes");

enum class TextAttributeBehavior
{
Expand Down
34 changes: 33 additions & 1 deletion src/buffer/out/textBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ TextBuffer::TextBuffer(const COORD screenBufferSize,
_storage{},
_unicodeStorage{},
_renderTarget{ renderTarget },
_size{}
_size{},
_curHyperlinkId{ 1 }
{
// initialize ROWs
for (size_t i = 0; i < static_cast<size_t>(screenBufferSize.Y); ++i)
Expand Down Expand Up @@ -2207,3 +2208,34 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,

return hr;
}

// Method Description:
// - Adds a hyperlink to our hyperlink table
// Arguments:
// - The hyperlink URI
void TextBuffer::AddHyperlinkToMap(std::wstring uri) noexcept
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
{
_hyperlinkMap.insert(std::pair<SHORT, std::wstring>(_curHyperlinkId, uri));
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
_curHyperlinkId++;
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
}

// Method Description:
// - Retrieves the next hyperlink ID to use - this is needed for setting
// the hyperlink ID in text attributes
// Return Value:
// - the SHORT hyperlink ID
SHORT TextBuffer::GetCurHyperlinkId() const noexcept
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
{
return _curHyperlinkId;
}

// Method Description:
// - Retrieves the URI associated with a particular hyperlink ID
// Arguments:
// - The hyperlink ID
// Return Value:
// - The URI
std::wstring TextBuffer::GetHyperlinkUriFromId(SHORT id) const noexcept
{
return _hyperlinkMap.at(id);
}
7 changes: 7 additions & 0 deletions src/buffer/out/textBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ class TextBuffer final

const std::vector<SMALL_RECT> GetTextRects(COORD start, COORD end, bool blockSelection = false) const;

void AddHyperlinkToMap(std::wstring uri) noexcept;
SHORT GetCurHyperlinkId() const noexcept;
std::wstring GetHyperlinkUriFromId(SHORT id) const noexcept;

class TextAndColor
{
public:
Expand Down Expand Up @@ -188,6 +192,9 @@ class TextBuffer final
// storage location for glyphs that can't fit into the buffer normally
UnicodeStorage _unicodeStorage;

SHORT _curHyperlinkId;
std::map<SHORT, std::wstring> _hyperlinkMap;

void _RefreshRowIDs(std::optional<SHORT> newRowWidth);

Microsoft::Console::Render::IRenderTarget& _renderTarget;
Expand Down
6 changes: 6 additions & 0 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
// macro directly with a VirtualKeyModifiers
const auto altEnabled = WI_IsFlagSet(modifiers, static_cast<uint32_t>(VirtualKeyModifiers::Menu));
const auto shiftEnabled = WI_IsFlagSet(modifiers, static_cast<uint32_t>(VirtualKeyModifiers::Shift));
const auto ctrlEnabled = WI_IsFlagSet(modifiers, static_cast<uint32_t>(VirtualKeyModifiers::Control));

if (_CanSendVTMouseInput())
{
Expand Down Expand Up @@ -1110,6 +1111,11 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
_terminal->SetSelectionEnd(terminalPosition, mode);
_selectionNeedsToBeCopied = true;
}
if (ctrlEnabled && mode == ::Terminal::SelectionExpansionMode::Cell)
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
{
// Control+Click: if the text selected is a hyperlink, open the link
_terminal->OpenHyperlink(terminalPosition);
}
else if (mode == ::Terminal::SelectionExpansionMode::Cell)
{
// Single Click: reset the selection and begin a new one
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalControl/TerminalControl.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@

<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>dwrite.lib;dxgi.lib;d2d1.lib;d3d11.lib;shcore.lib;winmm.lib;pathcch.lib;propsys.lib;uiautomationcore.lib;Shlwapi.lib;ntdll.lib;user32.lib;kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dwrite.lib;dxgi.lib;d2d1.lib;d3d11.lib;shcore.lib;winmm.lib;pathcch.lib;propsys.lib;uiautomationcore.lib;Shlwapi.lib;ntdll.lib;user32.lib;kernel32.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<ClCompile>
<AdditionalIncludeDirectories>$(OpenConsoleDir)src\cascadia\inc;$(OpenConsoleDir)src\types\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalControl/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,6 @@
TRACELOGGING_DECLARE_PROVIDER(g_hTerminalControlProvider);
#include <telemetry/ProjectTelemetry.h>

#include <shellapi.h>

#include "til.h"
2 changes: 2 additions & 0 deletions src/cascadia/TerminalCore/ITerminalApi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ namespace Microsoft::Terminal::Core

virtual bool CopyToClipboard(std::wstring_view content) noexcept = 0;

virtual bool AddHyperlink(std::wstring uri) noexcept = 0;

protected:
ITerminalApi() = default;
};
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ class Microsoft::Terminal::Core::Terminal final :
bool IsVtInputEnabled() const noexcept override;

bool CopyToClipboard(std::wstring_view content) noexcept override;

bool AddHyperlink(std::wstring uri) noexcept override;
#pragma endregion

#pragma region ITerminalInput
Expand Down Expand Up @@ -152,6 +154,7 @@ class Microsoft::Terminal::Core::Terminal final :
bool IsScreenReversed() const noexcept override;
const std::vector<Microsoft::Console::Render::RenderOverlay> GetOverlays() const noexcept override;
const bool IsGridLineDrawingAllowed() noexcept override;
const std::wstring GetHyperlinkUri(SHORT id) const noexcept override;
#pragma endregion

#pragma region IUiaData
Expand Down Expand Up @@ -188,6 +191,7 @@ class Microsoft::Terminal::Core::Terminal final :
void SetSelectionAnchor(const COORD position);
void SetSelectionEnd(const COORD position, std::optional<SelectionExpansionMode> newExpansionMode = std::nullopt);
void SetBlockSelection(const bool isEnabled) noexcept;
void OpenHyperlink(const COORD position);

const TextBuffer::TextAndColor RetrieveSelectedTextFromBuffer(bool trimTrailingWhitespace) const;
#pragma endregion
Expand Down
31 changes: 31 additions & 0 deletions src/cascadia/TerminalCore/TerminalApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,3 +560,34 @@ try
return true;
}
CATCH_LOG_RETURN_FALSE()

// Method Description:
// - Updates the buffer's current text attributes depending on whether we are
// starting/ending a hyperlink
// Arguments:
// - The hyperlink URI
// Return Value:
// - true
bool Terminal::AddHyperlink(std::wstring uri) noexcept
{
auto attr = _buffer->GetCurrentAttributes();
if (uri.empty())
{
// URI is empty, this means we are ending a hyperlink
attr.SetBold(false); // for now we manually set the bold/underline text attributes;
attr.SetUnderlined(false); // at some point we should just change text rendering directly
attr.SetHyperlinkId(0); // based on whether the hyperlink id is non-zero
_buffer->SetCurrentAttributes(attr);
}
else
{
// URI is non-empty, this means we are starting a hyperlink
attr.SetBold(true);
attr.SetUnderlined(true);
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
attr.SetHyperlinkId(_buffer->GetCurHyperlinkId());
_buffer->SetCurrentAttributes(attr);
_buffer->AddHyperlinkToMap(uri);
}
return true;
;
}
11 changes: 11 additions & 0 deletions src/cascadia/TerminalCore/TerminalDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,17 @@ bool TerminalDispatch::ResetPrivateModes(const gsl::span<const DispatchTypes::Pr
return _SetResetPrivateModes(params, false);
}

// Method Description:
// - Start or end a hyperlink
// Arguments:
// - The hyperlink URI
// Return Value:
// - true
bool TerminalDispatch::AddHyperlink(const std::wstring uri)
{
return _terminalApi.AddHyperlink(uri);
}

// Routine Description:
// - Generalized handler for the setting/resetting of DECSET/DECRST parameters.
// All params in the rgParams will attempt to be executed, even if one
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalCore/TerminalDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ class TerminalDispatch : public Microsoft::Console::VirtualTerminal::TermDispatc
bool SetPrivateModes(const gsl::span<const ::Microsoft::Console::VirtualTerminal::DispatchTypes::PrivateModeParams> /*params*/) noexcept override; // DECSET
bool ResetPrivateModes(const gsl::span<const ::Microsoft::Console::VirtualTerminal::DispatchTypes::PrivateModeParams> /*params*/) noexcept override; // DECRST

bool AddHyperlink(const std::wstring uri) override;

private:
::Microsoft::Terminal::Core::ITerminalApi& _terminalApi;

Expand Down
14 changes: 14 additions & 0 deletions src/cascadia/TerminalCore/TerminalSelection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,17 @@ void Terminal::ColorSelection(const COORD, const COORD, const TextAttribute)
{
THROW_HR(E_NOTIMPL);
}

PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
// Method Description:
// - If the clicked text is a hyperlink, open it
// Arguments:
// - The position of the clicked text
void Terminal::OpenHyperlink(const COORD position)
{
auto attr = _buffer->GetCellDataAt(_ConvertToBufferCell(position))->TextAttr();
if (attr.IsHyperlink())
{
auto uri = _buffer->GetHyperlinkUriFromId(attr.GetHyperlinkId());
ShellExecute(nullptr, L"open", uri.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
PankajBhojwani marked this conversation as resolved.
Show resolved Hide resolved
}
}
5 changes: 5 additions & 0 deletions src/cascadia/TerminalCore/terminalrenderdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ const bool Terminal::IsGridLineDrawingAllowed() noexcept
return true;
}

const std::wstring Microsoft::Terminal::Core::Terminal::GetHyperlinkUri(SHORT id) const noexcept
{
return _buffer->GetHyperlinkUriFromId(id);
}

std::vector<Microsoft::Console::Types::Viewport> Terminal::GetSelectionRects() noexcept
try
{
Expand Down
30 changes: 30 additions & 0 deletions src/host/outputStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,3 +770,33 @@ bool ConhostInternalGetSet::PrivateIsVtInputEnabled() const
{
return _io.GetActiveInputBuffer()->IsInVirtualTerminalInputMode();
}

// Method Description:
// - Updates the buffer's current text attributes depending on whether we are
// starting/ending a hyperlink
// Arguments:
// - The hyperlink URI
// Return Value:
// - true
bool ConhostInternalGetSet::PrivateAddHyperlink(const std::wstring uri) const
{
auto attr = _io.GetActiveOutputBuffer().GetAttributes();
if (uri.empty())
{
// URI is empty, this means we are ending a hyperlink
attr.SetBold(false); // for now we manually set the bold/underline text attributes;
attr.SetUnderlined(false); // at some point we should just change text rendering directly
attr.SetHyperlinkId(0); // based on whether the hyperlink id is non-zero
_io.GetActiveOutputBuffer().SetAttributes(attr);
}
else
{
// URI is non-empty, this means we are starting a hyperlink
attr.SetBold(true);
attr.SetUnderlined(true);
attr.SetHyperlinkId(_io.GetActiveOutputBuffer().GetCurHyperlinkId());
_io.GetActiveOutputBuffer().SetAttributes(attr);
_io.GetActiveOutputBuffer().AddHyperlinkToMap(uri);
}
return true;
}
2 changes: 2 additions & 0 deletions src/host/outputStream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ class ConhostInternalGetSet final : public Microsoft::Console::VirtualTerminal::

bool PrivateIsVtInputEnabled() const override;

bool PrivateAddHyperlink(const std::wstring uri) const override;

private:
Microsoft::Console::IIoProvider& _io;
};
Loading