-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
Avoid moving the selection while typing a search query #15998
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,30 +8,21 @@ | |
|
||
using namespace Microsoft::Console::Types; | ||
|
||
bool Search::ResetIfStale(Microsoft::Console::Render::IRenderData& renderData) | ||
{ | ||
return ResetIfStale(renderData, | ||
_needle, | ||
_step == -1, // this is the opposite of the initializer below | ||
_caseInsensitive); | ||
} | ||
|
||
bool Search::ResetIfStale(Microsoft::Console::Render::IRenderData& renderData, const std::wstring_view& needle, bool reverse, bool caseInsensitive) | ||
{ | ||
const auto& textBuffer = renderData.GetTextBuffer(); | ||
const auto lastMutationId = textBuffer.GetLastMutationId(); | ||
|
||
if (_needle == needle && | ||
_reverse == reverse && | ||
_caseInsensitive == caseInsensitive && | ||
_lastMutationId == lastMutationId) | ||
{ | ||
_step = reverse ? -1 : 1; | ||
return false; | ||
} | ||
|
||
_renderData = &renderData; | ||
_needle = needle; | ||
_reverse = reverse; | ||
_caseInsensitive = caseInsensitive; | ||
_lastMutationId = lastMutationId; | ||
|
||
|
@@ -42,12 +33,38 @@ bool Search::ResetIfStale(Microsoft::Console::Render::IRenderData& renderData, c | |
return true; | ||
} | ||
|
||
void Search::MovePastCurrentSelection() | ||
void Search::MoveToCurrentSelection() | ||
{ | ||
if (_renderData->IsSelectionActive()) | ||
{ | ||
MovePastPoint(_renderData->GetTextBuffer().ScreenToBufferPosition(_renderData->GetSelectionAnchor())); | ||
MoveToPoint(_renderData->GetTextBuffer().ScreenToBufferPosition(_renderData->GetSelectionAnchor())); | ||
} | ||
} | ||
|
||
void Search::MoveToPoint(const til::point anchor) noexcept | ||
{ | ||
if (_results.empty()) | ||
{ | ||
return; | ||
} | ||
|
||
const auto count = gsl::narrow_cast<ptrdiff_t>(_results.size()); | ||
ptrdiff_t index = 0; | ||
|
||
if (_step < 0) | ||
{ | ||
for (index = count - 1; index >= 0 && til::at(_results, index).start > anchor; --index) | ||
{ | ||
} | ||
} | ||
else | ||
{ | ||
for (index = 0; index < count && til::at(_results, index).start < anchor; ++index) | ||
{ | ||
} | ||
} | ||
|
||
_index = (index + count) % count; | ||
} | ||
Comment on lines
+44
to
68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This new function is a copy of the existing one below but with |
||
|
||
void Search::MovePastPoint(const til::point anchor) noexcept | ||
|
@@ -58,18 +75,17 @@ void Search::MovePastPoint(const til::point anchor) noexcept | |
} | ||
|
||
const auto count = gsl::narrow_cast<ptrdiff_t>(_results.size()); | ||
const auto highestIndex = count - 1; | ||
auto index = _reverse ? highestIndex : 0; | ||
ptrdiff_t index = 0; | ||
|
||
if (_reverse) | ||
if (_step < 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I figured that if we don't invalidate on |
||
{ | ||
for (; index >= 0 && til::at(_results, index).start >= anchor; --index) | ||
for (index = count - 1; index >= 0 && til::at(_results, index).start >= anchor; --index) | ||
{ | ||
} | ||
} | ||
else | ||
{ | ||
for (; index <= highestIndex && til::at(_results, index).start <= anchor; ++index) | ||
for (index = 0; index < count && til::at(_results, index).start <= anchor; ++index) | ||
{ | ||
} | ||
} | ||
|
@@ -119,7 +135,7 @@ const std::vector<til::point_span>& Search::Results() const noexcept | |
return _results; | ||
} | ||
|
||
size_t Search::CurrentMatch() const noexcept | ||
ptrdiff_t Search::CurrentMatch() const noexcept | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
{ | ||
return _index; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,25 +25,23 @@ class Search final | |
public: | ||
Search() = default; | ||
|
||
bool ResetIfStale(Microsoft::Console::Render::IRenderData& renderData); | ||
bool ResetIfStale(Microsoft::Console::Render::IRenderData& renderData, const std::wstring_view& needle, bool reverse, bool caseInsensitive); | ||
|
||
void MovePastCurrentSelection(); | ||
void MoveToCurrentSelection(); | ||
void MoveToPoint(til::point anchor) noexcept; | ||
void MovePastPoint(til::point anchor) noexcept; | ||
void FindNext() noexcept; | ||
|
||
const til::point_span* GetCurrent() const noexcept; | ||
bool SelectCurrent() const; | ||
|
||
const std::vector<til::point_span>& Results() const noexcept; | ||
size_t CurrentMatch() const noexcept; | ||
bool CurrentDirection() const noexcept; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
ptrdiff_t CurrentMatch() const noexcept; | ||
|
||
private: | ||
// _renderData is a pointer so that Search() is constexpr default constructable. | ||
Microsoft::Console::Render::IRenderData* _renderData = nullptr; | ||
std::wstring _needle; | ||
bool _reverse = false; | ||
bool _caseInsensitive = false; | ||
uint64_t _lastMutationId = 0; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1569,7 +1569,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation | |
|
||
if (_searcher.ResetIfStale(*GetRenderData(), text, !goForward, !caseSensitive)) | ||
{ | ||
_searcher.MovePastCurrentSelection(); | ||
_searcher.MoveToCurrentSelection(); | ||
_cachedSearchResultRows = {}; | ||
} | ||
else | ||
{ | ||
|
@@ -1600,12 +1601,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation | |
|
||
Windows::Foundation::Collections::IVector<int32_t> ControlCore::SearchResultRows() | ||
{ | ||
auto lock = _terminal->LockForWriting(); | ||
if (_searcher.ResetIfStale(*GetRenderData())) | ||
const auto lock = _terminal->LockForReading(); | ||
|
||
if (!_cachedSearchResultRows) | ||
{ | ||
auto results = std::vector<int32_t>(); | ||
|
||
auto lastRow = til::CoordTypeMin; | ||
|
||
for (const auto& match : _searcher.Results()) | ||
{ | ||
const auto row{ match.start.y }; | ||
|
@@ -1615,6 +1617,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation | |
lastRow = row; | ||
} | ||
} | ||
|
||
_cachedSearchResultRows = winrt::single_threaded_vector<int32_t>(std::move(results)); | ||
} | ||
|
||
|
@@ -2245,27 +2248,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation | |
|
||
Windows::Foundation::Collections::IVector<Control::ScrollMark> ControlCore::ScrollMarks() const | ||
{ | ||
auto internalMarks{ _terminal->GetScrollMarks() }; | ||
auto v = winrt::single_threaded_observable_vector<Control::ScrollMark>(); | ||
for (const auto& mark : internalMarks) | ||
{ | ||
Control::ScrollMark m{}; | ||
const auto& internalMarks = _terminal->GetScrollMarks(); | ||
std::vector<Control::ScrollMark> v; | ||
|
||
// sneaky: always evaluate the color of the mark to a real value | ||
// before shoving it into the optional. If the mark doesn't have a | ||
// specific color set, we'll use the value from the color table | ||
// that's appropriate for this category of mark. If we do have a | ||
// color set, then great we'll use that. The TermControl can then | ||
// always use the value in the Mark regardless if it was actually | ||
// set or not. | ||
m.Color = OptionalFromColor(_terminal->GetColorForMark(mark)); | ||
m.Start = mark.start.to_core_point(); | ||
m.End = mark.end.to_core_point(); | ||
v.reserve(internalMarks.size()); | ||
|
||
v.Append(m); | ||
for (const auto& mark : internalMarks) | ||
{ | ||
v.emplace_back( | ||
mark.start.to_core_point(), | ||
mark.end.to_core_point(), | ||
OptionalFromColor(_terminal->GetColorForMark(mark))); | ||
} | ||
|
||
return v; | ||
return winrt::single_threaded_vector(std::move(v)); | ||
Comment on lines
+2271
to
+2284
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding this to the PR was a bit of a mistake (I did
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. absolutely fine with me |
||
} | ||
|
||
void ControlCore::AddMark(const Control::ScrollMark& mark) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.