Skip to content

Commit 19a8501

Browse files
mark mode: begin selection at focused search result (#19550)
## Summary of the Pull Request Searching in terminal highlights all search results. However, those results are considered separate from a selection. In the past, the highlighted result would be selected, resulting in it being the initial position for mark mode. Now that it's separate, mark mode doesn't start there. To fix this, there's 2 changes here: 1. When we exit the search, we now select the focused search result. This becomes the initial position for mark mode. 2. When we're in the middle of a search and mark mode becomes enabled, the focused search result becomes the initial position for mark mode. With this change, mark mode's initial position is determined in this order: 1. the position of an active selection 2. the position of the focused search result (if one is available) 3. the top-left position of the viewport (if there is a scrollback) (see #19549) 4. the current cursor position ## Validation Steps Performed Entering mark mode in scenario X results in a starting position of Y: ✅ selected text during a search --> selected text - NOTE: this seems to only occur if you start a search, then manually click on the terminal to bring focus there, but keep the search results active ✅ performed a search and results are available -->focused search result ✅ performed a search and no results are available - scrolled up --> top-left of viewport - no scrollback --> cursor position ✅ performed a search, got results, then closed search --> focused search result Closes #19358
1 parent 898b9e3 commit 19a8501

File tree

2 files changed

+31
-7
lines changed

2 files changed

+31
-7
lines changed

src/cascadia/TerminalControl/ControlCore.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,6 +1787,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
17871787
void ControlCore::ClearSearch()
17881788
{
17891789
const auto lock = _terminal->LockForWriting();
1790+
1791+
// GH #19358: select the focused search result before clearing search
1792+
if (const auto focusedSearchResult = _terminal->GetSearchHighlightFocused())
1793+
{
1794+
_terminal->SetSelectionAnchor(focusedSearchResult->start);
1795+
_terminal->SetSelectionEnd(focusedSearchResult->end);
1796+
_renderer->TriggerSelection();
1797+
}
1798+
17901799
_terminal->SetSearchHighlights({});
17911800
_terminal->SetSearchHighlightFocused(0);
17921801
_renderer->TriggerSearchHighlight(_searcher.Results());

src/cascadia/TerminalCore/TerminalSelection.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -362,10 +362,30 @@ void Terminal::ToggleMarkMode()
362362
{
363363
// Enter Mark Mode
364364
// NOTE: directly set cursor state. We already should have locked before calling this function.
365-
if (!IsSelectionActive())
365+
if (IsSelectionActive())
366+
{
367+
// Selection already existed --> just target "end"
368+
if (WI_AreAllFlagsClear(_selectionEndpoint, SelectionEndpoint::Start | SelectionEndpoint::End))
369+
{
370+
WI_SetFlag(_selectionEndpoint, SelectionEndpoint::End);
371+
}
372+
}
373+
else if (const auto focusedSearchResult = GetSearchHighlightFocused())
374+
{
375+
// We have a focused search result --> treat it as selection
376+
*_selection.write() = SelectionInfo{
377+
.start = focusedSearchResult->start,
378+
.end = focusedSearchResult->end,
379+
.pivot = focusedSearchResult->start,
380+
.blockSelection = false,
381+
.active = true,
382+
};
383+
WI_SetFlag(_selectionEndpoint, SelectionEndpoint::End);
384+
}
385+
else
366386
{
367387
// If we're scrolled up, use the viewport origin as the selection start.
368-
// Otherwise, use the cursor position.
388+
// Otherwise, just use the cursor position.
369389
const auto cursorPos = _scrollOffset != 0 ? _GetVisibleViewport().Origin() :
370390
_activeBuffer().GetCursor().GetPosition();
371391
*_selection.write() = SelectionInfo{
@@ -377,11 +397,6 @@ void Terminal::ToggleMarkMode()
377397
};
378398
WI_SetAllFlags(_selectionEndpoint, SelectionEndpoint::Start | SelectionEndpoint::End);
379399
}
380-
else if (WI_AreAllFlagsClear(_selectionEndpoint, SelectionEndpoint::Start | SelectionEndpoint::End))
381-
{
382-
// Selection already existed
383-
WI_SetFlag(_selectionEndpoint, SelectionEndpoint::End);
384-
}
385400
_ScrollToPoint(_selection->start);
386401
_selectionMode = SelectionInteractionMode::Mark;
387402
_selectionIsTargetingUrl = false;

0 commit comments

Comments
 (0)