mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-11 13:56:33 -06:00
Add support for regex search to conhost and Terminal (#17316)
This is broken down into individual reviewable commits. [Here is](https://github.com/microsoft/terminal/assets/189190/3b2ffd50-1350-4f3c-86b0-75abbd846969) a video of it in action! Part of #3920 (cherry picked from commit ecb56314762dcb9b41e177d05d669b28bbbe1490) Service-Card-Id: PVTI_lADOAF3p4s4AmhmszgTTM0g Service-Version: 1.21
This commit is contained in:
parent
dc8a830fea
commit
87c87b51fc
1
.github/actions/spelling/expect/expect.txt
vendored
1
.github/actions/spelling/expect/expect.txt
vendored
@ -607,6 +607,7 @@ FILTERONPASTE
|
|||||||
FINDCASE
|
FINDCASE
|
||||||
FINDDLG
|
FINDDLG
|
||||||
FINDDOWN
|
FINDDOWN
|
||||||
|
FINDREGEX
|
||||||
FINDSTRINGEXACT
|
FINDSTRINGEXACT
|
||||||
FINDUP
|
FINDUP
|
||||||
FIter
|
FIter
|
||||||
|
|||||||
@ -8,24 +8,26 @@
|
|||||||
|
|
||||||
using namespace Microsoft::Console::Types;
|
using namespace Microsoft::Console::Types;
|
||||||
|
|
||||||
bool Search::IsStale(const Microsoft::Console::Render::IRenderData& renderData, const std::wstring_view& needle, bool caseInsensitive) const noexcept
|
bool Search::IsStale(const Microsoft::Console::Render::IRenderData& renderData, const std::wstring_view& needle, SearchFlag flags) const noexcept
|
||||||
{
|
{
|
||||||
return _renderData != &renderData ||
|
return _renderData != &renderData ||
|
||||||
_needle != needle ||
|
_needle != needle ||
|
||||||
_caseInsensitive != caseInsensitive ||
|
_flags != flags ||
|
||||||
_lastMutationId != renderData.GetTextBuffer().GetLastMutationId();
|
_lastMutationId != renderData.GetTextBuffer().GetLastMutationId();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Search::Reset(Microsoft::Console::Render::IRenderData& renderData, const std::wstring_view& needle, bool caseInsensitive, bool reverse)
|
bool Search::Reset(Microsoft::Console::Render::IRenderData& renderData, const std::wstring_view& needle, SearchFlag flags, bool reverse)
|
||||||
{
|
{
|
||||||
const auto& textBuffer = renderData.GetTextBuffer();
|
const auto& textBuffer = renderData.GetTextBuffer();
|
||||||
|
|
||||||
_renderData = &renderData;
|
_renderData = &renderData;
|
||||||
_needle = needle;
|
_needle = needle;
|
||||||
_caseInsensitive = caseInsensitive;
|
_flags = flags;
|
||||||
_lastMutationId = textBuffer.GetLastMutationId();
|
_lastMutationId = textBuffer.GetLastMutationId();
|
||||||
|
|
||||||
_results = textBuffer.SearchText(needle, caseInsensitive);
|
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;
|
_index = reverse ? gsl::narrow_cast<ptrdiff_t>(_results.size()) - 1 : 0;
|
||||||
_step = reverse ? -1 : 1;
|
_step = reverse ? -1 : 1;
|
||||||
return true;
|
return true;
|
||||||
@ -144,3 +146,8 @@ ptrdiff_t Search::CurrentMatch() const noexcept
|
|||||||
{
|
{
|
||||||
return _index;
|
return _index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Search::IsOk() const noexcept
|
||||||
|
{
|
||||||
|
return _ok;
|
||||||
|
}
|
||||||
|
|||||||
@ -20,13 +20,23 @@ Revision History:
|
|||||||
#include "textBuffer.hpp"
|
#include "textBuffer.hpp"
|
||||||
#include "../renderer/inc/IRenderData.hpp"
|
#include "../renderer/inc/IRenderData.hpp"
|
||||||
|
|
||||||
|
enum class SearchFlag : unsigned int
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
CaseInsensitive = 1 << 0,
|
||||||
|
RegularExpression = 1 << 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_ENUM_FLAG_OPERATORS(SearchFlag);
|
||||||
|
|
||||||
class Search final
|
class Search final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Search() = default;
|
Search() = default;
|
||||||
|
|
||||||
bool IsStale(const Microsoft::Console::Render::IRenderData& renderData, const std::wstring_view& needle, bool caseInsensitive) const noexcept;
|
bool IsStale(const Microsoft::Console::Render::IRenderData& renderData, const std::wstring_view& needle, SearchFlag flags) const noexcept;
|
||||||
bool Reset(Microsoft::Console::Render::IRenderData& renderData, const std::wstring_view& needle, bool caseInsensitive, bool reverse);
|
bool Reset(Microsoft::Console::Render::IRenderData& renderData, const std::wstring_view& needle, SearchFlag flags, bool reverse);
|
||||||
|
|
||||||
void MoveToCurrentSelection();
|
void MoveToCurrentSelection();
|
||||||
void MoveToPoint(til::point anchor) noexcept;
|
void MoveToPoint(til::point anchor) noexcept;
|
||||||
@ -39,14 +49,16 @@ public:
|
|||||||
const std::vector<til::point_span>& Results() const noexcept;
|
const std::vector<til::point_span>& Results() const noexcept;
|
||||||
std::vector<til::point_span>&& ExtractResults() noexcept;
|
std::vector<til::point_span>&& ExtractResults() noexcept;
|
||||||
ptrdiff_t CurrentMatch() const noexcept;
|
ptrdiff_t CurrentMatch() const noexcept;
|
||||||
|
bool IsOk() const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// _renderData is a pointer so that Search() is constexpr default constructable.
|
// _renderData is a pointer so that Search() is constexpr default constructable.
|
||||||
Microsoft::Console::Render::IRenderData* _renderData = nullptr;
|
Microsoft::Console::Render::IRenderData* _renderData = nullptr;
|
||||||
std::wstring _needle;
|
std::wstring _needle;
|
||||||
bool _caseInsensitive = false;
|
SearchFlag _flags{};
|
||||||
uint64_t _lastMutationId = 0;
|
uint64_t _lastMutationId = 0;
|
||||||
|
|
||||||
|
bool _ok{ false };
|
||||||
std::vector<til::point_span> _results;
|
std::vector<til::point_span> _results;
|
||||||
ptrdiff_t _index = 0;
|
ptrdiff_t _index = 0;
|
||||||
ptrdiff_t _step = 0;
|
ptrdiff_t _step = 0;
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
#include "../../types/inc/GlyphWidth.hpp"
|
#include "../../types/inc/GlyphWidth.hpp"
|
||||||
#include "../renderer/base/renderer.hpp"
|
#include "../renderer/base/renderer.hpp"
|
||||||
#include "../types/inc/utils.hpp"
|
#include "../types/inc/utils.hpp"
|
||||||
|
#include "search.h"
|
||||||
|
|
||||||
using namespace Microsoft::Console;
|
using namespace Microsoft::Console;
|
||||||
using namespace Microsoft::Console::Types;
|
using namespace Microsoft::Console::Types;
|
||||||
@ -3193,14 +3194,15 @@ void TextBuffer::CopyHyperlinkMaps(const TextBuffer& other)
|
|||||||
|
|
||||||
// Searches through the entire (committed) text buffer for `needle` and returns the coordinates in absolute coordinates.
|
// 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.
|
// The end coordinates of the returned ranges are considered inclusive.
|
||||||
std::vector<til::point_span> TextBuffer::SearchText(const std::wstring_view& needle, bool caseInsensitive) const
|
std::optional<std::vector<til::point_span>> TextBuffer::SearchText(const std::wstring_view& needle, SearchFlag flags) const
|
||||||
{
|
{
|
||||||
return SearchText(needle, caseInsensitive, 0, til::CoordTypeMax);
|
return SearchText(needle, flags, 0, til::CoordTypeMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Searches through the given rows [rowBeg,rowEnd) for `needle` and returns the coordinates in absolute coordinates.
|
// 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.
|
// 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, bool caseInsensitive, 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);
|
rowEnd = std::min(rowEnd, _estimateOffsetOfLastCommittedRow() + 1);
|
||||||
|
|
||||||
@ -3214,11 +3216,25 @@ std::vector<til::point_span> TextBuffer::SearchText(const std::wstring_view& nee
|
|||||||
|
|
||||||
auto text = ICU::UTextFromTextBuffer(*this, rowBeg, rowEnd);
|
auto text = ICU::UTextFromTextBuffer(*this, rowBeg, rowEnd);
|
||||||
|
|
||||||
uint32_t flags = UREGEX_LITERAL;
|
uint32_t icuFlags{ 0 };
|
||||||
WI_SetFlagIf(flags, UREGEX_CASE_INSENSITIVE, caseInsensitive);
|
WI_SetFlagIf(icuFlags, UREGEX_CASE_INSENSITIVE, WI_IsFlagSet(flags, SearchFlag::CaseInsensitive));
|
||||||
|
|
||||||
|
if (WI_IsFlagSet(flags, SearchFlag::RegularExpression))
|
||||||
|
{
|
||||||
|
WI_SetFlag(icuFlags, UREGEX_MULTILINE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WI_SetFlag(icuFlags, UREGEX_LITERAL);
|
||||||
|
}
|
||||||
|
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
const auto re = ICU::CreateRegex(needle, flags, &status);
|
const auto re = ICU::CreateRegex(needle, icuFlags, &status);
|
||||||
|
if (status > U_ZERO_ERROR)
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
uregex_setUText(re.get(), &text, &status);
|
uregex_setUText(re.get(), &text, &status);
|
||||||
|
|
||||||
if (uregex_find(re.get(), -1, &status))
|
if (uregex_find(re.get(), -1, &status))
|
||||||
|
|||||||
@ -58,6 +58,7 @@ filling in the last row, and updating the screen.
|
|||||||
#include "../buffer/out/textBufferTextIterator.hpp"
|
#include "../buffer/out/textBufferTextIterator.hpp"
|
||||||
|
|
||||||
struct URegularExpression;
|
struct URegularExpression;
|
||||||
|
enum class SearchFlag : unsigned int;
|
||||||
|
|
||||||
namespace Microsoft::Console::Render
|
namespace Microsoft::Console::Render
|
||||||
{
|
{
|
||||||
@ -293,8 +294,8 @@ public:
|
|||||||
|
|
||||||
static void Reflow(TextBuffer& oldBuffer, TextBuffer& newBuffer, const Microsoft::Console::Types::Viewport* lastCharacterViewport = nullptr, PositionInformation* positionInfo = nullptr);
|
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, bool caseInsensitive) const;
|
std::optional<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, bool caseInsensitive, til::CoordType rowBeg, til::CoordType rowEnd) 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
|
// Mark handling
|
||||||
std::vector<ScrollMark> GetMarkRows() const;
|
std::vector<ScrollMark> GetMarkRows() const;
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "WexTestClass.h"
|
#include "WexTestClass.h"
|
||||||
#include "../textBuffer.hpp"
|
#include "../textBuffer.hpp"
|
||||||
#include "../../renderer/inc/DummyRenderer.hpp"
|
#include "../../renderer/inc/DummyRenderer.hpp"
|
||||||
|
#include "../search.h"
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class WEX::TestExecution::VerifyOutputTraits<std::vector<til::point_span>>
|
class WEX::TestExecution::VerifyOutputTraits<std::vector<til::point_span>>
|
||||||
@ -49,15 +50,15 @@ class UTextAdapterTests
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto expected = std::vector{ s(0, 2), s(8, 10) };
|
auto expected = std::vector{ s(0, 2), s(8, 10) };
|
||||||
auto actual = buffer.SearchText(L"abc", false);
|
auto actual = buffer.SearchText(L"abc", SearchFlag::None);
|
||||||
VERIFY_ARE_EQUAL(expected, actual);
|
VERIFY_ARE_EQUAL(expected, actual);
|
||||||
|
|
||||||
expected = std::vector{ s(5, 5) };
|
expected = std::vector{ s(5, 5) };
|
||||||
actual = buffer.SearchText(L"𝒷", false);
|
actual = buffer.SearchText(L"𝒷", SearchFlag::None);
|
||||||
VERIFY_ARE_EQUAL(expected, actual);
|
VERIFY_ARE_EQUAL(expected, actual);
|
||||||
|
|
||||||
expected = std::vector{ s(12, 15) };
|
expected = std::vector{ s(12, 15) };
|
||||||
actual = buffer.SearchText(L"ネコ", false);
|
actual = buffer.SearchText(L"ネコ", SearchFlag::None);
|
||||||
VERIFY_ARE_EQUAL(expected, actual);
|
VERIFY_ARE_EQUAL(expected, actual);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1654,10 +1654,13 @@ 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 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();
|
const auto lock = _terminal->LockForWriting();
|
||||||
const auto searchInvalidated = _searcher.IsStale(*_terminal.get(), text, !caseSensitive);
|
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)
|
if (searchInvalidated || !resetOnly)
|
||||||
{
|
{
|
||||||
@ -1666,7 +1669,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
if (searchInvalidated)
|
if (searchInvalidated)
|
||||||
{
|
{
|
||||||
oldResults = _searcher.ExtractResults();
|
oldResults = _searcher.ExtractResults();
|
||||||
_searcher.Reset(*_terminal.get(), text, !caseSensitive, !goForward);
|
_searcher.Reset(*_terminal.get(), text, flags, !goForward);
|
||||||
|
|
||||||
if (SnapSearchResultToSelection())
|
if (SnapSearchResultToSelection())
|
||||||
{
|
{
|
||||||
@ -1700,6 +1703,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
.TotalMatches = totalMatches,
|
.TotalMatches = totalMatches,
|
||||||
.CurrentMatch = currentMatch,
|
.CurrentMatch = currentMatch,
|
||||||
.SearchInvalidated = searchInvalidated,
|
.SearchInvalidated = searchInvalidated,
|
||||||
|
.SearchRegexInvalid = !_searcher.IsOk(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -219,7 +219,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 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;
|
const std::vector<til::point_span>& SearchResultRows() const noexcept;
|
||||||
void ClearSearch();
|
void ClearSearch();
|
||||||
void SnapSearchResultToSelection(bool snap) noexcept;
|
void SnapSearchResultToSelection(bool snap) noexcept;
|
||||||
|
|||||||
@ -54,6 +54,7 @@ namespace Microsoft.Terminal.Control
|
|||||||
Int32 TotalMatches;
|
Int32 TotalMatches;
|
||||||
Int32 CurrentMatch;
|
Int32 CurrentMatch;
|
||||||
Boolean SearchInvalidated;
|
Boolean SearchInvalidated;
|
||||||
|
Boolean SearchRegexInvalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
[default_interface] runtimeclass SelectionColor
|
[default_interface] runtimeclass SelectionColor
|
||||||
@ -134,7 +135,7 @@ namespace Microsoft.Terminal.Control
|
|||||||
void ResumeRendering();
|
void ResumeRendering();
|
||||||
void BlinkAttributeTick();
|
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();
|
void ClearSearch();
|
||||||
Boolean SnapSearchResultToSelection;
|
Boolean SnapSearchResultToSelection;
|
||||||
|
|
||||||
|
|||||||
@ -304,4 +304,16 @@ Please either install the missing font or choose another one.</value>
|
|||||||
<value>Restored</value>
|
<value>Restored</value>
|
||||||
<comment>"Restored" as in "This content was restored"</comment>
|
<comment>"Restored" as in "This content was restored"</comment>
|
||||||
</data>
|
</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>
|
||||||
|
|||||||
@ -30,6 +30,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
_focusableElements.insert(TextBox());
|
_focusableElements.insert(TextBox());
|
||||||
_focusableElements.insert(CloseButton());
|
_focusableElements.insert(CloseButton());
|
||||||
_focusableElements.insert(CaseSensitivityButton());
|
_focusableElements.insert(CaseSensitivityButton());
|
||||||
|
_focusableElements.insert(RegexButton());
|
||||||
_focusableElements.insert(GoForwardButton());
|
_focusableElements.insert(GoForwardButton());
|
||||||
_focusableElements.insert(GoBackwardButton());
|
_focusableElements.insert(GoBackwardButton());
|
||||||
|
|
||||||
@ -235,6 +236,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
return CaseSensitivityButton().IsChecked().GetBoolean();
|
return CaseSensitivityButton().IsChecked().GetBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SearchBoxControl::RegularExpression()
|
||||||
|
{
|
||||||
|
return RegexButton().IsChecked().GetBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Handler for pressing Enter on TextBox, trigger
|
// - Handler for pressing Enter on TextBox, trigger
|
||||||
// text search
|
// text search
|
||||||
@ -256,11 +262,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
const auto state = CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift);
|
const auto state = CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift);
|
||||||
if (WI_IsFlagSet(state, CoreVirtualKeyStates::Down))
|
if (WI_IsFlagSet(state, CoreVirtualKeyStates::Down))
|
||||||
{
|
{
|
||||||
Search.raise(Text(), !GoForward(), CaseSensitive());
|
Search.raise(Text(), !GoForward(), CaseSensitive(), RegularExpression());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Search.raise(Text(), GoForward(), CaseSensitive());
|
Search.raise(Text(), GoForward(), CaseSensitive(), RegularExpression());
|
||||||
}
|
}
|
||||||
e.Handled(true);
|
e.Handled(true);
|
||||||
}
|
}
|
||||||
@ -351,7 +357,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
}
|
}
|
||||||
|
|
||||||
// kick off search
|
// kick off search
|
||||||
Search.raise(Text(), GoForward(), CaseSensitive());
|
Search.raise(Text(), GoForward(), CaseSensitive(), RegularExpression());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
@ -372,7 +378,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
}
|
}
|
||||||
|
|
||||||
// kick off search
|
// kick off search
|
||||||
Search.raise(Text(), GoForward(), CaseSensitive());
|
Search.raise(Text(), GoForward(), CaseSensitive(), RegularExpression());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
@ -410,7 +416,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
// - <none>
|
// - <none>
|
||||||
void SearchBoxControl::TextBoxTextChanged(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
|
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:
|
// Method Description:
|
||||||
@ -422,7 +428,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
// - <none>
|
// - <none>
|
||||||
void SearchBoxControl::CaseSensitivityButtonClicked(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
|
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:
|
// Method Description:
|
||||||
@ -515,7 +526,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
double SearchBoxControl::_GetStatusMaxWidth()
|
double SearchBoxControl::_GetStatusMaxWidth()
|
||||||
{
|
{
|
||||||
const auto fontSize = StatusBox().FontSize();
|
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(0, -1), fontSize),
|
||||||
_TextWidth(_FormatStatus(MaximumTotalResultsToShowInStatus, MaximumTotalResultsToShowInStatus - 1), fontSize),
|
_TextWidth(_FormatStatus(MaximumTotalResultsToShowInStatus, MaximumTotalResultsToShowInStatus - 1), fontSize),
|
||||||
_TextWidth(_FormatStatus(MaximumTotalResultsToShowInStatus + 1, MaximumTotalResultsToShowInStatus - 1), fontSize),
|
_TextWidth(_FormatStatus(MaximumTotalResultsToShowInStatus + 1, MaximumTotalResultsToShowInStatus - 1), fontSize),
|
||||||
@ -532,9 +544,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
// - currentMatch - the index of the current match (0-based)
|
// - currentMatch - the index of the current match (0-based)
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - <none>
|
// - <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);
|
StatusBox().Text(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -39,10 +39,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
winrt::hstring Text();
|
winrt::hstring Text();
|
||||||
bool GoForward();
|
bool GoForward();
|
||||||
bool CaseSensitive();
|
bool CaseSensitive();
|
||||||
|
bool RegularExpression();
|
||||||
void SetFocusOnTextbox();
|
void SetFocusOnTextbox();
|
||||||
void PopulateTextbox(const winrt::hstring& text);
|
void PopulateTextbox(const winrt::hstring& text);
|
||||||
bool ContainsFocus();
|
bool ContainsFocus();
|
||||||
void SetStatus(int32_t totalMatches, int32_t currentMatch);
|
void SetStatus(int32_t totalMatches, int32_t currentMatch, bool searchRegexInvalid);
|
||||||
void ClearStatus();
|
void ClearStatus();
|
||||||
|
|
||||||
void GoBackwardClicked(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::UI::Xaml::RoutedEventArgs& /*e*/);
|
void GoBackwardClicked(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::UI::Xaml::RoutedEventArgs& /*e*/);
|
||||||
@ -51,6 +52,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
|
|
||||||
void TextBoxTextChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
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 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 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);
|
void SearchBoxPointerReleasedHandler(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace Microsoft.Terminal.Control
|
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
|
[default_interface] runtimeclass SearchBoxControl : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
@ -11,7 +11,6 @@ namespace Microsoft.Terminal.Control
|
|||||||
void SetFocusOnTextbox();
|
void SetFocusOnTextbox();
|
||||||
void PopulateTextbox(String text);
|
void PopulateTextbox(String text);
|
||||||
Boolean ContainsFocus();
|
Boolean ContainsFocus();
|
||||||
void SetStatus(Int32 totalMatches, Int32 currentMatch);
|
|
||||||
void ClearStatus();
|
void ClearStatus();
|
||||||
Windows.Foundation.Rect ContentClipRect{ get; };
|
Windows.Foundation.Rect ContentClipRect{ get; };
|
||||||
Double OpenAnimationStartPoint{ get; };
|
Double OpenAnimationStartPoint{ get; };
|
||||||
|
|||||||
@ -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" />
|
<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>
|
||||||
|
|
||||||
|
<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"
|
<Button x:Name="CloseButton"
|
||||||
x:Uid="SearchBox_Close"
|
x:Uid="SearchBox_Close"
|
||||||
Width="32"
|
Width="32"
|
||||||
|
|||||||
@ -568,7 +568,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_handleSearchResults(_core.Search(_searchBox->Text(), goForward, _searchBox->CaseSensitive(), false));
|
_handleSearchResults(_core.Search(_searchBox->Text(), goForward, _searchBox->CaseSensitive(), _searchBox->RegularExpression(), false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,11 +597,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
// - <none>
|
// - <none>
|
||||||
void TermControl::_Search(const winrt::hstring& text,
|
void TermControl::_Search(const winrt::hstring& text,
|
||||||
const bool goForward,
|
const bool goForward,
|
||||||
const bool caseSensitive)
|
const bool caseSensitive,
|
||||||
|
const bool regularExpression)
|
||||||
{
|
{
|
||||||
if (_searchBox && _searchBox->IsOpen())
|
if (_searchBox && _searchBox->IsOpen())
|
||||||
{
|
{
|
||||||
_handleSearchResults(_core.Search(text, goForward, caseSensitive, false));
|
_handleSearchResults(_core.Search(text, goForward, caseSensitive, regularExpression, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,13 +616,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
// - <none>
|
// - <none>
|
||||||
void TermControl::_SearchChanged(const winrt::hstring& text,
|
void TermControl::_SearchChanged(const winrt::hstring& text,
|
||||||
const bool goForward,
|
const bool goForward,
|
||||||
const bool caseSensitive)
|
const bool caseSensitive,
|
||||||
|
const bool regularExpression)
|
||||||
{
|
{
|
||||||
if (_searchBox && _searchBox->IsOpen())
|
if (_searchBox && _searchBox->IsOpen())
|
||||||
{
|
{
|
||||||
// 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, true);
|
const auto result = _core.Search(text, goForward, caseSensitive, regularExpression, true);
|
||||||
_handleSearchResults(result);
|
_handleSearchResults(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3747,7 +3749,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();
|
||||||
_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)
|
void TermControl::_handleSearchResults(SearchResults results)
|
||||||
@ -3764,7 +3767,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_searchBox->SetStatus(results.TotalMatches, results.CurrentMatch);
|
_searchBox->SetStatus(results.TotalMatches, results.CurrentMatch, results.SearchRegexInvalid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (results.SearchInvalidated)
|
if (results.SearchInvalidated)
|
||||||
|
|||||||
@ -397,8 +397,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||||||
|
|
||||||
double _GetAutoScrollSpeed(double cursorDistanceFromBorder) const;
|
double _GetAutoScrollSpeed(double cursorDistanceFromBorder) const;
|
||||||
|
|
||||||
void _Search(const winrt::hstring& text, const bool goForward, const bool caseSensitive);
|
void _Search(const winrt::hstring& text, const bool goForward, const bool caseSensitive, const bool regularExpression);
|
||||||
void _SearchChanged(const winrt::hstring& text, const bool goForward, const bool caseSensitive);
|
void _SearchChanged(const winrt::hstring& text, const bool goForward, const bool caseSensitive, const bool regularExpression);
|
||||||
void _CloseSearchBoxControl(const winrt::Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
void _CloseSearchBoxControl(const winrt::Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||||
void _refreshSearch();
|
void _refreshSearch();
|
||||||
void _handleSearchResults(SearchResults results);
|
void _handleSearchResults(SearchResults results);
|
||||||
|
|||||||
@ -1568,7 +1568,7 @@ void Terminal::ColorSelection(const TextAttribute& attr, winrt::Microsoft::Termi
|
|||||||
|
|
||||||
if (!textView.empty())
|
if (!textView.empty())
|
||||||
{
|
{
|
||||||
const auto hits = textBuffer.SearchText(textView, true);
|
const auto hits = textBuffer.SearchText(textView, SearchFlag::CaseInsensitive).value_or(std::vector<til::point_span>{});
|
||||||
for (const auto& s : hits)
|
for (const auto& s : hits)
|
||||||
{
|
{
|
||||||
colorSelection(s.start, s.end, attr);
|
colorSelection(s.start, s.end, attr);
|
||||||
|
|||||||
@ -83,6 +83,7 @@ BEGIN
|
|||||||
EDITTEXT ID_CONSOLE_FINDSTR, 47, 7, 128, 12, WS_GROUP | WS_TABSTOP | ES_AUTOHSCROLL
|
EDITTEXT ID_CONSOLE_FINDSTR, 47, 7, 128, 12, WS_GROUP | WS_TABSTOP | ES_AUTOHSCROLL
|
||||||
|
|
||||||
AUTOCHECKBOX "Match &case", ID_CONSOLE_FINDCASE, 4, 42, 64, 12
|
AUTOCHECKBOX "Match &case", ID_CONSOLE_FINDCASE, 4, 42, 64, 12
|
||||||
|
AUTOCHECKBOX "Regula&r expression", ID_CONSOLE_FINDREGEX, 4, 28, 96, 12
|
||||||
|
|
||||||
GROUPBOX "Direction", -1, 107, 26, 68, 28, WS_GROUP
|
GROUPBOX "Direction", -1, 107, 26, 68, 28, WS_GROUP
|
||||||
AUTORADIOBUTTON "&Up", ID_CONSOLE_FINDUP, 111, 38, 25, 12, WS_GROUP
|
AUTORADIOBUTTON "&Up", ID_CONSOLE_FINDUP, 111, 38, 25, 12, WS_GROUP
|
||||||
|
|||||||
@ -49,5 +49,6 @@ Author(s):
|
|||||||
#define ID_CONSOLE_FINDCASE 602
|
#define ID_CONSOLE_FINDCASE 602
|
||||||
#define ID_CONSOLE_FINDUP 603
|
#define ID_CONSOLE_FINDUP 603
|
||||||
#define ID_CONSOLE_FINDDOWN 604
|
#define ID_CONSOLE_FINDDOWN 604
|
||||||
|
#define ID_CONSOLE_FINDREGEX 605
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|||||||
@ -701,7 +701,7 @@ bool Selection::_HandleColorSelection(const INPUT_KEY_INFO* const pInputKeyInfo)
|
|||||||
ClearSelection();
|
ClearSelection();
|
||||||
|
|
||||||
const auto& textBuffer = gci.renderData.GetTextBuffer();
|
const auto& textBuffer = gci.renderData.GetTextBuffer();
|
||||||
const auto hits = textBuffer.SearchText(str, true);
|
const auto hits = textBuffer.SearchText(str, SearchFlag::CaseInsensitive).value_or(std::vector<til::point_span>{});
|
||||||
for (const auto& s : hits)
|
for (const auto& s : hits)
|
||||||
{
|
{
|
||||||
ColorSelection(s.start, s.end, selectionAttr);
|
ColorSelection(s.start, s.end, selectionAttr);
|
||||||
|
|||||||
@ -98,7 +98,7 @@ class SearchTests
|
|||||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
|
||||||
Search s;
|
Search s;
|
||||||
s.Reset(gci.renderData, L"AB", false, false);
|
s.Reset(gci.renderData, L"AB", SearchFlag::None, false);
|
||||||
DoFoundChecks(s, {}, 1, false);
|
DoFoundChecks(s, {}, 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ class SearchTests
|
|||||||
{
|
{
|
||||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
Search s;
|
Search s;
|
||||||
s.Reset(gci.renderData, L"\x304b", false, false);
|
s.Reset(gci.renderData, L"\x304b", SearchFlag::None, false);
|
||||||
DoFoundChecks(s, { 2, 0 }, 1, false);
|
DoFoundChecks(s, { 2, 0 }, 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ class SearchTests
|
|||||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
|
||||||
Search s;
|
Search s;
|
||||||
s.Reset(gci.renderData, L"ab", true, false);
|
s.Reset(gci.renderData, L"ab", SearchFlag::CaseInsensitive, false);
|
||||||
DoFoundChecks(s, {}, 1, false);
|
DoFoundChecks(s, {}, 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ class SearchTests
|
|||||||
{
|
{
|
||||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
Search s;
|
Search s;
|
||||||
s.Reset(gci.renderData, L"\x304b", true, false);
|
s.Reset(gci.renderData, L"\x304b", SearchFlag::CaseInsensitive, false);
|
||||||
DoFoundChecks(s, { 2, 0 }, 1, false);
|
DoFoundChecks(s, { 2, 0 }, 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ class SearchTests
|
|||||||
{
|
{
|
||||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
Search s;
|
Search s;
|
||||||
s.Reset(gci.renderData, L"AB", false, true);
|
s.Reset(gci.renderData, L"AB", SearchFlag::None, true);
|
||||||
DoFoundChecks(s, { 0, 3 }, -1, true);
|
DoFoundChecks(s, { 0, 3 }, -1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ class SearchTests
|
|||||||
{
|
{
|
||||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
Search s;
|
Search s;
|
||||||
s.Reset(gci.renderData, L"\x304b", false, true);
|
s.Reset(gci.renderData, L"\x304b", SearchFlag::None, true);
|
||||||
DoFoundChecks(s, { 2, 3 }, -1, true);
|
DoFoundChecks(s, { 2, 3 }, -1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ class SearchTests
|
|||||||
{
|
{
|
||||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
Search s;
|
Search s;
|
||||||
s.Reset(gci.renderData, L"ab", true, true);
|
s.Reset(gci.renderData, L"ab", SearchFlag::CaseInsensitive, true);
|
||||||
DoFoundChecks(s, { 0, 3 }, -1, true);
|
DoFoundChecks(s, { 0, 3 }, -1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +155,52 @@ class SearchTests
|
|||||||
{
|
{
|
||||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
Search s;
|
Search s;
|
||||||
s.Reset(gci.renderData, L"\x304b", true, true);
|
s.Reset(gci.renderData, L"\x304b", SearchFlag::CaseInsensitive, true);
|
||||||
DoFoundChecks(s, { 2, 3 }, -1, true);
|
DoFoundChecks(s, { 2, 3 }, -1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(ForwardCaseSensitiveRegex)
|
||||||
|
{
|
||||||
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
|
||||||
|
Search s;
|
||||||
|
s.Reset(gci.renderData, L"[BA]{2}", SearchFlag::RegularExpression, false);
|
||||||
|
DoFoundChecks(s, {}, 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(ForwardCaseSensitiveRegexJapanese)
|
||||||
|
{
|
||||||
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
Search s;
|
||||||
|
// N.B. this is not a literal U+30xx, but a regex escape sequence \x{30xx}
|
||||||
|
s.Reset(gci.renderData, LR"-([\x{3041}-\x{304c}])-", SearchFlag::RegularExpression, false);
|
||||||
|
DoFoundChecks(s, { 2, 0 }, 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(ForwardCaseInsensitiveRegex)
|
||||||
|
{
|
||||||
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
|
||||||
|
Search s;
|
||||||
|
s.Reset(gci.renderData, L"ab", SearchFlag::CaseInsensitive | SearchFlag::RegularExpression, false);
|
||||||
|
DoFoundChecks(s, {}, 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(ForwardCaseInsensitiveRegexJapanese)
|
||||||
|
{
|
||||||
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
Search s;
|
||||||
|
// N.B. this is not a literal U+30xx, but a regex escape sequence \x{30xx}
|
||||||
|
s.Reset(gci.renderData, LR"-([\x{3041}-\x{304c}])-", SearchFlag::CaseInsensitive | SearchFlag::RegularExpression, false);
|
||||||
|
DoFoundChecks(s, { 2, 0 }, 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(ForwardCaseSensitiveRegexWithCaseInsensitiveFlag)
|
||||||
|
{
|
||||||
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
|
||||||
|
Search s;
|
||||||
|
s.Reset(gci.renderData, L"(?i)ab", SearchFlag::RegularExpression, false);
|
||||||
|
DoFoundChecks(s, {}, 1, false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -23,7 +23,7 @@ INT_PTR CALLBACK FindDialogProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM l
|
|||||||
// This bool is used to track which option - up or down - was used to perform the last search. That way, the next time the
|
// This bool is used to track which option - up or down - was used to perform the last search. That way, the next time the
|
||||||
// find dialog is opened, it will default to the last used option.
|
// find dialog is opened, it will default to the last used option.
|
||||||
static auto reverse = true;
|
static auto reverse = true;
|
||||||
static auto caseInsensitive = true;
|
static SearchFlag flags{ SearchFlag::CaseInsensitive };
|
||||||
static std::wstring lastFindString;
|
static std::wstring lastFindString;
|
||||||
static Search searcher;
|
static Search searcher;
|
||||||
|
|
||||||
@ -32,7 +32,8 @@ INT_PTR CALLBACK FindDialogProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM l
|
|||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
SetWindowLongPtrW(hWnd, DWLP_USER, lParam);
|
SetWindowLongPtrW(hWnd, DWLP_USER, lParam);
|
||||||
CheckRadioButton(hWnd, ID_CONSOLE_FINDUP, ID_CONSOLE_FINDDOWN, (reverse ? ID_CONSOLE_FINDUP : ID_CONSOLE_FINDDOWN));
|
CheckRadioButton(hWnd, ID_CONSOLE_FINDUP, ID_CONSOLE_FINDDOWN, (reverse ? ID_CONSOLE_FINDUP : ID_CONSOLE_FINDDOWN));
|
||||||
CheckDlgButton(hWnd, ID_CONSOLE_FINDCASE, !caseInsensitive);
|
CheckDlgButton(hWnd, ID_CONSOLE_FINDCASE, WI_IsFlagClear(flags, SearchFlag::CaseInsensitive));
|
||||||
|
CheckDlgButton(hWnd, ID_CONSOLE_FINDREGEX, WI_IsFlagSet(flags, SearchFlag::RegularExpression));
|
||||||
SetDlgItemTextW(hWnd, ID_CONSOLE_FINDSTR, lastFindString.c_str());
|
SetDlgItemTextW(hWnd, ID_CONSOLE_FINDSTR, lastFindString.c_str());
|
||||||
return TRUE;
|
return TRUE;
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
@ -46,15 +47,16 @@ INT_PTR CALLBACK FindDialogProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM l
|
|||||||
length = GetDlgItemTextW(hWnd, ID_CONSOLE_FINDSTR, lastFindString.data(), gsl::narrow_cast<int>(length + 1));
|
length = GetDlgItemTextW(hWnd, ID_CONSOLE_FINDSTR, lastFindString.data(), gsl::narrow_cast<int>(length + 1));
|
||||||
lastFindString.resize(length);
|
lastFindString.resize(length);
|
||||||
|
|
||||||
caseInsensitive = IsDlgButtonChecked(hWnd, ID_CONSOLE_FINDCASE) == 0;
|
WI_UpdateFlag(flags, SearchFlag::CaseInsensitive, IsDlgButtonChecked(hWnd, ID_CONSOLE_FINDCASE) == 0);
|
||||||
|
WI_UpdateFlag(flags, SearchFlag::RegularExpression, IsDlgButtonChecked(hWnd, ID_CONSOLE_FINDREGEX) != 0);
|
||||||
reverse = IsDlgButtonChecked(hWnd, ID_CONSOLE_FINDDOWN) == 0;
|
reverse = IsDlgButtonChecked(hWnd, ID_CONSOLE_FINDDOWN) == 0;
|
||||||
|
|
||||||
LockConsole();
|
LockConsole();
|
||||||
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
|
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
|
||||||
|
|
||||||
if (searcher.IsStale(gci.renderData, lastFindString, caseInsensitive))
|
if (searcher.IsStale(gci.renderData, lastFindString, flags))
|
||||||
{
|
{
|
||||||
searcher.Reset(gci.renderData, lastFindString, caseInsensitive, reverse);
|
searcher.Reset(gci.renderData, lastFindString, flags, reverse);
|
||||||
searcher.MoveToCurrentSelection();
|
searcher.MoveToCurrentSelection();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@ -46,5 +46,6 @@ Author(s):
|
|||||||
#define ID_CONSOLE_FINDCASE 602
|
#define ID_CONSOLE_FINDCASE 602
|
||||||
#define ID_CONSOLE_FINDUP 603
|
#define ID_CONSOLE_FINDUP 603
|
||||||
#define ID_CONSOLE_FINDDOWN 604
|
#define ID_CONSOLE_FINDDOWN 604
|
||||||
|
#define ID_CONSOLE_FINDREGEX 605
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|||||||
@ -625,9 +625,9 @@ try
|
|||||||
// -> We need to turn [_beg,_end) into (_beg,_end).
|
// -> We need to turn [_beg,_end) into (_beg,_end).
|
||||||
exclusiveBegin.x--;
|
exclusiveBegin.x--;
|
||||||
|
|
||||||
if (_searcher.IsStale(*_pData, queryText, ignoreCase))
|
if (_searcher.IsStale(*_pData, queryText, ignoreCase ? SearchFlag::CaseInsensitive : SearchFlag::None))
|
||||||
{
|
{
|
||||||
_searcher.Reset(*_pData, queryText, ignoreCase, searchBackward);
|
_searcher.Reset(*_pData, queryText, ignoreCase ? SearchFlag::CaseInsensitive : SearchFlag::None, searchBackward);
|
||||||
}
|
}
|
||||||
_searcher.MovePastPoint(searchBackward ? _end : exclusiveBegin);
|
_searcher.MovePastPoint(searchBackward ? _end : exclusiveBegin);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user