Skip to content

Commit 89a4e14

Browse files
committed
Really basic fuzzy search in Pane
1 parent 378b659 commit 89a4e14

27 files changed

+2329
-26
lines changed

src/buffer/out/UTextAdapter.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,18 @@ til::point_span Microsoft::Console::ICU::BufferRangeFromMatch(UText* ut, URegula
327327

328328
return ret;
329329
}
330+
331+
UText Microsoft::Console::ICU::UTextForWrappableRow(const TextBuffer& textBuffer, til::CoordType& row) noexcept
332+
{
333+
const auto startRow = row;
334+
auto length = 0;
335+
while (textBuffer.GetRowByOffset(row).WasWrapForced())
336+
{
337+
row++;
338+
length += textBuffer.GetRowByOffset(row).size();
339+
}
340+
length += textBuffer.GetRowByOffset(row).size();
341+
const auto ut = UTextFromTextBuffer(textBuffer, startRow, row + 1);
342+
343+
return ut;
344+
}

src/buffer/out/UTextAdapter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace Microsoft::Console::ICU
1212
using unique_uregex = wistd::unique_ptr<URegularExpression, wil::function_deleter<decltype(&uregex_close), &uregex_close>>;
1313

1414
UText UTextFromTextBuffer(const TextBuffer& textBuffer, til::CoordType rowBeg, til::CoordType rowEnd) noexcept;
15+
UText UTextForWrappableRow(const TextBuffer& textBuffer, til::CoordType& row) noexcept;
1516
unique_uregex CreateRegex(const std::wstring_view& pattern, uint32_t flags, UErrorCode* status) noexcept;
1617
til::point_span BufferRangeFromMatch(UText* ut, URegularExpression* re);
1718
}

src/cascadia/TerminalApp/AppActionHandlers.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "TerminalPage.h"
88
#include "ScratchpadContent.h"
9+
#include "FuzzySearchPane.h"
910
#include "../WinRTUtils/inc/WtExeUtils.h"
1011
#include "../../types/inc/utils.hpp"
1112
#include "Utils.h"
@@ -1467,6 +1468,25 @@ namespace winrt::TerminalApp::implementation
14671468
}
14681469
}
14691470

