Skip to content

Commit

Permalink
Show number of search results & positions of hits in scrollbar (#14045)
Browse files Browse the repository at this point in the history
This is a resurrection of #8588. That PR became painfully stale after
the `ControlCore` split. Original description:

> ## Summary of the Pull Request
> This is a PoC for:
> * Search status in SearchBox (aka number of matches + index of the
current match)
> * Live search (aka search upon typing)
> ## Detailed Description of the Pull Request / Additional comments
> * Introduced this optionally (global setting to enable it)
> * The approach is following:
>   * Every time the filter changes, enumerate all matches
>   * Upon navigation just take the relevant match and select it
> 

I cleaned it up a bit, and added support for also displaying the
positions of the matches in the scrollbar (if `showMarksOnScrollbar` is
also turned on).

It's also been made SUBSTANTIALLY easier after #15858 was merged.

Similar to before, searching while there's piles of output running isn't
_perfect_. But it's pretty awful currently, so that's not the end of the
world.

Gifs below.

* closes #8631 (which is a bullet point in #3920)
* closes #6319


Co-authored-by: Don-Vito <khvitaly@gmail.com>

---------

Co-authored-by: khvitaly <khvitaly@gmail.com>
  • Loading branch information
zadjii-msft and Don-Vito authored Sep 5, 2023
1 parent c5e0908 commit 0cbde94
Show file tree
Hide file tree
Showing 19 changed files with 383 additions and 24 deletions.
25 changes: 23 additions & 2 deletions src/buffer/out/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@

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();
Expand Down Expand Up @@ -71,8 +79,10 @@ void Search::MovePastPoint(const til::point anchor) noexcept

void Search::FindNext() noexcept
{
const auto count = gsl::narrow_cast<ptrdiff_t>(_results.size());
_index = (_index + _step + count) % count;
if (const auto count{ gsl::narrow_cast<ptrdiff_t>(_results.size()) })
{
_index = (_index + _step + count) % count;
}
}

const til::point_span* Search::GetCurrent() const noexcept
Expand All @@ -87,6 +97,7 @@ const til::point_span* Search::GetCurrent() const noexcept

// Routine Description:
// - Takes the found word and selects it in the screen buffer

bool Search::SelectCurrent() const
{
if (const auto s = GetCurrent())
Expand All @@ -102,3 +113,13 @@ bool Search::SelectCurrent() const

return false;
}

const std::vector<til::point_span>& Search::Results() const noexcept
{
return _results;
}

size_t Search::CurrentMatch() const noexcept
{
return _index;
}
7 changes: 6 additions & 1 deletion src/buffer/out/search.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ 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();
Expand All @@ -34,10 +35,14 @@ class Search final
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;

private:
// _renderData is a pointer so that Search() is constexpr default constructable.
Microsoft::Console::Render::IRenderData* _renderData = nullptr;
std::wstring_view _needle;
std::wstring _needle;
bool _reverse = false;
bool _caseInsensitive = false;
uint64_t _lastMutationId = 0;
Expand Down
40 changes: 39 additions & 1 deletion src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ constexpr const auto TsfRedrawInterval = std::chrono::milliseconds(100);
// The minimum delay between updating the locations of regex patterns
constexpr const auto UpdatePatternLocationsInterval = std::chrono::milliseconds(500);

// The delay before performing the search after change of search criteria
constexpr const auto SearchAfterChangeDelay = std::chrono::milliseconds(200);

namespace winrt::Microsoft::Terminal::Control::implementation
{
static winrt::Microsoft::Terminal::Core::OptionalColor OptionalFromColor(const til::color& c)
Expand Down Expand Up @@ -1346,6 +1349,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
nullptr;
}

til::color ControlCore::ForegroundColor() const
{
return _terminal->GetRenderSettings().GetColorAlias(ColorAlias::DefaultForeground);
}

til::color ControlCore::BackgroundColor() const
{
return _terminal->GetRenderSettings().GetColorAlias(ColorAlias::DefaultBackground);
Expand Down Expand Up @@ -1552,6 +1560,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}

const auto foundMatch = _searcher.SelectCurrent();
auto foundResults = winrt::make_self<implementation::FoundResultsArgs>(foundMatch);
if (foundMatch)
{
// this is used for search,
Expand All @@ -1560,15 +1569,44 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_terminal->SetBlockSelection(false);
_renderer->TriggerSelection();
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));

foundResults->TotalMatches(gsl::narrow<int32_t>(_searcher.Results().size()));
foundResults->CurrentMatch(gsl::narrow<int32_t>(_searcher.CurrentMatch()));

