Skip to content

Commit

Permalink
search: allow search to communicate failure
Browse files Browse the repository at this point in the history
  • Loading branch information
DHowett committed May 30, 2024
1 parent fc8bb05 commit e5314bf
Show file tree
Hide file tree
Showing 16 changed files with 97 additions and 32 deletions.
9 changes: 8 additions & 1 deletion src/buffer/out/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ bool Search::Reset(Microsoft::Console::Render::IRenderData& renderData, const st
_flags = flags;
_lastMutationId = textBuffer.GetLastMutationId();

_ok = textBuffer.SearchText(needle, _flags, _results);
auto result = textBuffer.SearchText(needle, _flags);
_ok = result.has_value();
_results = std::move(result).value_or(std::vector<til::point_span>{});
_index = reverse ? gsl::narrow_cast<ptrdiff_t>(_results.size()) - 1 : 0;
_step = reverse ? -1 : 1;
return true;
Expand Down Expand Up @@ -144,3 +146,8 @@ ptrdiff_t Search::CurrentMatch() const noexcept
{
return _index;
}

bool Search::IsOk() const noexcept
{
return _ok;
}
2 changes: 2 additions & 0 deletions src/buffer/out/search.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Search final
const std::vector<til::point_span>& Results() const noexcept;
std::vector<til::point_span>&& ExtractResults() noexcept;
ptrdiff_t CurrentMatch() const noexcept;
bool IsOk() const noexcept;

private:
// _renderData is a pointer so that Search() is constexpr default constructable.
Expand All @@ -57,6 +58,7 @@ class Search final
SearchFlag _flags{};
uint64_t _lastMutationId = 0;

bool _ok{ false };
std::vector<til::point_span> _results;
ptrdiff_t _index = 0;
ptrdiff_t _step = 0;
Expand Down
10 changes: 8 additions & 2 deletions src/buffer/out/textBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3185,14 +3185,15 @@ void TextBuffer::CopyHyperlinkMaps(const TextBuffer& other)

// Searches through the entire (committed) text buffer for `needle` and returns the coordinates in absolute coordinates.
// The end coordinates of the returned ranges are considered inclusive.
std::vector<til::point_span> TextBuffer::SearchText(const std::wstring_view& needle, SearchFlag flags) const
std::optional<std::vector<til::point_span>> TextBuffer::SearchText(const std::wstring_view& needle, SearchFlag flags) const
{
return SearchText(needle, flags, 0, til::CoordTypeMax);
}

// Searches through the given rows [rowBeg,rowEnd) for `needle` and returns the coordinates in absolute coordinates.
// While the end coordinates of the returned ranges are considered inclusive, the [rowBeg,rowEnd) range is half-open.
std::vector<til::point_span> TextBuffer::SearchText(const std::wstring_view& needle, SearchFlag flags, til::CoordType rowBeg, til::CoordType rowEnd) const
// Returns nullopt if the parameters were invalid (e.g. regex search was requested with an invalid regex)
std::optional<std::vector<til::point_span>> TextBuffer::SearchText(const std::wstring_view& needle, SearchFlag flags, til::CoordType rowBeg, til::CoordType rowEnd) const
{
rowEnd = std::min(rowEnd, _estimateOffsetOfLastCommittedRow() + 1);

Expand Down Expand Up @@ -3220,6 +3221,11 @@ std::vector<til::point_span> TextBuffer::SearchText(const std::wstring_view& nee

UErrorCode status = U_ZERO_ERROR;
const auto re = ICU::CreateRegex(needle, icuFlags, &status);
if (status > U_ZERO_ERROR)
{
return std::nullopt;
}

uregex_setUText(re.get(), &text, &status);

if (uregex_find(re.get(), -1, &status))
Expand Down
4 changes: 2 additions & 2 deletions src/buffer/out/textBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ class TextBuffer final

static void Reflow(TextBuffer& oldBuffer, TextBuffer& newBuffer, const Microsoft::Console::Types::Viewport* lastCharacterViewport = nullptr, PositionInformation* positionInfo = nullptr);

std::vector<til::point_span> SearchText(const std::wstring_view& needle, SearchFlag flags) const;
std::vector<til::point_span> SearchText(const std::wstring_view& needle, SearchFlag flags, til::CoordType rowBeg, til::CoordType rowEnd) const;
std::optional<std::vector<til::point_span>> SearchText(const std::wstring_view& needle, SearchFlag flags) const;
std::optional<std::vector<til::point_span>> SearchText(const std::wstring_view& needle, SearchFlag flags, til::CoordType rowBeg, til::CoordType rowEnd) const;

// Mark handling
std::vector<ScrollMark> GetMarkRows() const;
Expand Down
4 changes: 3 additions & 1 deletion src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1654,11 +1654,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - resetOnly: If true, only Reset() will be called, if anything. FindNext() will never be called.
// Return Value:
// - <none>
SearchResults ControlCore::Search(const std::wstring_view& text, const bool goForward, const bool caseSensitive, const bool resetOnly)
SearchResults ControlCore::Search(const std::wstring_view& text, const bool goForward, const bool caseSensitive, const bool regularExpression, const bool resetOnly)
{
const auto lock = _terminal->LockForWriting();
SearchFlag flags{};
WI_SetFlagIf(flags, SearchFlag::CaseInsensitive, !caseSensitive);
WI_SetFlagIf(flags, SearchFlag::RegularExpression, regularExpression);
const auto searchInvalidated = _searcher.IsStale(*_terminal.get(), text, flags);

if (searchInvalidated || !resetOnly)
Expand Down Expand Up @@ -1702,6 +1703,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
.TotalMatches = totalMatches,
.CurrentMatch = currentMatch,
.SearchInvalidated = searchInvalidated,
.SearchRegexInvalid = !_searcher.IsOk(),
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SetSelectionAnchor(const til::point position);
void SetEndSelectionPoint(const til::point position);

SearchResults Search(const std::wstring_view& text, bool goForward, bool caseSensitive, bool reset);
SearchResults Search(const std::wstring_view& text, bool goForward, bool caseSensitive, bool regularExpression, bool reset);
const std::vector<til::point_span>& SearchResultRows() const noexcept;
void ClearSearch();
void SnapSearchResultToSelection(bool snap) noexcept;
Expand Down
3 changes: 2 additions & 1 deletion src/cascadia/TerminalControl/ControlCore.idl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ namespace Microsoft.Terminal.Control
Int32 TotalMatches;
Int32 CurrentMatch;
Boolean SearchInvalidated;
Boolean SearchRegexInvalid;
};

[default_interface] runtimeclass SelectionColor
Expand Down Expand Up @@ -134,7 +135,7 @@ namespace Microsoft.Terminal.Control
void ResumeRendering();
void BlinkAttributeTick();

SearchResults Search(String text, Boolean goForward, Boolean caseSensitive, Boolean reset);
SearchResults Search(String text, Boolean goForward, Boolean caseSensitive, Boolean regularExpression, Boolean reset);
void ClearSearch();
Boolean SnapSearchResultToSelection;

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 @@ -300,4 +300,16 @@ Please either install the missing font or choose another one.</value>
<value>Restored</value>
<comment>"Restored" as in "This content was restored"</comment>
</data>
</root>
<data name="SearchBox_RegularExpression.ToolTipService.ToolTip" xml:space="preserve">
<value>Regular Expression</value>
<comment>The tooltip text for the button on the search box control governing the use of "regular expressions" ("regex").</comment>
</data>
<data name="SearchBox_RegularExpression.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Regular Expression Search</value>
<comment>The accessibility description text for the button on the search box control governing the use of "regular expressions" ("regex").</comment>
</data>
<data name="SearchRegexInvalid" xml:space="preserve">
<value>invalid</value>
<comment>This brief message is displayed when a regular expression is invalid.</comment>
</data>
</root>
38 changes: 29 additions & 9 deletions src/cascadia/TerminalControl/SearchBoxControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_focusableElements.insert(TextBox());
_focusableElements.insert(CloseButton());
_focusableElements.insert(CaseSensitivityButton());
_focusableElements.insert(RegexButton());
_focusableElements.insert(GoForwardButton());
_focusableElements.insert(GoBackwardButton());

Expand Down Expand Up @@ -224,6 +225,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return CaseSensitivityButton().IsChecked().GetBoolean();
}

bool SearchBoxControl::RegularExpression()
{
return RegexButton().IsChecked().GetBoolean();
}

// Method Description:
// - Handler for pressing Enter on TextBox, trigger
// text search
Expand All @@ -245,11 +251,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto state = CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift);
if (WI_IsFlagSet(state, CoreVirtualKeyStates::Down))
{
Search.raise(Text(), !GoForward(), CaseSensitive());
Search.raise(Text(), !GoForward(), CaseSensitive(), RegularExpression());
}
else
{
Search.raise(Text(), GoForward(), CaseSensitive());
Search.raise(Text(), GoForward(), CaseSensitive(), RegularExpression());
}
e.Handled(true);
}
Expand Down Expand Up @@ -340,7 +346,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}

