mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-06 06:09:50 +00:00
Compare commits
75 Commits
v1.21.2361
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
971e7c5c91 | ||
|
|
444398d630 | ||
|
|
198decc6e0 | ||
|
|
574f30b424 | ||
|
|
d3e69f788c | ||
|
|
c1d1f6371e | ||
|
|
1fb4331cb3 | ||
|
|
362693b326 | ||
|
|
7cccf568a7 | ||
|
|
1fc01d8197 | ||
|
|
1e527c4090 | ||
|
|
d53d4bd99c | ||
|
|
ca4ec38485 | ||
|
|
c731eae08c | ||
|
|
56c79112e5 | ||
|
|
ecc735d007 | ||
|
|
e0fb764c05 | ||
|
|
5ca26aa3dd | ||
|
|
8146ecdffe | ||
|
|
dba1629d06 | ||
|
|
a346a2a60a | ||
|
|
462b8d228d | ||
|
|
0a1568ddfc | ||
|
|
b1107de808 | ||
|
|
c97721c352 | ||
|
|
fd77061c42 | ||
|
|
bc315b16d9 | ||
|
|
d707096ba6 | ||
|
|
6b650d725d | ||
|
|
876d4faf53 | ||
|
|
aa4730812c | ||
|
|
c2f36cc44e | ||
|
|
59063725b5 | ||
|
|
af776524ba | ||
|
|
28bce48b29 | ||
|
|
e4056caaeb | ||
|
|
5360d68e59 | ||
|
|
09eb0a91a6 | ||
|
|
ebdc887368 | ||
|
|
b288f5dec9 | ||
|
|
5509a965c8 | ||
|
|
49c729aae4 | ||
|
|
2dc568391d | ||
|
|
28a71b10ac | ||
|
|
9e6b97c12e | ||
|
|
953d87b1ad | ||
|
|
03f81b2b7e | ||
|
|
198b3cff4d | ||
|
|
da1e89f3ee | ||
|
|
f396d3685c | ||
|
|
195fc67fa3 | ||
|
|
e49e13e3c6 | ||
|
|
bcbce3462f | ||
|
|
57913e426b | ||
|
|
e4e603d757 | ||
|
|
d437420eed | ||
|
|
5cf5ccdd51 | ||
|
|
f61c080a26 | ||
|
|
ec0ae7d34e | ||
|
|
3f39b5b10a | ||
|
|
8ae9e39d67 | ||
|
|
a3c1d8a254 | ||
|
|
bc5bf1e130 | ||
|
|
85f1bb7cde | ||
|
|
f87a988d12 | ||
|
|
160716d47b | ||
|
|
8e5efb71bb | ||
|
|
1068f857b9 | ||
|
|
fe59504d20 | ||
|
|
4a2de19375 | ||
|
|
4ab4d416f0 | ||
|
|
81a4a3120c | ||
|
|
5391f4e64b | ||
|
|
ff1558c272 | ||
|
|
fa06c6fa2f |
@@ -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();
|
||||
@@ -87,6 +95,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())
|
||||
@@ -102,3 +111,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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -34,6 +35,10 @@ public:
|
||||
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;
|
||||
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
@@ -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,
|
||||
@@ -1560,15 +1569,43 @@ 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();
|
||||
_searcher.ResetIfStale(*GetRenderData());
|
||||
|
||||
auto results = std::vector<int32_t>();
|
||||
|
||||
// use a map to remove duplicates
|
||||
std::map<int32_t, bool> rows;
|
||||
for (const auto& match : _searcher.Results())
|
||||
{
|
||||
const auto row = match.start.y;
|
||||
// First check if it's in the map
|
||||
if (rows.find(row) == rows.end())
|
||||
{
|
||||
rows[row] = true;
|
||||
results.push_back(row);
|
||||
}
|
||||
}
|
||||
return winrt::single_threaded_vector<int32_t>(std::move(results));
|
||||
}
|
||||
|
||||
void ControlCore::ClearSearch()
|
||||
{
|
||||
_terminal->AlwaysNotifyOnBufferRotation(false);
|
||||
_searcher = {};
|
||||
}
|
||||
|
||||
@@ -1866,6 +1903,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_terminal->Write(hstr);
|
||||
|
||||
// Start the throttled update of where our hyperlinks are.
|
||||
|
||||
const auto shared = _shared.lock_shared();
|
||||
if (shared->updatePatternLocations)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
@@ -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,
|
||||
|
||||
@@ -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; };
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -82,6 +82,8 @@ namespace Microsoft.Terminal.Control
|
||||
runtimeclass FoundResultsArgs
|
||||
{
|
||||
Boolean FoundMatch { get; };
|
||||
Int32 TotalMatches { get; };
|
||||
Int32 CurrentMatch { get; };
|
||||
}
|
||||
|
||||
runtimeclass ShowWindowArgs
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "pch.h"
|
||||
#include "SearchBoxControl.h"
|
||||
#include "SearchBoxControl.g.cpp"
|
||||
#include <LibraryResources.h>
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
@@ -18,12 +19,26 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
this->CharacterReceived({ this, &SearchBoxControl::_CharacterHandler });
|
||||
this->KeyDown({ this, &SearchBoxControl::_KeyDownHandler });
|
||||
this->RegisterPropertyChangedCallback(UIElement::VisibilityProperty(), [this](auto&&, auto&&) {
|
||||
// Once the control is visible again we trigger SearchChanged event.
|
||||
// We do this since we probably have a value from the previous search,
|
||||
// and in such case logically the search changes from "nothing" to this value.
|
||||
// A good example for SearchChanged event consumer is Terminal Control.
|
||||
// Once the Search Box is open we want the Terminal Control
|
||||
// to immediately perform the search with the value appearing in the box.
|
||||
if (Visibility() == Visibility::Visible)
|
||||
{
|
||||
_SearchChangedHandlers(TextBox().Text(), _GoForward(), _CaseSensitive());
|
||||
}
|
||||
});
|
||||
|
||||
_focusableElements.insert(TextBox());
|
||||
_focusableElements.insert(CloseButton());
|
||||
_focusableElements.insert(CaseSensitivityButton());
|
||||
_focusableElements.insert(GoForwardButton());
|
||||
_focusableElements.insert(GoBackwardButton());
|
||||
|
||||
StatusBox().Width(_GetStatusMaxWidth());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -62,6 +77,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
if (e.OriginalKey() == winrt::Windows::System::VirtualKey::Enter)
|
||||
{
|
||||
// If the buttons are disabled, then don't allow enter to search either.
|
||||
if (!GoForwardButton().IsEnabled() || !GoBackwardButton().IsEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto state = CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift);
|
||||
if (WI_IsFlagSet(state, CoreVirtualKeyStates::Down))
|
||||
{
|
||||
@@ -209,4 +230,137 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
e.Handled(true);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Handler for changing the text. Triggers SearchChanged event
|
||||
// Arguments:
|
||||
// - sender: not used
|
||||
// - e: event data
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void SearchBoxControl::TextBoxTextChanged(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
|
||||
{
|
||||
_SearchChangedHandlers(TextBox().Text(), _GoForward(), _CaseSensitive());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Handler for clicking the case sensitivity toggle. Triggers SearchChanged event
|
||||
// Arguments:
|
||||
// - sender: not used
|
||||
// - e: not used
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void SearchBoxControl::CaseSensitivityButtonClicked(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
|
||||
{
|
||||
_SearchChangedHandlers(TextBox().Text(), _GoForward(), _CaseSensitive());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Formats a status message representing the search state:
|
||||
// * "Searching" - if totalMatches is negative
|
||||
// * "No results" - if totalMatches is 0
|
||||
// * "?/n" - if totalMatches=n matches and we didn't start the iteration over matches
|
||||
// (usually we will get this after buffer update)
|
||||
// * "m/n" - if we are currently at match m out of n.
|
||||
// * "m/max+" - if n > max results to show
|
||||
// * "?/max+" - if m > max results to show
|
||||
// Arguments:
|
||||
// - totalMatches - total number of matches (search results)
|
||||
// - currentMatch - the index of the current match (0-based)
|
||||
// Return Value:
|
||||
// - status message
|
||||
winrt::hstring SearchBoxControl::_FormatStatus(int32_t totalMatches, int32_t currentMatch)
|
||||
{
|
||||
if (totalMatches < 0)
|
||||
{
|
||||
return RS_(L"TermControl_Searching");
|
||||
}
|
||||
|
||||
if (totalMatches == 0)
|
||||
{
|
||||
return RS_(L"TermControl_NoMatch");
|
||||
}
|
||||
|
||||
std::wstring currentString;
|
||||
std::wstring totalString;
|
||||
|
||||
if (currentMatch < 0 || currentMatch > (MaximumTotalResultsToShowInStatus - 1))
|
||||
{
|
||||
currentString = CurrentIndexTooHighStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentString = fmt::format(L"{}", currentMatch + 1);
|
||||
}
|
||||
|
||||
if (totalMatches > MaximumTotalResultsToShowInStatus)
|
||||
{
|
||||
totalString = TotalResultsTooHighStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
totalString = fmt::format(L"{}", totalMatches);
|
||||
}
|
||||
|
||||
return winrt::hstring{ fmt::format(RS_(L"TermControl_NumResults").c_str(), currentString, totalString) };
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper method to measure the width of the text block given the text and the font size
|
||||
// Arguments:
|
||||
// - text: the text to measure
|
||||
// - fontSize: the size of the font to measure
|
||||
// Return Value:
|
||||
// - the size in pixels
|
||||
double SearchBoxControl::_TextWidth(winrt::hstring text, double fontSize)
|
||||
{
|
||||
winrt::Windows::UI::Xaml::Controls::TextBlock t;
|
||||
t.FontSize(fontSize);
|
||||
t.Text(text);
|
||||
t.Measure({ FLT_MAX, FLT_MAX });
|
||||
return t.ActualWidth();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This method tries to predict the maximal size of the status box
|
||||
// by measuring different possible statuses
|
||||
// Return Value:
|
||||
// - the size in pixels
|
||||
double SearchBoxControl::_GetStatusMaxWidth()
|
||||
{
|
||||
const auto fontSize = StatusBox().FontSize();
|
||||
const auto maxLength = std::max({ _TextWidth(_FormatStatus(-1, -1), fontSize),
|
||||
_TextWidth(_FormatStatus(0, -1), fontSize),
|
||||
_TextWidth(_FormatStatus(MaximumTotalResultsToShowInStatus, MaximumTotalResultsToShowInStatus - 1), fontSize),
|
||||
_TextWidth(_FormatStatus(MaximumTotalResultsToShowInStatus + 1, MaximumTotalResultsToShowInStatus - 1), fontSize),
|
||||
_TextWidth(_FormatStatus(MaximumTotalResultsToShowInStatus + 1, MaximumTotalResultsToShowInStatus), fontSize) });
|
||||
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Formats and sets the status message in the status box.
|
||||
// Increases the size of the box if required.
|
||||
// Arguments:
|
||||
// - totalMatches - total number of matches (search results)
|
||||
// - currentMatch - the index of the current match (0-based)
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void SearchBoxControl::SetStatus(int32_t totalMatches, int32_t currentMatch)
|
||||
{
|
||||
const auto status = _FormatStatus(totalMatches, currentMatch);
|
||||
StatusBox().Text(status);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Enables / disables results navigation buttons
|
||||
// Arguments:
|
||||
// - enable: if true, the buttons should be enabled
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void SearchBoxControl::SetNavigationEnabled(bool enabled)
|
||||
{
|
||||
GoBackwardButton().IsEnabled(enabled);
|
||||
GoForwardButton().IsEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
struct SearchBoxControl : SearchBoxControlT<SearchBoxControl>
|
||||
{
|
||||
static constexpr int32_t MaximumTotalResultsToShowInStatus = 999;
|
||||
static constexpr std::wstring_view TotalResultsTooHighStatus = L"999+";
|
||||
static constexpr std::wstring_view CurrentIndexTooHighStatus = L"?";
|
||||
static constexpr std::wstring_view StatusDelimiter = L"/";
|
||||
|
||||
SearchBoxControl();
|
||||
|
||||
void TextBoxKeyDown(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
@@ -28,17 +33,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void SetFocusOnTextbox();
|
||||
void PopulateTextbox(const winrt::hstring& text);
|
||||
bool ContainsFocus();
|
||||
void SetStatus(int32_t totalMatches, int32_t currentMatch);
|
||||
void SetNavigationEnabled(bool enabled);
|
||||
|
||||
void GoBackwardClicked(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::UI::Xaml::RoutedEventArgs& /*e*/);
|
||||
void GoForwardClicked(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::UI::Xaml::RoutedEventArgs& /*e*/);
|
||||
void CloseClick(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::UI::Xaml::RoutedEventArgs& 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);
|
||||
|
||||
WINRT_CALLBACK(Search, SearchHandler);
|
||||
WINRT_CALLBACK(SearchChanged, SearchHandler);
|
||||
TYPED_EVENT(Closed, Control::SearchBoxControl, Windows::UI::Xaml::RoutedEventArgs);
|
||||
|
||||
private:
|
||||
std::unordered_set<winrt::Windows::Foundation::IInspectable> _focusableElements;
|
||||
|
||||
static winrt::hstring _FormatStatus(int32_t totalMatches, int32_t currentMatch);
|
||||
static double _TextWidth(winrt::hstring text, double fontSize);
|
||||
double _GetStatusMaxWidth();
|
||||
|
||||
bool _GoForward();
|
||||
bool _CaseSensitive();
|
||||
void _KeyDownHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
|
||||
@@ -11,8 +11,11 @@ namespace Microsoft.Terminal.Control
|
||||
void SetFocusOnTextbox();
|
||||
void PopulateTextbox(String text);
|
||||
Boolean ContainsFocus();
|
||||
void SetStatus(Int32 totalMatches, Int32 currentMatch);
|
||||
void SetNavigationEnabled(Boolean enabled);
|
||||
|
||||
event SearchHandler Search;
|
||||
event SearchHandler SearchChanged;
|
||||
event Windows.Foundation.TypedEventHandler<SearchBoxControl, Windows.UI.Xaml.RoutedEventArgs> Closed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,15 @@
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IsSpellCheckEnabled="False"
|
||||
KeyDown="TextBoxKeyDown" />
|
||||
KeyDown="TextBoxKeyDown"
|
||||
TextChanged="TextBoxTextChanged" />
|
||||
|
||||
<TextBlock x:Name="StatusBox"
|
||||
x:Uid="SearchBox_StatusBox"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="15" />
|
||||
|
||||
<ToggleButton x:Name="GoBackwardButton"
|
||||
x:Uid="SearchBox_SearchBackwards"
|
||||
@@ -195,7 +203,8 @@
|
||||
Height="32"
|
||||
Margin="4,0"
|
||||
Padding="0"
|
||||
BackgroundSizing="OuterBorderEdge">
|
||||
BackgroundSizing="OuterBorderEdge"
|
||||
Click="CaseSensitivityButtonClicked">
|
||||
<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>
|
||||
|
||||
|
||||
@@ -302,6 +302,21 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const auto fullHeight{ ScrollBarCanvas().ActualHeight() };
|
||||
const auto totalBufferRows{ update.newMaximum + update.newViewportSize };
|
||||
|
||||
auto drawPip = [&](const auto row, const auto rightAlign, const auto& brush) {
|
||||
Windows::UI::Xaml::Shapes::Rectangle r;
|
||||
r.Fill(brush);
|
||||
r.Width(16.0f / 3.0f); // pip width - 1/3rd of the scrollbar width.
|
||||
r.Height(2);
|
||||
const auto fractionalHeight = row / totalBufferRows;
|
||||
const auto relativePos = fractionalHeight * fullHeight;
|
||||
ScrollBarCanvas().Children().Append(r);
|
||||
Windows::UI::Xaml::Controls::Canvas::SetTop(r, relativePos);
|
||||
if (rightAlign)
|
||||
{
|
||||
Windows::UI::Xaml::Controls::Canvas::SetLeft(r, 16.0f * .66f);
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto m : marks)
|
||||
{
|
||||
Windows::UI::Xaml::Shapes::Rectangle r;
|
||||
@@ -312,14 +327,22 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// pre-evaluate that for us, and shove the real value into the
|
||||
// Color member, regardless if the mark has a literal value set.
|
||||
brush.Color(static_cast<til::color>(m.Color.Color));
|
||||
r.Fill(brush);
|
||||
r.Width(16.0f / 3.0f); // pip width - 1/3rd of the scrollbar width.
|
||||
r.Height(2);
|
||||
const auto markRow = m.Start.Y;
|
||||
const auto fractionalHeight = markRow / totalBufferRows;
|
||||
const auto relativePos = fractionalHeight * fullHeight;
|
||||
ScrollBarCanvas().Children().Append(r);
|
||||
Windows::UI::Xaml::Controls::Canvas::SetTop(r, relativePos);
|
||||
drawPip(m.Start.Y, false, brush);
|
||||
}
|
||||
|
||||
if (_searchBox)
|
||||
{
|
||||
const auto searchMatches{ _core.SearchResultRows() };
|
||||
if (searchMatches.Size() > 0 && _searchBox->Visibility() == Visibility::Visible)
|
||||
{
|
||||
const til::color fgColor{ _core.ForegroundColor() };
|
||||
Media::SolidColorBrush searchMarkBrush{};
|
||||
searchMarkBrush.Color(fgColor);
|
||||
for (const auto m : searchMatches)
|
||||
{
|
||||
drawPip(m, true, searchMarkBrush);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -390,6 +413,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Method Description:
|
||||
// - Search text in text buffer. This is triggered if the user click
|
||||
// search button or press enter.
|
||||
// In the live search mode it will be also triggered once every time search criteria changes
|
||||
// Arguments:
|
||||
// - text: the text to search
|
||||
// - goForward: boolean that represents if the current search direction is forward
|
||||
@@ -403,6 +427,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_core.Search(text, goForward, caseSensitive);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - The handler for the "search criteria changed" event. Clears selection and initiates a new search.
|
||||
// Arguments:
|
||||
// - text: the text to search
|
||||
// - goForward: indicates whether the search should be performed forward (if set to true) or backward
|
||||
// - caseSensitive: boolean that represents if the current search is case sensitive
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TermControl::_SearchChanged(const winrt::hstring& text,
|
||||
const bool goForward,
|
||||
const bool caseSensitive)
|
||||
{
|
||||
if (_searchBox && _searchBox->Visibility() == Visibility::Visible)
|
||||
{
|
||||
_core.Search(text, goForward, caseSensitive);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - The handler for the close button or pressing "Esc" when focusing on the
|
||||
// search dialog.
|
||||
@@ -3420,8 +3462,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - args: contains information about the results that were or were not found.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TermControl::_coreFoundMatch(const IInspectable& /*sender*/, const Control::FoundResultsArgs& args)
|
||||
winrt::fire_and_forget TermControl::_coreFoundMatch(const IInspectable& /*sender*/, Control::FoundResultsArgs args)
|
||||
{
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
if (auto automationPeer{ Automation::Peers::FrameworkElementAutomationPeer::FromElement(*this) })
|
||||
{
|
||||
automationPeer.RaiseNotificationEvent(
|
||||
@@ -3430,6 +3473,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
args.FoundMatch() ? RS_(L"SearchBox_MatchesAvailable") : RS_(L"SearchBox_NoMatches"), // what to announce if results were found
|
||||
L"SearchBoxResultAnnouncement" /* unique name for this group of notifications */);
|
||||
}
|
||||
|
||||
// Manually send a scrollbar update, now, on the UI thread. We're
|
||||
// already UI-driven, so that's okay. We're not really changing the
|
||||
// scrollbar, but we do want to update the position of any marks. The
|
||||
// Core might send a scrollbar updated event too, but if the first
|
||||
// search hit is in the visible viewport, then the pips won't display
|
||||
// until the user first scrolls.
|
||||
auto scrollBar = ScrollBar();
|
||||
ScrollBarUpdate update{
|
||||
.newValue = scrollBar.Value(),
|
||||
.newMaximum = scrollBar.Maximum(),
|
||||
.newMinimum = scrollBar.Minimum(),
|
||||
.newViewportSize = scrollBar.ViewportSize(),
|
||||
};
|
||||
_throttledUpdateScrollbar(update);
|
||||
|
||||
if (_searchBox)
|
||||
{
|
||||
_searchBox->SetStatus(args.TotalMatches(), args.CurrentMatch());
|
||||
_searchBox->SetNavigationEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void TermControl::OwningHwnd(uint64_t owner)
|
||||
|
||||
@@ -274,6 +274,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void _UpdateSettingsFromUIThread();
|
||||
void _UpdateAppearanceFromUIThread(Control::IControlAppearance newAppearance);
|
||||
|
||||
void _ApplyUISettings();
|
||||
winrt::fire_and_forget UpdateAppearance(Control::IControlAppearance newAppearance);
|
||||
void _SetBackgroundImage(const IControlAppearance& newAppearance);
|
||||
@@ -343,6 +344,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
double _GetAutoScrollSpeed(double cursorDistanceFromBorder) const;
|
||||
|
||||
void _Search(const winrt::hstring& text, const bool goForward, const bool caseSensitive);
|
||||
|
||||
void _SearchChanged(const winrt::hstring& text, const bool goForward, const bool caseSensitive);
|
||||
void _CloseSearchBoxControl(const winrt::Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
|
||||
// TSFInputControl Handlers
|
||||
@@ -357,7 +360,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
winrt::fire_and_forget _coreTransparencyChanged(IInspectable sender, Control::TransparencyChangedEventArgs args);
|
||||
void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args);
|
||||
void _coreWarningBell(const IInspectable& sender, const IInspectable& args);
|
||||
void _coreFoundMatch(const IInspectable& sender, const Control::FoundResultsArgs& args);
|
||||
winrt::fire_and_forget _coreFoundMatch(const IInspectable& sender, Control::FoundResultsArgs args);
|
||||
|
||||
til::point _toPosInDips(const Core::Point terminalCellPos);
|
||||
void _throttledUpdateScrollbar(const ScrollBarUpdate& update);
|
||||
|
||||
@@ -1302,6 +1302,7 @@
|
||||
x:Load="False"
|
||||
Closed="_CloseSearchBoxControl"
|
||||
Search="_Search"
|
||||
SearchChanged="_SearchChanged"
|
||||
Visibility="Collapsed" />
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../cascadia/terminalcore/ITerminalInput.hpp"
|
||||
|
||||
#include <til/ticket_lock.h>
|
||||
#include <til/winrt.h>
|
||||
|
||||
inline constexpr size_t TaskbarMinProgress{ 10 };
|
||||
|
||||
@@ -118,6 +119,8 @@ public:
|
||||
const til::point& end,
|
||||
const bool fromUi);
|
||||
|
||||
til::property<bool> AlwaysNotifyOnBufferRotation;
|
||||
|
||||
std::wstring_view CurrentCommand() const;
|
||||
|
||||
#pragma region ITerminalApi
|
||||
|
||||
@@ -472,7 +472,7 @@ void Terminal::NotifyBufferRotation(const int delta)
|
||||
|
||||
const auto oldScrollOffset = _scrollOffset;
|
||||
_PreserveUserScrollOffset(delta);
|
||||
if (_scrollOffset != oldScrollOffset || hasScrollMarks)
|
||||
if (_scrollOffset != oldScrollOffset || hasScrollMarks || AlwaysNotifyOnBufferRotation())
|
||||
{
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
|
||||
@@ -154,6 +154,13 @@ void ScrollTest::TestNotifyScrolling()
|
||||
// SHRT_MAX
|
||||
// - Have a selection
|
||||
|
||||
BEGIN_TEST_METHOD_PROPERTIES()
|
||||
TEST_METHOD_PROPERTY(L"Data:notifyOnCircling", L"{false, true}")
|
||||
END_TEST_METHOD_PROPERTIES();
|
||||
INIT_TEST_PROPERTY(bool, notifyOnCircling, L"Controls whether we should always request scroll notifications");
|
||||
|
||||
_term->AlwaysNotifyOnBufferRotation(notifyOnCircling);
|
||||
|
||||
Log::Comment(L"Watch out - this test takes a while to run, and won't "
|
||||
L"output anything unless in encounters an error. This is expected.");
|
||||
|
||||
@@ -180,10 +187,12 @@ void ScrollTest::TestNotifyScrolling()
|
||||
// causes the first scroll event
|
||||
auto scrolled = currentRow >= TerminalViewHeight - 1;
|
||||
|
||||
// When we circle the buffer, the scroll bar's position does not
|
||||
// change.
|
||||
// When we circle the buffer, the scroll bar's position does not change.
|
||||
// However, as of GH#14045, we will send a notification IF the control
|
||||
// requested on (by setting AlwaysNotifyOnBufferRotation)
|
||||
auto circledBuffer = currentRow >= totalBufferSize - 1;
|
||||
auto expectScrollBarNotification = scrolled && !circledBuffer;
|
||||
auto expectScrollBarNotification = (scrolled && !circledBuffer) || // If we scrolled, but didn't circle the buffer OR
|
||||
(circledBuffer && notifyOnCircling); // we circled AND we asked for notifications.
|
||||
|
||||
if (expectScrollBarNotification)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
|
||||
property& operator=(const property& other) = default;
|
||||
|
||||
T operator()() const
|
||||
T operator()() const noexcept
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
@@ -23,11 +23,13 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
}
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
#ifdef WINRT_Windows_Foundation_H
|
||||
if constexpr (std::is_same_v<T, winrt::hstring>)
|
||||
{
|
||||
return !_value.empty();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user