_terminal->AlwaysNotifyOnBufferRotation(true);
}

// Raise a FoundMatch event, which the control will use to notify
// narrator if there was any results in the buffer
_FoundMatchHandlers(*this, winrt::make<implementation::FoundResultsArgs>(foundMatch));
_FoundMatchHandlers(*this, *foundResults);
}

Windows::Foundation::Collections::IVector<int32_t> ControlCore::SearchResultRows()
{
auto lock = _terminal->LockForWriting();
if (_searcher.ResetIfStale(*GetRenderData()))
{
auto results = std::vector<int32_t>();

auto lastRow = til::CoordTypeMin;
for (const auto& match : _searcher.Results())
{
const auto row{ match.start.y };
if (row != lastRow)
{
results.push_back(row);
lastRow = row;
}
}
_cachedSearchResultRows = winrt::single_threaded_vector<int32_t>(std::move(results));
}

return _cachedSearchResultRows;
}

void ControlCore::ClearSearch()
{
_terminal->AlwaysNotifyOnBufferRotation(false);
_searcher = {};
}

Expand Down
5 changes: 5 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::hstring FontFaceName() const noexcept;
uint16_t FontWeight() const noexcept;

til::color ForegroundColor() const;
til::color BackgroundColor() const;

void SendInput(const winrt::hstring& wstr);
Expand Down Expand Up @@ -208,6 +209,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void Search(const winrt::hstring& text, const bool goForward, const bool caseSensitive);
void ClearSearch();

Windows::Foundation::Collections::IVector<int32_t> SearchResultRows();

void LeftClickOnTerminal(const til::point terminalPosition,
const int numberOfClicks,
const bool altEnabled,
Expand Down Expand Up @@ -338,6 +341,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation

til::point _contextMenuBufferPosition{ 0, 0 };

Windows::Foundation::Collections::IVector<int32_t> _cachedSearchResultRows{ nullptr };

void _setupDispatcherAndCallbacks();

bool _setFontSizeUnderLock(float fontSize);
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.idl
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,12 @@ namespace Microsoft.Terminal.Control
Microsoft.Terminal.Core.Point CursorPosition { get; };
void ResumeRendering();
void BlinkAttributeTick();

void Search(String text, Boolean goForward, Boolean caseSensitive);
void ClearSearch();
IVector<Int32> SearchResultRows { get; };

Microsoft.Terminal.Core.Color ForegroundColor { get; };
Microsoft.Terminal.Core.Color BackgroundColor { get; };

SelectionData SelectionInfo { get; };
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalControl/EventArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}

WINRT_PROPERTY(bool, FoundMatch);
WINRT_PROPERTY(int32_t, TotalMatches);
WINRT_PROPERTY(int32_t, CurrentMatch);
};

struct ShowWindowArgs : public ShowWindowArgsT<ShowWindowArgs>
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalControl/EventArgs.idl
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ namespace Microsoft.Terminal.Control
runtimeclass FoundResultsArgs
{
Boolean FoundMatch { get; };
Int32 TotalMatches { get; };
Int32 CurrentMatch { get; };
}

runtimeclass ShowWindowArgs
Expand Down
14 changes: 13 additions & 1 deletion src/cascadia/TerminalControl/Resources/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,18 @@
<data name="HowToOpenRun.Text" xml:space="preserve">
<value>Ctrl+Click to follow link</value>
</data>
<data name="TermControl_NoMatch" xml:space="preserve">
<value>No results</value>
<comment>Will be presented near the search box when Find operation returned no results.</comment>
</data>
<data name="TermControl_Searching" xml:space="preserve">
<value>Searching...</value>
<comment>Will be presented near the search box when Find operation is running.</comment>
</data>
<data name="TermControl_NumResults" xml:space="preserve">
<value>{0}/{1}</value>
<comment>Will be displayed to indicate what result the user has selected, of how many total results. {0} will be replaced with the index of the current result. {1} will be replaced with the total number of results.</comment>
</data>
<data name="InvalidUri" xml:space="preserve">
<value>Invalid URI</value>
<comment>Whenever we encounter an invalid URI or URL we show this string as a warning.</comment>
Expand Down Expand Up @@ -276,4 +288,4 @@ Please either install the missing font or choose another one.</value>
<value>Select output</value>
<comment>The tooltip for a button for selecting all of a command's output</comment>
</data>
</root>
</root>
Loading

0 comments on commit 0cbde94

Please sign in to comment.