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

Add support for tabbing to embedded hyperlinks #18347

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
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
58 changes: 52 additions & 6 deletions src/cascadia/TerminalCore/TerminalSelection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,8 @@ void Terminal::SelectHyperlink(const SearchDirection dir)
}

// 0. Useful tools/vars
const auto bufferSize = _activeBuffer().GetSize();
const auto& buffer = _activeBuffer();
const auto bufferSize = buffer.GetSize();
const auto viewportHeight = _GetMutableViewport().Height();

// The patterns are stored relative to the "search area". Initially, this search area will be the viewport,
Expand Down Expand Up @@ -514,15 +515,60 @@ void Terminal::SelectHyperlink(const SearchDirection dir)
searchArea = Viewport::FromDimensions(searchStart, { searchEnd.x + 1, searchEnd.y + 1 });
}
}
}

// 1.C) Nothing was found. Bail!
if (!result.has_value())
// 2. We found a hyperlink from the pattern tree. Look for embedded hyperlinks too!
// Use the result (if one was found) to narrow down the search.
searchStart = dir == SearchDirection::Forward ?
_selection->start :
(result ? result->second : bufferSize.Origin());
searchEnd = dir == SearchDirection::Forward ?
(result ? result->first : buffer.GetLastNonSpaceCharacter()) :
_selection->start;
auto iter = buffer.GetCellDataAt(dir == SearchDirection::Forward ? searchStart : searchEnd);
while (dir == SearchDirection::Forward ? iter.Pos() < searchEnd : iter.Pos() > searchStart)
{
// Don't let us select the same hyperlink again
if (iter.Pos() < _selection->start || iter.Pos() > _selection->end)
{
return;
if (auto attr = iter->TextAttr(); attr.IsHyperlink())
{
// Found an embedded hyperlink!
const auto hyperlinkId = attr.GetHyperlinkId();

// Expand the start to include the entire hyperlink
TextBufferCellIterator hyperlinkStartIter{ buffer, iter.Pos() };
while (attr.IsHyperlink() && attr.GetHyperlinkId() == hyperlinkId)
{
hyperlinkStartIter--;
attr = hyperlinkStartIter->TextAttr();
}
// undo a move to be inclusive
hyperlinkStartIter++;

// Expand the end to include the entire hyperlink
// No need to undo a move! We'll decrement in the next step anyways.
TextBufferCellIterator hyperlinkEndIter{ buffer, iter.Pos() };
attr = hyperlinkEndIter->TextAttr();
while (attr.IsHyperlink() && attr.GetHyperlinkId() == hyperlinkId)
{
hyperlinkEndIter++;
attr = hyperlinkEndIter->TextAttr();
}

result = { hyperlinkStartIter.Pos(), hyperlinkEndIter.Pos() };
break;
}
}
iter += dir == SearchDirection::Forward ? 1 : -1;
}

// 2. Select the hyperlink
// 3. Select the hyperlink, if one exists
if (!result.has_value())
{
return;
}
else
{
auto selection{ _selection.write() };
wil::hide_name _selection;
Expand All @@ -534,7 +580,7 @@ void Terminal::SelectHyperlink(const SearchDirection dir)
_selectionEndpoint = SelectionEndpoint::End;
}

// 3. Scroll to the selected area (if necessary)
// 4. Scroll to the selected area (if necessary)
_ScrollToPoint(_selection->end);
}

Expand Down
Loading