@@ -404,7 +404,8 @@ void Terminal::SelectHyperlink(const SearchDirection dir)
404
404
}
405
405
406
406
// 0. Useful tools/vars
407
- const auto bufferSize = _activeBuffer ().GetSize ();
407
+ const auto & buffer = _activeBuffer ();
408
+ const auto bufferSize = buffer.GetSize ();
408
409
const auto viewportHeight = _GetMutableViewport ().Height ();
409
410
410
411
// The patterns are stored relative to the "search area". Initially, this search area will be the viewport,
@@ -514,15 +515,60 @@ void Terminal::SelectHyperlink(const SearchDirection dir)
514
515
searchArea = Viewport::FromDimensions (searchStart, { searchEnd.x + 1 , searchEnd.y + 1 });
515
516
}
516
517
}
518
+ }
517
519
518
- // 1.C) Nothing was found. Bail!
519
- if (!result.has_value ())
520
+ // 2. We found a hyperlink from the pattern tree. Look for embedded hyperlinks too!
521
+ // Use the result (if one was found) to narrow down the search.
522
+ searchStart = dir == SearchDirection::Forward ?
523
+ _selection->start :
524
+ (result ? result->second : bufferSize.Origin ());
525
+ searchEnd = dir == SearchDirection::Forward ?
526
+ (result ? result->first : buffer.GetLastNonSpaceCharacter ()) :
527
+ _selection->start ;
528
+ auto iter = buffer.GetCellDataAt (dir == SearchDirection::Forward ? searchStart : searchEnd);
529
+ while (dir == SearchDirection::Forward ? iter.Pos () < searchEnd : iter.Pos () > searchStart)
530
+ {
531
+ // Don't let us select the same hyperlink again
532
+ if (iter.Pos () < _selection->start || iter.Pos () > _selection->end )
520
533
{
521
- return ;
534
+ if (auto attr = iter->TextAttr (); attr.IsHyperlink ())
535
+ {
536
+ // Found an embedded hyperlink!
537
+ const auto hyperlinkId = attr.GetHyperlinkId ();
538
+
539
+ // Expand the start to include the entire hyperlink
540
+ TextBufferCellIterator hyperlinkStartIter{ buffer, iter.Pos () };
541
+ while (attr.IsHyperlink () && attr.GetHyperlinkId () == hyperlinkId)
542
+ {
543
+ hyperlinkStartIter--;
544
+ attr = hyperlinkStartIter->TextAttr ();
545
+ }
546
+ // undo a move to be inclusive
547
+ hyperlinkStartIter++;
548
+
549
+ // Expand the end to include the entire hyperlink
550
+ // No need to undo a move! We'll decrement in the next step anyways.
551
+ TextBufferCellIterator hyperlinkEndIter{ buffer, iter.Pos () };
552
+ attr = hyperlinkEndIter->TextAttr ();
553
+ while (attr.IsHyperlink () && attr.GetHyperlinkId () == hyperlinkId)
554
+ {
555
+ hyperlinkEndIter++;
556
+ attr = hyperlinkEndIter->TextAttr ();
557
+ }
558
+
559
+ result = { hyperlinkStartIter.Pos (), hyperlinkEndIter.Pos () };
560
+ break ;
561
+ }
522
562
}
563
+ iter += dir == SearchDirection::Forward ? 1 : -1 ;
523
564
}
524
565
525
- // 2. Select the hyperlink
566
+ // 3. Select the hyperlink, if one exists
567
+ if (!result.has_value ())
568
+ {
569
+ return ;
570
+ }
571
+ else
526
572
{
527
573
auto selection{ _selection.write () };
528
574
wil::hide_name _selection;
@@ -534,7 +580,7 @@ void Terminal::SelectHyperlink(const SearchDirection dir)
534
580
_selectionEndpoint = SelectionEndpoint::End;
535
581
}
536
582
537
- // 3 . Scroll to the selected area (if necessary)
583
+ // 4 . Scroll to the selected area (if necessary)
538
584
_ScrollToPoint (_selection->end );
539
585
}
540
586
0 commit comments