1471+
void TerminalPage::_HandleOpenFuzzySearch(const IInspectable& sender,
1472+
const ActionEventArgs& args)
1473+
{
1474+
if (Feature_FuzzySearch::IsEnabled())
1475+
{
1476+
const auto& fuzzySearchPane{ winrt::make_self<FuzzySearchPane>(_GetActiveControl()) };
1477+
1478+
// This is maybe a little wacky - add our key event handler to the pane
1479+
// we made. So that we can get actions for keys that the content didn't
1480+
// handle.
1481+
fuzzySearchPane->GetRoot().KeyDown({ this, &TerminalPage::_KeyDownHandler });
1482+
1483+
const auto resultPane = std::make_shared<Pane>(*fuzzySearchPane);
1484+
_SplitPane(_senderOrFocusedTab(sender), SplitDirection::Automatic, 0.5f, resultPane);
1485+
fuzzySearchPane->Focus();
1486+
args.Handled(true);
1487+
}
1488+
}
1489+
14701490
void TerminalPage::_HandleOpenAbout(const IInspectable& /*sender*/,
14711491
const ActionEventArgs& args)
14721492
{
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
#include "pch.h"
5+
#include "FuzzySearchPane.h"
6+
7+
using namespace winrt::Windows::Foundation;
8+
using namespace winrt::Windows::UI::Xaml;
9+
using namespace winrt::Microsoft::Terminal::Settings::Model;
10+
11+
namespace winrt::TerminalApp::implementation
12+
{
13+
FuzzySearchPane::FuzzySearchPane(const winrt::Microsoft::Terminal::Control::TermControl& control)
14+
{
15+
_control = control;
16+
_root = winrt::Windows::UI::Xaml::Controls::Grid{};
17+
// Vertical and HorizontalAlignment are Stretch by default
18+
19+
auto res = Windows::UI::Xaml::Application::Current().Resources();
20+
auto bg = res.Lookup(winrt::box_value(L"UnfocusedBorderBrush"));
21+
_root.Background(bg.try_as<Media::Brush>());
22+
23+
const Controls::RowDefinition row1;
24+
row1.Height(GridLengthHelper::FromValueAndType(1, GridUnitType::Star));
25+
_root.RowDefinitions().Append(row1);
26+
27+
const Controls::RowDefinition row2;
28+
row2.Height(GridLengthHelper::Auto());
29+
_root.RowDefinitions().Append(row2);
30+
31+
_listBox = Controls::ListBox{};
32+
_listBox.Margin({ 10, 10, 10, 10 });
33+
_root.Children().Append(_listBox);
34+
35+
_searchBox = Controls::TextBox{};
36+
_root.Children().Append(_searchBox);
37+
38+
_searchBox.TextChanged({ this, &FuzzySearchPane::OnTextChanged });
39+
_searchBox.KeyDown({ this, &FuzzySearchPane::OnKeyUp });
40+
41+
Controls::Grid::SetRow(_listBox, 0);
42+
Controls::Grid::SetRow(_searchBox, 1);
43+
}
44+
45+
void FuzzySearchPane::OnKeyUp(Windows::Foundation::IInspectable const&, Input::KeyRoutedEventArgs const& e)
46+
{
47+
if (e.OriginalKey() == winrt::Windows::System::VirtualKey::Down || e.OriginalKey() == winrt::Windows::System::VirtualKey::Up)
48+
{
49+
auto selectedIndex = _listBox.SelectedIndex();
50+
51+
if (e.OriginalKey() == winrt::Windows::System::VirtualKey::Down)
52+
{
53+
selectedIndex++;
54+
}
55+
else if (e.OriginalKey() == winrt::Windows::System::VirtualKey::Up)
56+
{
57+
selectedIndex--;
58+
}
59+
60+
if (selectedIndex >= 0 && selectedIndex < static_cast<int32_t>(_listBox.Items().Size()))
61+
{
62+
_listBox.SelectedIndex(selectedIndex);
63+
_listBox.ScrollIntoView(Controls::ListBox().SelectedItem());
64+
}
65+
66+
e.Handled(true);
67+
}
68+
else if (e.OriginalKey() == winrt::Windows::System::VirtualKey::Enter)
69+
{
70+
if (const auto selectedItem = _listBox.SelectedItem())
71+
{
72+
if (const auto listBoxItem = selectedItem.try_as<Controls::ListBoxItem>())
73+
{
74+
if (const auto fuzzyMatch = listBoxItem.DataContext().try_as<winrt::Microsoft::Terminal::Control::FuzzySearchTextLine>())
75+
{
76+
_control.SelectChar(fuzzyMatch.FirstPosition());
77+
_control.Focus(FocusState::Programmatic);
78+
e.Handled(true);
79+
}
80+
}
81+
}
82+
}
83+
else if (e.OriginalKey() == winrt::Windows::System::VirtualKey::Escape)
84+
{
85+
Close();
86+
e.Handled(true);
87+
}
88+
}
89+
90+
void FuzzySearchPane::OnTextChanged(Windows::Foundation::IInspectable const&, Controls::TextChangedEventArgs const&) const
91+
{
92+
_listBox.Items().Clear();
93+
const auto needle = _searchBox.Text();
94+
const auto fuzzySearchResult = _control.FuzzySearch(needle);
95+
if (fuzzySearchResult.NumberOfResults() > 0)
96+
{
97+
for (auto fuzzyMatch : fuzzySearchResult.Results())
98+
{
99+
auto control = Controls::TextBlock{};
100+
const auto inlinesCollection = control.Inlines();
101+
inlinesCollection.Clear();
102+
103+
for (const auto& match : fuzzyMatch.Segments())
104+
{
105+
const auto matchText = match.TextSegment();
106+
const auto fontWeight = match.IsHighlighted() ? Windows::UI::Text::FontWeights::Bold() : Windows::UI::Text::FontWeights::Normal();
107+
108+
Media::SolidColorBrush foregroundBrush;
109+
110+
if (match.IsHighlighted())
111+
{
112+
foregroundBrush.Color(Windows::UI::Colors::OrangeRed());
113+
}
114+
else
115+
{
116+
foregroundBrush.Color(Windows::UI::Colors::White());
117+
}
118+
119+
Documents::Run run;
120+
run.Text(matchText);
121+
run.FontWeight(fontWeight);
122+
run.Foreground(foregroundBrush);
123+
inlinesCollection.Append(run);
124+
}
125+
auto lbi = Controls::ListBoxItem();
126+
lbi.DataContext(fuzzyMatch);
127+
lbi.Content(control);
128+
_listBox.Items().Append(lbi);
129+
}
130+
_listBox.SelectedIndex(0);
131+
}
132+
}
133+
134+
void FuzzySearchPane::UpdateSettings(const CascadiaSettings& /*settings*/)
135+
{
136+
// Nothing to do.
137+
}
138+
139+
winrt::Windows::UI::Xaml::FrameworkElement FuzzySearchPane::GetRoot()
140+
{
141+
return _root;
142+
}
143+
winrt::Windows::Foundation::Size FuzzySearchPane::MinimumSize()
144+
{
145+
return { 1, 1 };
146+
}
147+
void FuzzySearchPane::Focus(winrt::Windows::UI::Xaml::FocusState reason)
148+
{
149+
_searchBox.Focus(reason);
150+
}
151+
void FuzzySearchPane::Close()
152+
{
153+
CloseRequested.raise(*this, nullptr);
154+
}
155+
156+
INewContentArgs FuzzySearchPane::GetNewTerminalArgs(const BuildStartupKind /* kind */) const
157+
{
158+
return BaseContentArgs(L"scratchpad");
159+
}
160+
161+
winrt::hstring FuzzySearchPane::Icon() const
162+
{
163+
static constexpr std::wstring_view glyph{ L"\xe70b" }; // QuickNote
164+
return winrt::hstring{ glyph };
165+
}
166+
167+
winrt::Windows::UI::Xaml::Media::Brush FuzzySearchPane::BackgroundBrush()
168+
{
169+
return _root.Background();
170+
}
171+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
#pragma once
5+
#include "winrt/TerminalApp.h"
6+
7+
namespace winrt::TerminalApp::implementation
8+
{
9+
class FuzzySearchPane : public winrt::implements<FuzzySearchPane, IPaneContent>
10+
{
11+
public:
12+
FuzzySearchPane(const winrt::Microsoft::Terminal::Control::TermControl& control);
13+
void TextBoxTextChanged(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& /*e*/);
14+
void OnTextChanged(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::Controls::TextChangedEventArgs const&) const;
15+
void OnKeyUp(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::Input::KeyRoutedEventArgs const&);
16+
17+
winrt::Windows::UI::Xaml::FrameworkElement GetRoot();
18+
19+
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
20+
21+
winrt::Windows::Foundation::Size MinimumSize();
22+
23+
void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic);
24+
void Close();
25+
winrt::Microsoft::Terminal::Settings::Model::INewContentArgs GetNewTerminalArgs(BuildStartupKind kind) const;
26+
27+
winrt::hstring Title() { return L"FuzzySearch"; }
28+
uint64_t TaskbarState() { return 0; }
29+
uint64_t TaskbarProgress() { return 0; }
30+
bool ReadOnly() { return false; }
31+
winrt::hstring Icon() const;
32+
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() const noexcept { return nullptr; }
33+
winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush();
34+
35+
til::typed_event<> ConnectionStateChanged;
36+
til::typed_event<IPaneContent> CloseRequested;
37+
til::typed_event<IPaneContent, winrt::TerminalApp::BellEventArgs> BellRequested;
38+
til::typed_event<IPaneContent> TitleChanged;
39+
til::typed_event<IPaneContent> TabColorChanged;
40+
til::typed_event<IPaneContent> TaskbarProgressChanged;
41+
til::typed_event<IPaneContent> ReadOnlyChanged;
42+
til::typed_event<IPaneContent> FocusRequested;
43+
44+
private:
45+
winrt::Windows::UI::Xaml::Controls::Grid _root{ nullptr };
46+
winrt::Windows::UI::Xaml::Controls::ListBox _listBox{ nullptr };
47+
winrt::Windows::UI::Xaml::Controls::TextBox _searchBox{ nullptr };
48+
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
49+
};
50+
}

src/cascadia/TerminalApp/TerminalAppLib.vcxproj

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@
161161
<ClInclude Include="ScratchpadContent.h">
162162
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
163163
</ClInclude>
164+
<ClInclude Include="FuzzySearchPane.h">
165+
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
166+
</ClInclude>
164167
<ClInclude Include="SettingsPaneContent.h">
165168
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
166169
</ClInclude>
@@ -274,6 +277,9 @@
274277
<ClCompile Include="ScratchpadContent.cpp">
275278
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
276279
</ClCompile>
280+
<ClCompile Include="FuzzySearchPane.cpp">
281+
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
282+
</ClCompile>
277283
<ClCompile Include="SettingsPaneContent.cpp">
278284
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
279285
</ClCompile>
@@ -400,7 +406,6 @@
400406
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\UIHelpers\UIHelpers.vcxproj">
401407
<Project>{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}</Project>
402408
</ProjectReference>
403-
404409
</ItemGroup>
405410
<PropertyGroup>
406411
<!-- This is a hack to get the ARM64 CI build working. See
@@ -466,10 +471,8 @@
466471
</ItemDefinitionGroup>
467472
<!-- ========================= Globals ======================== -->
468473
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
469-
470474
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
471475
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
472-
473476
<!--
474477
By default, the PRI file will contain resource paths beginning with the
475478
project name. Since we enabled XBF embedding, this *also* includes App.xbf.
@@ -490,4 +493,4 @@
490493
</ItemGroup>
491494
</Target>
492495
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
493-
</Project>
496+
</Project>

0 commit comments

Comments
 (0)