// kick off search
Search.raise(Text(), GoForward(), CaseSensitive());
Search.raise(Text(), GoForward(), CaseSensitive(), RegularExpression());
}

// Method Description:
Expand All @@ -361,7 +367,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}

// kick off search
Search.raise(Text(), GoForward(), CaseSensitive());
Search.raise(Text(), GoForward(), CaseSensitive(), RegularExpression());
}

// Method Description:
Expand Down Expand Up @@ -399,7 +405,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void SearchBoxControl::TextBoxTextChanged(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
{
SearchChanged.raise(Text(), GoForward(), CaseSensitive());
SearchChanged.raise(Text(), GoForward(), CaseSensitive(), RegularExpression());
}

// Method Description:
Expand All @@ -411,7 +417,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void SearchBoxControl::CaseSensitivityButtonClicked(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
{
SearchChanged.raise(Text(), GoForward(), CaseSensitive());
SearchChanged.raise(Text(), GoForward(), CaseSensitive(), RegularExpression());
}

void SearchBoxControl::RegexButtonClicked(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
{
SearchChanged.raise(Text(), GoForward(), CaseSensitive(), RegularExpression());
}

// Method Description:
Expand Down Expand Up @@ -504,7 +515,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
double SearchBoxControl::_GetStatusMaxWidth()
{
const auto fontSize = StatusBox().FontSize();
const auto maxLength = std::max({ _TextWidth(_FormatStatus(-1, -1), fontSize),
const auto maxLength = std::max({ _TextWidth(RS_(L"SearchRegexInvalid"), fontSize),
_TextWidth(_FormatStatus(-1, -1), fontSize),
_TextWidth(_FormatStatus(0, -1), fontSize),
_TextWidth(_FormatStatus(MaximumTotalResultsToShowInStatus, MaximumTotalResultsToShowInStatus - 1), fontSize),
_TextWidth(_FormatStatus(MaximumTotalResultsToShowInStatus + 1, MaximumTotalResultsToShowInStatus - 1), fontSize),
Expand All @@ -521,9 +533,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - currentMatch - the index of the current match (0-based)
// Return Value:
// - <none>
void SearchBoxControl::SetStatus(int32_t totalMatches, int32_t currentMatch)
void SearchBoxControl::SetStatus(int32_t totalMatches, int32_t currentMatch, bool searchRegexInvalid)
{
const auto status = _FormatStatus(totalMatches, currentMatch);
hstring status;
if (searchRegexInvalid)
{
status = RS_(L"SearchRegexInvalid");
}
else
{
status = _FormatStatus(totalMatches, currentMatch);
}
StatusBox().Text(status);
}

Expand Down
4 changes: 3 additions & 1 deletion src/cascadia/TerminalControl/SearchBoxControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::hstring Text();
bool GoForward();
bool CaseSensitive();
bool RegularExpression();
void SetFocusOnTextbox();
void PopulateTextbox(const winrt::hstring& text);
bool ContainsFocus();
void SetStatus(int32_t totalMatches, int32_t currentMatch);
void SetStatus(int32_t totalMatches, int32_t currentMatch, bool searchRegexInvalid);
void ClearStatus();

void GoBackwardClicked(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::UI::Xaml::RoutedEventArgs& /*e*/);
Expand All @@ -50,6 +51,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation

void TextBoxTextChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void CaseSensitivityButtonClicked(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void RegexButtonClicked(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void SearchBoxPointerPressedHandler(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void SearchBoxPointerReleasedHandler(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);

Expand Down
3 changes: 1 addition & 2 deletions src/cascadia/TerminalControl/SearchBoxControl.idl
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@

namespace Microsoft.Terminal.Control
{
delegate void SearchHandler(String query, Boolean goForward, Boolean isCaseSensitive);
delegate void SearchHandler(String query, Boolean goForward, Boolean isCaseSensitive, Boolean regularExpression);

[default_interface] runtimeclass SearchBoxControl : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
SearchBoxControl();
void SetFocusOnTextbox();
void PopulateTextbox(String text);
Boolean ContainsFocus();
void SetStatus(Int32 totalMatches, Int32 currentMatch);
void ClearStatus();
Windows.Foundation.Rect ContentClipRect{ get; };
Double OpenAnimationStartPoint{ get; };
Expand Down
11 changes: 11 additions & 0 deletions src/cascadia/TerminalControl/SearchBoxControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,17 @@
<PathIcon Data="M8.87305 10H7.60156L6.5625 7.25195H2.40625L1.42871 10H0.150391L3.91016 0.197266H5.09961L8.87305 10ZM6.18652 6.21973L4.64844 2.04297C4.59831 1.90625 4.54818 1.6875 4.49805 1.38672H4.4707C4.42513 1.66471 4.37272 1.88346 4.31348 2.04297L2.78906 6.21973H6.18652ZM15.1826 10H14.0615V8.90625H14.0342C13.5465 9.74479 12.8288 10.1641 11.8809 10.1641C11.1836 10.1641 10.6367 9.97949 10.2402 9.61035C9.84831 9.24121 9.65234 8.7513 9.65234 8.14062C9.65234 6.83268 10.4225 6.07161 11.9629 5.85742L14.0615 5.56348C14.0615 4.37402 13.5807 3.7793 12.6191 3.7793C11.776 3.7793 11.015 4.06641 10.3359 4.64062V3.49219C11.0241 3.05469 11.8171 2.83594 12.7148 2.83594C14.36 2.83594 15.1826 3.70638 15.1826 5.44727V10ZM14.0615 6.45898L12.373 6.69141C11.8535 6.76432 11.4616 6.89421 11.1973 7.08105C10.9329 7.26335 10.8008 7.58919 10.8008 8.05859C10.8008 8.40039 10.9215 8.68066 11.1631 8.89941C11.4092 9.11361 11.735 9.2207 12.1406 9.2207C12.6966 9.2207 13.1546 9.02702 13.5146 8.63965C13.8792 8.24772 14.0615 7.75326 14.0615 7.15625V6.45898Z" />
</ToggleButton>

<ToggleButton x:Name="RegexButton"
x:Uid="SearchBox_RegularExpression"
Width="32"
Height="32"
Margin="4,0"
Padding="0"
BackgroundSizing="OuterBorderEdge"
Click="RegexButtonClicked">
<PathIcon Data="M 11.7716,12.7647 V 14.2481 H 11.06066 V 12.8194 C 10.08996,12.8194 9.30156,12.62344 8.69546,12.23151 V 11.04201 C 8.95978,11.27443 9.31981,11.4704 9.77556,11.6299 10.23585,11.78485 10.66423,11.86232 11.06076,11.86232 V 8.36232 C 10.05816,7.87925 9.40876,7.43491 9.11256,7.02932 8.81634,6.61916 8.66822,6.13609 8.66822,5.58012 8.66822,4.91931 8.89381,4.34962 9.34498,3.87112 9.79615,3.38805 10.36808,3.09866 11.06078,3.00296 V 1.77246 H 11.77172 V 2.97556 C 12.66495,3.002904 13.28242,3.13051 13.62422,3.35837 V 4.52047 C 13.15938,4.15589 12.54182,3.95992 11.77172,3.93258 V 7.54198 C 12.71964,7.99315 13.36682,8.43065 13.71312,8.85448 14.06403,9.27375 14.23949,9.75227 14.23949,10.28998 14.23949,10.93712 14.02074,11.48168 13.58324,11.92378 13.1503,12.36128 12.54644,12.64155 11.77174,12.7646 Z M 11.06066,7.1592 V 3.9737 C 10.67785,4.051174 10.37479,4.22207 10.15148,4.4864 9.92817,4.74617 9.81652,5.0629 9.81652,5.4366 9.81652,5.82853 9.90767,6.14982 10.08996,6.40047 10.27225,6.65112 10.59582,6.90405 11.06066,7.15926 Z M 11.7716,8.7178 V 11.8076 C 12.65116,11.61619 13.0909,11.14224 13.0909,10.3857 13.0909,9.75679 12.65112,9.2008 11.7716,8.7177 Z M 8.0089,8.5538 H 6.9835 L 4.714,4.3224 H 4.672984 L 2.560684,8.5538 H 1.555784 L 4.440584,2.8526 H 4.884924 Z " />
</ToggleButton>

<Button x:Name="CloseButton"
x:Uid="SearchBox_Close"
Width="32"
Expand Down
17 changes: 10 additions & 7 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
else
{
_handleSearchResults(_core.Search(_searchBox->Text(), goForward, _searchBox->CaseSensitive(), false));
_handleSearchResults(_core.Search(_searchBox->Text(), goForward, _searchBox->CaseSensitive(), _searchBox->RegularExpression(), false));
}
}

Expand Down Expand Up @@ -595,9 +595,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void TermControl::_Search(const winrt::hstring& text,
const bool goForward,
const bool caseSensitive)
const bool caseSensitive,
const bool regularExpression)
{
_handleSearchResults(_core.Search(text, goForward, caseSensitive, false));
_handleSearchResults(_core.Search(text, goForward, caseSensitive, regularExpression, false));
}

// Method Description:
Expand All @@ -610,11 +611,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void TermControl::_SearchChanged(const winrt::hstring& text,
const bool goForward,
const bool caseSensitive)
const bool caseSensitive,
const bool regularExpression)
{
if (_searchBox && _searchBox->Visibility() == Visibility::Visible)
{
_handleSearchResults(_core.Search(text, goForward, caseSensitive, false));
_handleSearchResults(_core.Search(text, goForward, caseSensitive, regularExpression, false));
}
}

Expand Down Expand Up @@ -3606,7 +3608,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation

const auto goForward = _searchBox->GoForward();
const auto caseSensitive = _searchBox->CaseSensitive();
_handleSearchResults(_core.Search(text, goForward, caseSensitive, true));
const auto regularExpression = _searchBox->RegularExpression();
_handleSearchResults(_core.Search(text, goForward, caseSensitive, regularExpression, true));
}

void TermControl::_handleSearchResults(SearchResults results)
Expand All @@ -3616,7 +3619,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return;
}

_searchBox->SetStatus(results.TotalMatches, results.CurrentMatch);
_searchBox->SetStatus(results.TotalMatches, results.CurrentMatch, results.SearchRegexInvalid);

if (results.SearchInvalidated)
{
Expand Down
Loading

0 comments on commit e5314bf

Please sign in to comment.