Avoid covering current search highlight with search box (#17516)

## Summary of the Pull Request
Adds a scroll offset to avoid hiding the current search highlight with
the search box.
- Offset is based on the number of rows that the search box takes up.
  (I am not totally sure I am calculating this right)
- This won't help when the current highlight is in the first couple
  rows of the buffer.

Fixes: #4407
This commit is contained in:
e82eric 2024-08-07 02:32:16 -04:00 committed by GitHub
parent f6a415511a
commit 0bafab9a0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 52 additions and 19 deletions

View File

@ -1689,22 +1689,22 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - resetOnly: If true, only Reset() will be called, if anything. FindNext() will never be called. // - resetOnly: If true, only Reset() will be called, if anything. FindNext() will never be called.
// Return Value: // Return Value:
// - <none> // - <none>
SearchResults ControlCore::Search(const std::wstring_view& text, const bool goForward, const bool caseSensitive, const bool regularExpression, const bool resetOnly) SearchResults ControlCore::Search(SearchRequest request)
{ {
const auto lock = _terminal->LockForWriting(); const auto lock = _terminal->LockForWriting();
SearchFlag flags{}; SearchFlag flags{};
WI_SetFlagIf(flags, SearchFlag::CaseInsensitive, !caseSensitive); WI_SetFlagIf(flags, SearchFlag::CaseInsensitive, !request.CaseSensitive);
WI_SetFlagIf(flags, SearchFlag::RegularExpression, regularExpression); WI_SetFlagIf(flags, SearchFlag::RegularExpression, request.RegularExpression);
const auto searchInvalidated = _searcher.IsStale(*_terminal.get(), text, flags); const auto searchInvalidated = _searcher.IsStale(*_terminal.get(), request.Text, flags);
if (searchInvalidated || !resetOnly) if (searchInvalidated || !request.Reset)
{ {
std::vector<til::point_span> oldResults; std::vector<til::point_span> oldResults;
if (searchInvalidated) if (searchInvalidated)
{ {
oldResults = _searcher.ExtractResults(); oldResults = _searcher.ExtractResults();
_searcher.Reset(*_terminal.get(), text, flags, !goForward); _searcher.Reset(*_terminal.get(), request.Text, flags, !request.GoForward);
if (SnapSearchResultToSelection()) if (SnapSearchResultToSelection())
{ {
@ -1716,12 +1716,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
} }
else else
{ {
_searcher.FindNext(!goForward); _searcher.FindNext(!request.GoForward);
} }
if (const auto idx = _searcher.CurrentMatch(); idx >= 0) if (const auto idx = _searcher.CurrentMatch(); idx >= 0)
{ {
_terminal->SetSearchHighlightFocused(gsl::narrow<size_t>(idx)); _terminal->SetSearchHighlightFocused(gsl::narrow<size_t>(idx), request.ScrollOffset);
} }
_renderer->TriggerSearchHighlight(oldResults); _renderer->TriggerSearchHighlight(oldResults);
} }
@ -1751,7 +1751,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{ {
const auto lock = _terminal->LockForWriting(); const auto lock = _terminal->LockForWriting();
_terminal->SetSearchHighlights({}); _terminal->SetSearchHighlights({});
_terminal->SetSearchHighlightFocused({}); _terminal->SetSearchHighlightFocused({}, 0);
_renderer->TriggerSearchHighlight(_searcher.Results()); _renderer->TriggerSearchHighlight(_searcher.Results());
_searcher = {}; _searcher = {};
} }
@ -2938,5 +2938,4 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{ {
_terminal->PreviewText(input); _terminal->PreviewText(input);
} }
} }

View File

@ -225,7 +225,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SetSelectionAnchor(const til::point position); void SetSelectionAnchor(const til::point position);
void SetEndSelectionPoint(const til::point position); void SetEndSelectionPoint(const til::point position);
SearchResults Search(const std::wstring_view& text, bool goForward, bool caseSensitive, bool regularExpression, bool reset); SearchResults Search(SearchRequest request);
const std::vector<til::point_span>& SearchResultRows() const noexcept; const std::vector<til::point_span>& SearchResultRows() const noexcept;
void ClearSearch(); void ClearSearch();
void SnapSearchResultToSelection(bool snap) noexcept; void SnapSearchResultToSelection(bool snap) noexcept;

View File

@ -49,6 +49,16 @@ namespace Microsoft.Terminal.Control
Boolean EndAtRightBoundary; Boolean EndAtRightBoundary;
}; };
struct SearchRequest
{
String Text;
Boolean GoForward;
Boolean CaseSensitive;
Boolean RegularExpression;
Boolean Reset;
Int32 ScrollOffset;
};
struct SearchResults struct SearchResults
{ {
Int32 TotalMatches; Int32 TotalMatches;
@ -136,7 +146,7 @@ namespace Microsoft.Terminal.Control
void ResumeRendering(); void ResumeRendering();
void BlinkAttributeTick(); void BlinkAttributeTick();
SearchResults Search(String text, Boolean goForward, Boolean caseSensitive, Boolean regularExpression, Boolean reset); SearchResults Search(SearchRequest request);
void ClearSearch(); void ClearSearch();
Boolean SnapSearchResultToSelection; Boolean SnapSearchResultToSelection;

View File

@ -584,6 +584,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_searchBox->Open([weakThis = get_weak()]() { _searchBox->Open([weakThis = get_weak()]() {
if (const auto self = weakThis.get(); self && !self->_IsClosing()) if (const auto self = weakThis.get(); self && !self->_IsClosing())
{ {
self->_searchScrollOffset = self->_calculateSearchScrollOffset();
self->_searchBox->SetFocusOnTextbox(); self->_searchBox->SetFocusOnTextbox();
self->_refreshSearch(); self->_refreshSearch();
} }
@ -605,7 +606,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
} }
else else
{ {
_handleSearchResults(_core.Search(_searchBox->Text(), goForward, _searchBox->CaseSensitive(), _searchBox->RegularExpression(), false)); const auto request = SearchRequest{ _searchBox->Text(), goForward, _searchBox->CaseSensitive(), _searchBox->RegularExpression(), false, _searchScrollOffset };
_handleSearchResults(_core.Search(request));
} }
} }
@ -639,7 +641,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{ {
if (_searchBox && _searchBox->IsOpen()) if (_searchBox && _searchBox->IsOpen())
{ {
_handleSearchResults(_core.Search(text, goForward, caseSensitive, regularExpression, false)); const auto request = SearchRequest{ text, goForward, caseSensitive, regularExpression, false, _searchScrollOffset };
_handleSearchResults(_core.Search(request));
} }
} }
@ -660,7 +663,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{ {
// We only want to update the search results based on the new text. Set // We only want to update the search results based on the new text. Set
// `resetOnly` to true so we don't accidentally update the current match index. // `resetOnly` to true so we don't accidentally update the current match index.
const auto result = _core.Search(text, goForward, caseSensitive, regularExpression, true); const auto request = SearchRequest{ text, goForward, caseSensitive, regularExpression, true, _searchScrollOffset };
const auto result = _core.Search(request);
_handleSearchResults(result); _handleSearchResults(result);
} }
} }
@ -3572,6 +3576,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
QuickFixIcon().FontSize(static_cast<double>(args.Width() / dpiScale)); QuickFixIcon().FontSize(static_cast<double>(args.Width() / dpiScale));
RefreshQuickFixMenu(); RefreshQuickFixMenu();
} }
_searchScrollOffset = _calculateSearchScrollOffset();
} }
void TermControl::_coreRaisedNotice(const IInspectable& /*sender*/, void TermControl::_coreRaisedNotice(const IInspectable& /*sender*/,
@ -3702,7 +3708,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto goForward = _searchBox->GoForward(); const auto goForward = _searchBox->GoForward();
const auto caseSensitive = _searchBox->CaseSensitive(); const auto caseSensitive = _searchBox->CaseSensitive();
const auto regularExpression = _searchBox->RegularExpression(); const auto regularExpression = _searchBox->RegularExpression();
_handleSearchResults(_core.Search(text, goForward, caseSensitive, regularExpression, true)); const auto request = SearchRequest{ text, goForward, caseSensitive, regularExpression, true, _calculateSearchScrollOffset() };
_handleSearchResults(_core.Search(request));
} }
void TermControl::_handleSearchResults(SearchResults results) void TermControl::_handleSearchResults(SearchResults results)
@ -3982,6 +3989,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
SearchMissingCommand.raise(*this, args); SearchMissingCommand.raise(*this, args);
} }
til::CoordType TermControl::_calculateSearchScrollOffset() const
{
auto result = 0;
if (_searchBox)
{
const auto displayInfo = DisplayInformation::GetForCurrentView();
const auto scaleFactor = _core.FontSize().Height / displayInfo.RawPixelsPerViewPixel();
const auto searchBoxRows = _searchBox->ActualHeight() / scaleFactor;
result = static_cast<int32_t>(std::ceil(searchBoxRows));
}
return result;
}
void TermControl::ClearQuickFix() void TermControl::ClearQuickFix()
{ {
_core.ClearQuickFix(); _core.ClearQuickFix();

View File

@ -289,6 +289,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool _isBackgroundLight{ false }; bool _isBackgroundLight{ false };
bool _detached{ false }; bool _detached{ false };
til::CoordType _searchScrollOffset = 0;
Windows::Foundation::Collections::IObservableVector<Windows::UI::Xaml::Controls::ICommandBarElement> _originalPrimaryElements{ nullptr }; Windows::Foundation::Collections::IObservableVector<Windows::UI::Xaml::Controls::ICommandBarElement> _originalPrimaryElements{ nullptr };
Windows::Foundation::Collections::IObservableVector<Windows::UI::Xaml::Controls::ICommandBarElement> _originalSecondaryElements{ nullptr }; Windows::Foundation::Collections::IObservableVector<Windows::UI::Xaml::Controls::ICommandBarElement> _originalSecondaryElements{ nullptr };
@ -409,6 +410,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _showContextMenuAt(const til::point& controlRelativePos); void _showContextMenuAt(const til::point& controlRelativePos);
void _bubbleSearchMissingCommand(const IInspectable& sender, const Control::SearchMissingCommandEventArgs& args); void _bubbleSearchMissingCommand(const IInspectable& sender, const Control::SearchMissingCommandEventArgs& args);
til::CoordType _calculateSearchScrollOffset() const;
void _PasteCommandHandler(const IInspectable& sender, const IInspectable& args); void _PasteCommandHandler(const IInspectable& sender, const IInspectable& args);
void _CopyCommandHandler(const IInspectable& sender, const IInspectable& args); void _CopyCommandHandler(const IInspectable& sender, const IInspectable& args);

View File

@ -1251,7 +1251,7 @@ void Terminal::SetSearchHighlights(const std::vector<til::point_span>& highlight
// Method Description: // Method Description:
// - Stores the focused search highlighted region in the terminal // - Stores the focused search highlighted region in the terminal
// - If the region isn't empty, it will be brought into view // - If the region isn't empty, it will be brought into view
void Terminal::SetSearchHighlightFocused(const size_t focusedIdx) void Terminal::SetSearchHighlightFocused(const size_t focusedIdx, til::CoordType searchScrollOffset)
{ {
_assertLocked(); _assertLocked();
_searchHighlightFocused = focusedIdx; _searchHighlightFocused = focusedIdx;
@ -1260,7 +1260,9 @@ void Terminal::SetSearchHighlightFocused(const size_t focusedIdx)
if (focusedIdx < _searchHighlights.size()) if (focusedIdx < _searchHighlights.size())
{ {
const auto focused = til::at(_searchHighlights, focusedIdx); const auto focused = til::at(_searchHighlights, focusedIdx);
_ScrollToPoints(focused.start, focused.end); const auto adjustedStart = til::point{ focused.start.x, std::max(0, focused.start.y - searchScrollOffset) };
const auto adjustedEnd = til::point{ focused.end.x, std::max(0, focused.end.y - searchScrollOffset) };
_ScrollToPoints(adjustedStart, adjustedEnd);
} }
} }

View File

@ -232,7 +232,7 @@ public:
void SetSearchMissingCommandCallback(std::function<void(std::wstring_view)> pfn) noexcept; void SetSearchMissingCommandCallback(std::function<void(std::wstring_view)> pfn) noexcept;
void SetClearQuickFixCallback(std::function<void()> pfn) noexcept; void SetClearQuickFixCallback(std::function<void()> pfn) noexcept;
void SetSearchHighlights(const std::vector<til::point_span>& highlights) noexcept; void SetSearchHighlights(const std::vector<til::point_span>& highlights) noexcept;
void SetSearchHighlightFocused(const size_t focusedIdx); void SetSearchHighlightFocused(const size_t focusedIdx, til::CoordType searchScrollOffset);
void BlinkCursor() noexcept; void BlinkCursor() noexcept;
void SetCursorOn(const bool isOn) noexcept; void SetCursorOn(const bool isOn) noexcept;