Compare commits

...

4 Commits

15 changed files with 331 additions and 223 deletions

View File

@@ -37,14 +37,14 @@ namespace winrt::TerminalApp::implementation
_Item = item;
_Filter = L"";
_Weight = 0;
_HighlightedName = _computeHighlightedName();
_HighlightedName = _computeHighlighted(_Item.Name());
// Recompute the highlighted name if the item name changes
_itemChangedRevoker = _Item.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& /*sender*/, auto& e) {
auto filteredCommand{ weakThis.get() };
if (filteredCommand && e.PropertyName() == L"Name")
{
filteredCommand->HighlightedName(filteredCommand->_computeHighlightedName());
filteredCommand->HighlightedName(filteredCommand->_computeHighlighted(filteredCommand->_Item.Name()));
filteredCommand->Weight(filteredCommand->_computeWeight());
}
});
@@ -57,11 +57,16 @@ namespace winrt::TerminalApp::implementation
if (filter != _Filter)
{
Filter(filter);
HighlightedName(_computeHighlightedName());
HighlightedName(_computeHighlighted(_Item.Name()));
Weight(_computeWeight());
}
}
winrt::TerminalApp::HighlightedText FilteredCommand::_computeHighlighted(winrt::hstring input)
{
return ComputeHighlighted(input, _Filter);
}
// Method Description:
// - Looks up the filter characters within the item name.
// Iterating through the filter and the item name it tries to associate the next filter character
@@ -81,15 +86,15 @@ namespace winrt::TerminalApp::implementation
//
// Return Value:
// - The HighlightedText object initialized with the segments computed according to the algorithm above.
winrt::TerminalApp::HighlightedText FilteredCommand::_computeHighlightedName()
winrt::TerminalApp::HighlightedText FilteredCommand::ComputeHighlighted(winrt::hstring input, winrt::hstring filter)
{
const auto segments = winrt::single_threaded_observable_vector<winrt::TerminalApp::HighlightedTextSegment>();
auto commandName = _Item.Name();
auto commandName = input;
auto isProcessingMatchedSegment = false;
uint32_t nextOffsetToReport = 0;
uint32_t currentOffset = 0;
for (const auto searchChar : _Filter)
for (const auto searchChar : filter)
{
const WCHAR searchCharAsString[] = { searchChar, L'\0' };
while (true)
@@ -202,30 +207,7 @@ namespace winrt::TerminalApp::implementation
// - the relative weight of this match
int FilteredCommand::_computeWeight()
{
auto result = 0;
auto isNextSegmentWordBeginning = true;
for (const auto& segment : _HighlightedName.Segments())
{
const auto& segmentText = segment.TextSegment();
const auto segmentSize = segmentText.size();
if (segment.IsHighlighted())
{
// Give extra point for each consecutive match
result += (segmentSize <= 1) ? segmentSize : 1 + 2 * (segmentSize - 1);
// Give extra point if this segment is at the beginning of a word
if (isNextSegmentWordBeginning)
{
result++;
}
}
isNextSegmentWordBeginning = segmentSize > 0 && segmentText[segmentSize - 1] == L' ';
}
return result;
return _HighlightedName.Weight();
}
// Function Description:

View File

@@ -19,9 +19,10 @@ namespace winrt::TerminalApp::implementation
FilteredCommand() = default;
FilteredCommand(const winrt::TerminalApp::PaletteItem& item);
virtual void UpdateFilter(const winrt::hstring& filter);
void UpdateFilter(const winrt::hstring& filter);
static int Compare(const winrt::TerminalApp::FilteredCommand& first, const winrt::TerminalApp::FilteredCommand& second);
static winrt::TerminalApp::HighlightedText ComputeHighlighted(winrt::hstring input, winrt::hstring filter);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::PaletteItem, Item, PropertyChanged.raise, nullptr);
@@ -29,14 +30,13 @@ namespace winrt::TerminalApp::implementation
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::HighlightedText, HighlightedName, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(int, Weight, PropertyChanged.raise);
protected:
void _constructFilteredCommand(const winrt::TerminalApp::PaletteItem& item);
private:
winrt::TerminalApp::HighlightedText _computeHighlightedName();
int _computeWeight();
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _itemChangedRevoker;
void _constructFilteredCommand(const winrt::TerminalApp::PaletteItem& item);
winrt::TerminalApp::HighlightedText _computeHighlighted(winrt::hstring input);
int _computeWeight();
friend class TerminalAppLocalTests::FilteredCommandTests;
};
}

View File

@@ -0,0 +1,121 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "FilteredTask.g.h"
#include "FilteredCommand.h"
#include "ActionPaletteItem.h"
#include <LibraryResources.h>
namespace winrt::TerminalApp::implementation
{
struct FilteredTask : FilteredTaskT<FilteredTask>
{
FilteredTask() = default;
FilteredTask(const winrt::Microsoft::Terminal::Settings::Model::Command& command)
{
_filteredCommand = winrt::make_self<implementation::FilteredCommand>(winrt::make<winrt::TerminalApp::implementation::ActionPaletteItem>(command, winrt::hstring{}));
_command = command;
// The Children() method must always return a non-null vector
_children = winrt::single_threaded_observable_vector<TerminalApp::FilteredTask>();
if (_command.HasNestedCommands())
{
for (const auto& [_, child] : _command.NestedCommands())
{
auto vm{ winrt::make<FilteredTask>(child) };
_children.Append(vm);
}
}
}
static int Compare(const winrt::TerminalApp::FilteredTask& first, const winrt::TerminalApp::FilteredTask& second)
{
auto firstWeight{ winrt::get_self<implementation::FilteredTask>(first)->Weight() };
auto secondWeight{ winrt::get_self<implementation::FilteredTask>(second)->Weight() };
if (firstWeight == secondWeight)
{
std::wstring_view firstName{ first.FilteredCommand().Item().Name() };
std::wstring_view secondName{ second.FilteredCommand().Item().Name() };
return lstrcmpi(firstName.data(), secondName.data()) < 0;
}
return firstWeight > secondWeight;
}
void UpdateFilter(const winrt::hstring& filter)
{
_filteredCommand->UpdateFilter(filter);
HighlightedInput(FilteredCommand::ComputeHighlighted(Input(), filter));
for (const auto& c : _children)
{
auto impl = winrt::get_self<implementation::FilteredTask>(c);
impl->UpdateFilter(filter);
}
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"Visibility" });
}
winrt::hstring Input()
{
if (const auto& actionItem{ _filteredCommand->Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
{
if (const auto& command{ actionItem.Command() })
{
if (const auto& sendInput{ command.ActionAndArgs().Args().try_as<winrt::Microsoft::Terminal::Settings::Model::SendInputArgs>() })
{
return winrt::hstring{ til::visualize_nonspace_control_codes(std::wstring{ sendInput.Input() }) };
}
}
}
return winrt::hstring{};
};
winrt::TerminalApp::PaletteItem Item() { return _filteredCommand->Item(); }
winrt::Windows::Foundation::Collections::IObservableVector<TerminalApp::FilteredTask> Children() { return _children; }
bool HasChildren() { return _children.Size() > 0; }
winrt::Microsoft::Terminal::Settings::Model::Command Command() { return _command; }
winrt::TerminalApp::FilteredCommand FilteredCommand() { return *_filteredCommand; }
int32_t Row() { return HasChildren() ? 2 : 1; } // See the BODGY comment in the .XAML for explanation
// Used to control if this item is visible in the TreeView. Turns out,
// TreeView is in fact sane enough to remove items entirely if they're
// Collapsed.
winrt::Windows::UI::Xaml::Visibility Visibility()
{
const auto ourWeight = Weight();
// Is there no filter, or do we match it?
if (_filteredCommand->Filter().empty() || ourWeight > 0)
{
return winrt::Windows::UI::Xaml::Visibility::Visible;
}
// If we don't match, maybe one of our children does
auto totalWeight = ourWeight;
for (const auto& c : _children)
{
auto impl = winrt::get_self<implementation::FilteredTask>(c);
totalWeight += impl->Weight();
}
return totalWeight > 0 ? winrt::Windows::UI::Xaml::Visibility::Visible : winrt::Windows::UI::Xaml::Visibility::Collapsed;
};
int Weight()
{
return std::max(_filteredCommand->Weight(), _HighlightedInput.Weight());
}
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::HighlightedText, HighlightedInput, PropertyChanged.raise);
private:
winrt::Microsoft::Terminal::Settings::Model::Command _command{ nullptr };
winrt::com_ptr<winrt::TerminalApp::implementation::FilteredCommand> _filteredCommand{ nullptr };
winrt::Windows::Foundation::Collections::IObservableVector<TerminalApp::FilteredTask> _children{ nullptr };
};
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "IPaneContent.idl";
import "TerminalSettingsCache.idl";
import "FilteredCommand.idl";
namespace TerminalApp
{
[default_interface] runtimeclass FilteredTask : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
String Input{ get; };
Windows.Foundation.Collections.IObservableVector<FilteredTask> Children { get; };
Boolean HasChildren { get; };
Int32 Row { get; };
Windows.UI.Xaml.Visibility Visibility { get; };
TerminalApp.FilteredCommand FilteredCommand{ get; };
}
}

View File

@@ -28,4 +28,32 @@ namespace winrt::TerminalApp::implementation
_Segments(segments)
{
}
int HighlightedText::Weight() const
{
auto result = 0;
auto isNextSegmentWordBeginning = true;
for (const auto& segment : _Segments)
{
const auto& segmentText = segment.TextSegment();
const auto segmentSize = segmentText.size();
if (segment.IsHighlighted())
{
// Give extra point for each consecutive match
result += (segmentSize <= 1) ? segmentSize : 1 + 2 * (segmentSize - 1);
// Give extra point if this segment is at the beginning of a word
if (isNextSegmentWordBeginning)
{
result++;
}
}
isNextSegmentWordBeginning = segmentSize > 0 && segmentText[segmentSize - 1] == L' ';
}
return result;
}
}

View File

@@ -22,6 +22,7 @@ namespace winrt::TerminalApp::implementation
{
HighlightedText() = default;
HighlightedText(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>& segments);
int32_t Weight() const;
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>, Segments, PropertyChanged.raise);

View File

@@ -16,7 +16,7 @@ namespace TerminalApp
{
HighlightedText();
HighlightedText(Windows.Foundation.Collections.IObservableVector<HighlightedTextSegment> segments);
Int32 Weight { get; };
Windows.Foundation.Collections.IObservableVector<HighlightedTextSegment> Segments;
}
}

View File

@@ -24,7 +24,15 @@ namespace winrt::TerminalApp::implementation
// - data template to use for rendering
Windows::UI::Xaml::DataTemplate PaletteItemTemplateSelector::SelectTemplateCore(const winrt::Windows::Foundation::IInspectable& item)
{
if (const auto filteredCommand{ item.try_as<winrt::TerminalApp::FilteredCommand>() })
auto filteredCommand{ item.try_as<winrt::TerminalApp::FilteredCommand>() };
if (filteredCommand == nullptr)
{
if (auto snippet{ item.try_as<winrt::TerminalApp::FilteredTask>() })
{
filteredCommand = snippet.FilteredCommand();
}
}
if (filteredCommand)
{
if (filteredCommand.Item().try_as<winrt::TerminalApp::TabPaletteItem>())
{

View File

@@ -3,10 +3,8 @@
#pragma once
#include "SnippetsPaneContent.g.h"
#include "FilteredTask.g.h"
#include "FilteredTask.h"
#include "BasicPaneEvents.h"
#include "FilteredCommand.h"
#include "ActionPaletteItem.h"
#include <LibraryResources.h>
namespace winrt::TerminalApp::implementation
@@ -55,90 +53,6 @@ namespace winrt::TerminalApp::implementation
void _treeItemKeyUpHandler(const IInspectable& sender, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
void _runCommand(const Microsoft::Terminal::Settings::Model::Command& command);
};
struct FilteredTask : FilteredTaskT<FilteredTask>
{
FilteredTask() = default;
FilteredTask(const winrt::Microsoft::Terminal::Settings::Model::Command& command)
{
_filteredCommand = winrt::make_self<implementation::FilteredCommand>(winrt::make<winrt::TerminalApp::implementation::ActionPaletteItem>(command, winrt::hstring{}));
_command = command;
// The Children() method must always return a non-null vector
_children = winrt::single_threaded_observable_vector<TerminalApp::FilteredTask>();
if (_command.HasNestedCommands())
{
for (const auto& [_, child] : _command.NestedCommands())
{
auto vm{ winrt::make<FilteredTask>(child) };
_children.Append(vm);
}
}
}
void UpdateFilter(const winrt::hstring& filter)
{
_filteredCommand->UpdateFilter(filter);
for (const auto& c : _children)
{
auto impl = winrt::get_self<implementation::FilteredTask>(c);
impl->UpdateFilter(filter);
}
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"Visibility" });
}
winrt::hstring Input()
{
if (const auto& actionItem{ _filteredCommand->Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
{
if (const auto& command{ actionItem.Command() })
{
if (const auto& sendInput{ command.ActionAndArgs().Args().try_as<winrt::Microsoft::Terminal::Settings::Model::SendInputArgs>() })
{
return winrt::hstring{ til::visualize_nonspace_control_codes(std::wstring{ sendInput.Input() }) };
}
}
}
return winrt::hstring{};
};
winrt::Windows::Foundation::Collections::IObservableVector<TerminalApp::FilteredTask> Children() { return _children; }
bool HasChildren() { return _children.Size() > 0; }
winrt::Microsoft::Terminal::Settings::Model::Command Command() { return _command; }
winrt::TerminalApp::FilteredCommand FilteredCommand() { return *_filteredCommand; }
int32_t Row() { return HasChildren() ? 2 : 1; } // See the BODGY comment in the .XAML for explanation
// Used to control if this item is visible in the TreeView. Turns out,
// TreeView is in fact sane enough to remove items entirely if they're
// Collapsed.
winrt::Windows::UI::Xaml::Visibility Visibility()
{
// Is there no filter, or do we match it?
if (_filteredCommand->Filter().empty() || _filteredCommand->Weight() > 0)
{
return winrt::Windows::UI::Xaml::Visibility::Visible;
}
// If we don't match, maybe one of our children does
auto totalWeight = _filteredCommand->Weight();
for (const auto& c : _children)
{
auto impl = winrt::get_self<implementation::FilteredTask>(c);
totalWeight += impl->_filteredCommand->Weight();
}
return totalWeight > 0 ? winrt::Windows::UI::Xaml::Visibility::Visible : winrt::Windows::UI::Xaml::Visibility::Collapsed;
};
til::property_changed_event PropertyChanged;
private:
winrt::Microsoft::Terminal::Settings::Model::Command _command{ nullptr };
winrt::com_ptr<winrt::TerminalApp::implementation::FilteredCommand> _filteredCommand{ nullptr };
winrt::Windows::Foundation::Collections::IObservableVector<TerminalApp::FilteredTask> _children{ nullptr };
};
}
namespace winrt::TerminalApp::factory_implementation

View File

@@ -31,10 +31,11 @@ namespace winrt::TerminalApp::implementation
_itemTemplateSelector = Resources().Lookup(winrt::box_value(L"PaletteItemTemplateSelector")).try_as<PaletteItemTemplateSelector>();
_listItemTemplate = Resources().Lookup(winrt::box_value(L"ListItemTemplate")).try_as<DataTemplate>();
_filteredActions = winrt::single_threaded_observable_vector<winrt::TerminalApp::FilteredCommand>();
_nestedActionStack = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
_currentNestedCommands = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
_allCommands = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
_filteredActions = winrt::single_threaded_observable_vector<winrt::TerminalApp::FilteredTask>();
// _nestedActionStack = winrt::single_threaded_vector<winrt::TerminalApp::FilteredTask>();
// _currentNestedCommands = winrt::single_threaded_vector<winrt::TerminalApp::FilteredTask>();
_allCommands = winrt::single_threaded_vector<winrt::TerminalApp::FilteredTask>();
_flatAllCommands = winrt::single_threaded_vector<winrt::TerminalApp::FilteredTask>();
_switchToMode();
@@ -113,6 +114,8 @@ namespace winrt::TerminalApp::implementation
_filteredActionsView().SelectionChanged({ this, &SuggestionsControl::_selectedCommandChanged });
}
TerminalApp::implementation::FilteredTask* impl(const TerminalApp::FilteredTask t) { return winrt::get_self<implementation::FilteredTask>(t); };
TerminalApp::SuggestionsMode SuggestionsControl::Mode() const
{
return _mode;
@@ -267,7 +270,7 @@ namespace winrt::TerminalApp::implementation
const Windows::UI::Xaml::RoutedEventArgs& /*args*/)
{
const auto selectedCommand = _filteredActionsView().SelectedItem();
const auto filteredCommand{ selectedCommand.try_as<winrt::TerminalApp::FilteredCommand>() };
const auto filteredCommand{ selectedCommand.try_as<winrt::TerminalApp::FilteredTask>() };
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"SelectedItem" });
@@ -280,7 +283,7 @@ namespace winrt::TerminalApp::implementation
if (filteredCommand != nullptr &&
isVisible)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
if (const auto actionPaletteItem{ impl(filteredCommand)->Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
{
const auto& cmd = actionPaletteItem.Command();
PreviewAction.raise(*this, cmd);
@@ -413,7 +416,7 @@ namespace winrt::TerminalApp::implementation
}
const auto selectedCommand = _filteredActionsView().SelectedItem();
const auto filteredCommand = selectedCommand.try_as<winrt::TerminalApp::FilteredCommand>();
const auto filteredCommand = selectedCommand.try_as<winrt::TerminalApp::FilteredTask>();
_dispatchCommand(filteredCommand);
e.Handled(true);
}
@@ -558,7 +561,7 @@ namespace winrt::TerminalApp::implementation
const Windows::UI::Xaml::Controls::ItemClickEventArgs& e)
{
const auto selectedCommand = e.ClickedItem();
if (const auto filteredCommand = selectedCommand.try_as<winrt::TerminalApp::FilteredCommand>())
if (const auto filteredCommand = selectedCommand.try_as<winrt::TerminalApp::FilteredTask>())
{
_dispatchCommand(filteredCommand);
}
@@ -571,9 +574,9 @@ namespace winrt::TerminalApp::implementation
if (const auto selectedList = e.AddedItems(); selectedList.Size() > 0)
{
const auto selectedCommand = selectedList.GetAt(0);
if (const auto filteredCmd = selectedCommand.try_as<TerminalApp::FilteredCommand>())
if (const auto filteredCmd = selectedCommand.try_as<TerminalApp::FilteredTask>())
{
if (const auto paletteItem = filteredCmd.Item().try_as<TerminalApp::PaletteItem>())
if (const auto paletteItem = impl(filteredCmd)->Item().try_as<TerminalApp::PaletteItem>())
{
automationPeer.RaiseNotificationEvent(
Automation::Peers::AutomationNotificationKind::ItemAdded,
@@ -600,30 +603,30 @@ namespace winrt::TerminalApp::implementation
PreviewAction.raise(*this, nullptr);
_searchBox().Focus(FocusState::Programmatic);
const auto previousAction{ _nestedActionStack.GetAt(_nestedActionStack.Size() - 1) };
_nestedActionStack.RemoveAtEnd();
// const auto previousAction{ _nestedActionStack.GetAt(_nestedActionStack.Size() - 1) };
// _nestedActionStack.RemoveAtEnd();
// Repopulate nested commands when the root has not been reached yet
if (_nestedActionStack.Size() > 0)
{
const auto newPreviousAction{ _nestedActionStack.GetAt(_nestedActionStack.Size() - 1) };
const auto actionPaletteItem{ newPreviousAction.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() };
// // Repopulate nested commands when the root has not been reached yet
// if (_nestedActionStack.Size() > 0)
// {
// const auto newPreviousAction{ _nestedActionStack.GetAt(_nestedActionStack.Size() - 1) };
// const auto actionPaletteItem{ impl(newPreviousAction)->Item().try_as<winrt::TerminalApp::ActionPaletteItem>() };
ParentCommandName(actionPaletteItem.Command().Name());
_updateCurrentNestedCommands(actionPaletteItem.Command());
}
else
{
ParentCommandName(L"");
_currentNestedCommands.Clear();
}
// ParentCommandName(actionPaletteItem.Command().Name());
// _updateCurrentNestedCommands(actionPaletteItem.Command());
// }
// else
// {
// ParentCommandName(L"");
// _currentNestedCommands.Clear();
// }
_updateFilteredActions();
const auto lastSelectedIt = std::find_if(begin(_filteredActions), end(_filteredActions), [&](const auto& filteredCommand) {
return filteredCommand.Item().Name() == previousAction.Item().Name();
});
const auto lastSelectedIndex = static_cast<int32_t>(std::distance(begin(_filteredActions), lastSelectedIt));
_scrollToIndex(lastSelectedIt != end(_filteredActions) ? lastSelectedIndex : 0);
// const auto lastSelectedIt = std::find_if(begin(_filteredActions), end(_filteredActions), [&](const auto& filteredCommand) {
// return impl(filteredCommand)->Item().Name() == impl(previousAction)->Item().Name();
// });
// const auto lastSelectedIndex = static_cast<int32_t>(std::distance(begin(_filteredActions), lastSelectedIt));
// _scrollToIndex(lastSelectedIt != end(_filteredActions) ? lastSelectedIndex : 0);
}
// Method Description:
@@ -668,13 +671,16 @@ namespace winrt::TerminalApp::implementation
// - <none>
// Return Value:
// - A list of Commands to filter.
Collections::IVector<winrt::TerminalApp::FilteredCommand> SuggestionsControl::_commandsToFilter()
Collections::IVector<winrt::TerminalApp::FilteredTask> SuggestionsControl::_commandsToFilter()
{
if (_nestedActionStack.Size() > 0)
// if (_nestedActionStack.Size() > 0)
// {
// return _currentNestedCommands;
// }
if (_searchBox().Text().size() > 0)
{
return _currentNestedCommands;
return _flatAllCommands;
}
return _allCommands;
}
@@ -687,22 +693,22 @@ namespace winrt::TerminalApp::implementation
// - command: the Command to dispatch. This might be null.
// Return Value:
// - <none>
void SuggestionsControl::_dispatchCommand(const winrt::TerminalApp::FilteredCommand& filteredCommand)
void SuggestionsControl::_dispatchCommand(const winrt::TerminalApp::FilteredTask& filteredCommand)
{
if (filteredCommand)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
if (const auto actionPaletteItem{ impl(filteredCommand)->Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
{
if (actionPaletteItem.Command().HasNestedCommands())
{
// If this Command had subcommands, then don't dispatch the
// action. Instead, display a new list of commands for the user
// to pick from.
_nestedActionStack.Append(filteredCommand);
ParentCommandName(actionPaletteItem.Command().Name());
_updateCurrentNestedCommands(actionPaletteItem.Command());
// // If this Command had subcommands, then don't dispatch the
// // action. Instead, display a new list of commands for the user
// // to pick from.
// _nestedActionStack.Append(filteredCommand);
// ParentCommandName(actionPaletteItem.Command().Name());
// _updateCurrentNestedCommands(actionPaletteItem.Command());
_updateUIForStackChange();
// _updateUIForStackChange();
}
else
{
@@ -710,7 +716,7 @@ namespace winrt::TerminalApp::implementation
const auto searchTextLength = _searchBox().Text().size();
// An action from the root command list has depth=0
const auto nestedCommandDepth = _nestedActionStack.Size();
const auto nestedCommandDepth = 0; // _nestedActionStack.Size();
// Close before we dispatch so that actions that open the command
// palette like the Tab Switcher will be able to have the last laugh.
@@ -800,7 +806,8 @@ namespace winrt::TerminalApp::implementation
_updateFilteredActions();
// In the command line mode we want the user to explicitly select the command
_filteredActionsView().SelectedIndex(std::min<int32_t>(lastSelectedIndex, _filteredActionsView().Items().Size() - 1));
// _filteredActionsView().SelectedIndex(std::min<int32_t>(lastSelectedIndex, _filteredActionsView().Items().Size() - 1));
_scrollToIndex(lastSelectedIndex);
const auto currentNeedleHasResults{ _filteredActions.Size() > 0 };
_noMatchesText().Visibility(currentNeedleHasResults ? Visibility::Collapsed : Visibility::Visible);
@@ -816,7 +823,7 @@ namespace winrt::TerminalApp::implementation
}
}
Collections::IObservableVector<winrt::TerminalApp::FilteredCommand> SuggestionsControl::FilteredActions()
Collections::IObservableVector<winrt::TerminalApp::FilteredTask> SuggestionsControl::FilteredActions()
{
return _filteredActions;
}
@@ -824,12 +831,40 @@ namespace winrt::TerminalApp::implementation
void SuggestionsControl::SetCommands(const Collections::IVector<Command>& actions)
{
_allCommands.Clear();
_flatAllCommands.Clear();
std::function<void(Collections::IMapView<winrt::hstring, Command>)> addMap;
addMap = [&](auto actionMap) {
for (const auto& [_, action] : actionMap)
{
if (action.HasNestedCommands())
{
addMap(action.NestedCommands());
}
else
{
auto filteredCommand{ winrt::make<FilteredTask>(action) };
_flatAllCommands.Append(filteredCommand);
}
}
};
for (const auto& action : actions)
{
// key chords aren't relevant in the suggestions control, so make the palette item with just the command and no keys
auto actionPaletteItem{ winrt::make<winrt::TerminalApp::implementation::ActionPaletteItem>(action, winrt::hstring{}) };
auto filteredCommand{ winrt::make<FilteredCommand>(actionPaletteItem) };
_allCommands.Append(filteredCommand);
// // key chords aren't relevant in the suggestions control, so make the palette item with just the command and no keys
// //auto actionPaletteItem{ winrt::make<winrt::TerminalApp::implementation::ActionPaletteItem>(action, winrt::hstring{}) };
// auto filteredCommand{ winrt::make<FilteredTask>(action) };
// _allCommands.Append(filteredCommand);
if (action.HasNestedCommands())
{
addMap(action.NestedCommands());
}
else
{
auto filteredCommand{ winrt::make<FilteredTask>(action) };
_allCommands.Append(filteredCommand);
_flatAllCommands.Append(filteredCommand);
}
}
if (Visibility() == Visibility::Visible)
@@ -853,9 +888,9 @@ namespace winrt::TerminalApp::implementation
_searchBox().Text(L"");
_searchBox().Select(_searchBox().Text().size(), 0);
_nestedActionStack.Clear();
// _nestedActionStack.Clear();
ParentCommandName(L"");
_currentNestedCommands.Clear();
// _currentNestedCommands.Clear();
// Leaving this block of code outside the above if-statement
// guarantees that the correct text is shown for the mode
// whenever _switchToMode is called.
@@ -879,9 +914,9 @@ namespace winrt::TerminalApp::implementation
// - A collection that will receive the filtered actions
// Return Value:
// - <none>
std::vector<winrt::TerminalApp::FilteredCommand> SuggestionsControl::_collectFilteredActions()
std::vector<winrt::TerminalApp::FilteredTask> SuggestionsControl::_collectFilteredActions()
{
std::vector<winrt::TerminalApp::FilteredCommand> actions;
std::vector<winrt::TerminalApp::FilteredTask> actions;
winrt::hstring searchText{ _getTrimmedInput() };
@@ -890,13 +925,14 @@ namespace winrt::TerminalApp::implementation
{
for (const auto& action : commandsToFilter)
{
auto* const snippet{ impl(action) };
// Update filter for all commands
// This will modify the highlighting but will also lead to re-computation of weight (and consequently sorting).
// Pay attention that it already updates the highlighting in the UI
action.UpdateFilter(searchText);
snippet->UpdateFilter(searchText);
// if there is active search we skip commands with 0 weight
if (searchText.empty() || action.Weight() > 0)
if (searchText.empty() || snippet->Weight() > 0)
{
actions.push_back(action);
}
@@ -910,6 +946,12 @@ namespace winrt::TerminalApp::implementation
// This is in contrast to the Command Palette, which always sorts its
// actions.
// We want to present the commands sorted
if (!searchText.empty())
{
std::sort(actions.begin(), actions.end(), FilteredTask::Compare);
}
// Adjust the order of the results depending on if we're top-down or
// bottom up. This way, the "first" / "best" match is always closest to
// the cursor.
@@ -937,9 +979,10 @@ namespace winrt::TerminalApp::implementation
// This allows WinUI to nicely animate the ListView as it changes.
for (uint32_t i = 0; i < _filteredActions.Size() && i < actions.size(); i++)
{
auto* const newItemImpl{ impl(actions[i]) };
for (auto j = i; j < _filteredActions.Size(); j++)
{
if (_filteredActions.GetAt(j).Item() == actions[i].Item())
if (impl(_filteredActions.GetAt(j))->Item() == newItemImpl->Item())
{
for (auto k = i; k < j; k++)
{
@@ -949,7 +992,7 @@ namespace winrt::TerminalApp::implementation
}
}
if (_filteredActions.GetAt(i).Item() != actions[i].Item())
if (impl(_filteredActions.GetAt(i))->Item() != newItemImpl->Item())
{
_filteredActions.InsertAt(i, actions[i]);
}
@@ -975,16 +1018,16 @@ namespace winrt::TerminalApp::implementation
// - parentCommand: the command with an optional list of nested commands.
// Return Value:
// - <none>
void SuggestionsControl::_updateCurrentNestedCommands(const winrt::Microsoft::Terminal::Settings::Model::Command& parentCommand)
void SuggestionsControl::_updateCurrentNestedCommands(const winrt::Microsoft::Terminal::Settings::Model::Command& /*parentCommand*/)
{
_currentNestedCommands.Clear();
for (const auto& nameAndCommand : parentCommand.NestedCommands())
{
const auto action = nameAndCommand.Value();
auto nestedActionPaletteItem{ winrt::make<winrt::TerminalApp::implementation::ActionPaletteItem>(action, winrt::hstring{}) };
auto nestedFilteredCommand{ winrt::make<FilteredCommand>(nestedActionPaletteItem) };
_currentNestedCommands.Append(nestedFilteredCommand);
}
// _currentNestedCommands.Clear();
// for (const auto& nameAndCommand : parentCommand.NestedCommands())
// {
// const auto action = nameAndCommand.Value();
// auto nestedActionPaletteItem{ winrt::make<winrt::TerminalApp::implementation::ActionPaletteItem>(action, winrt::hstring{}) };
// auto nestedFilteredTask{ winrt::make<FilteredTask>(action) };
// _currentNestedCommands.Append(nestedFilteredTask);
// }
}
// Method Description:
@@ -1003,10 +1046,10 @@ namespace winrt::TerminalApp::implementation
// Clear the text box each time we close the dialog. This is consistent with VsCode.
_searchBox().Text(L"");
_nestedActionStack.Clear();
// _nestedActionStack.Clear();
ParentCommandName(L"");
_currentNestedCommands.Clear();
// _currentNestedCommands.Clear();
PreviewAction.raise(*this, nullptr);
}

View File

@@ -3,7 +3,7 @@
#pragma once
#include "FilteredCommand.h"
#include "FilteredTask.h"
#include "SuggestionsControl.g.h"
#include "AppCommandlineArgs.h"
@@ -21,7 +21,7 @@ namespace winrt::TerminalApp::implementation
{
SuggestionsControl();
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::FilteredCommand> FilteredActions();
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::FilteredTask> FilteredActions();
void SetCommands(const Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::Command>& actions);
@@ -66,10 +66,11 @@ namespace winrt::TerminalApp::implementation
};
friend struct SuggestionsControlT<SuggestionsControl>; // for Xaml to bind events
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _allCommands{ nullptr };
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _currentNestedCommands{ nullptr };
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::FilteredCommand> _filteredActions{ nullptr };
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _nestedActionStack{ nullptr };
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredTask> _allCommands{ nullptr };
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredTask> _flatAllCommands{ nullptr };
// Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredTask> _currentNestedCommands{ nullptr };
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::FilteredTask> _filteredActions{ nullptr };
// Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredTask> _nestedActionStack{ nullptr };
TerminalApp::SuggestionsMode _mode{ TerminalApp::SuggestionsMode::Palette };
TerminalApp::SuggestionsDirection _direction{ TerminalApp::SuggestionsDirection::TopDown };
@@ -94,7 +95,7 @@ namespace winrt::TerminalApp::implementation
void _updateUIForStackChange();
void _updateFilteredActions();
void _dispatchCommand(const winrt::TerminalApp::FilteredCommand& command);
void _dispatchCommand(const winrt::TerminalApp::FilteredTask& command);
void _close();
void _dismissPalette();
@@ -120,8 +121,8 @@ namespace winrt::TerminalApp::implementation
void _choosingItemContainer(const Windows::UI::Xaml::Controls::ListViewBase& sender, const Windows::UI::Xaml::Controls::ChoosingItemContainerEventArgs& args);
void _containerContentChanging(const Windows::UI::Xaml::Controls::ListViewBase& sender, const Windows::UI::Xaml::Controls::ContainerContentChangingEventArgs& args);
std::vector<winrt::TerminalApp::FilteredCommand> _collectFilteredActions();
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _commandsToFilter();
std::vector<winrt::TerminalApp::FilteredTask> _collectFilteredActions();
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredTask> _commandsToFilter();
std::wstring _getTrimmedInput();
uint32_t _getNumVisibleItems();
friend class TerminalAppLocalTests::TabTests;

View File

@@ -3,7 +3,7 @@
import "TabBase.idl";
import "HighlightedTextControl.idl";
import "FilteredCommand.idl";
import "FilteredTask.idl";
namespace TerminalApp
{
@@ -31,7 +31,7 @@ namespace TerminalApp
Windows.UI.Xaml.FrameworkElement SelectedItem { get; };
Windows.Foundation.Collections.IObservableVector<FilteredCommand> FilteredActions { get; };
Windows.Foundation.Collections.IObservableVector<FilteredTask> FilteredActions { get; };
SuggestionsMode Mode { get; set; };

View File

@@ -36,7 +36,7 @@
</DataTemplate>
<DataTemplate x:Key="GeneralItemTemplate"
x:DataType="local:FilteredCommand">
x:DataType="local:FilteredTask">
<Grid HorizontalAlignment="Stretch"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
@@ -53,17 +53,17 @@
<ContentPresenter Grid.Column="0"
Width="16"
Height="16"
Content="{x:Bind Item.ResolvedIcon, Mode=OneWay}" />
Content="{x:Bind FilteredCommand.Item.ResolvedIcon, Mode=OneWay}" />
<local:HighlightedTextControl Grid.Column="1"
HorizontalAlignment="Left"
Text="{x:Bind HighlightedName, Mode=OneWay}" />
Text="{x:Bind FilteredCommand.HighlightedName, Mode=OneWay}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="NestedItemTemplate"
x:DataType="local:FilteredCommand">
x:DataType="local:FilteredTask">
<Grid HorizontalAlignment="Stretch"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
@@ -80,11 +80,11 @@
<ContentPresenter Grid.Column="0"
Width="16"
Height="16"
Content="{x:Bind Item.ResolvedIcon, Mode=OneWay}" />
Content="{x:Bind FilteredCommand.Item.ResolvedIcon, Mode=OneWay}" />
<local:HighlightedTextControl Grid.Column="1"
HorizontalAlignment="Left"
Text="{x:Bind HighlightedName, Mode=OneWay}" />
Text="{x:Bind FilteredCommand.HighlightedName, Mode=OneWay}" />
<FontIcon Grid.Column="2"
HorizontalAlignment="Right"

View File

@@ -130,6 +130,7 @@
<DependentUpon>CommandPalette.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="FilteredCommand.h" />
<ClInclude Include="FilteredTask.h" />
<ClInclude Include="Pane.h" />
<ClInclude Include="ColorHelper.h" />
<ClInclude Include="pch.h" />
@@ -360,6 +361,7 @@
<SubType>Code</SubType>
</Midl>
<Midl Include="FilteredCommand.idl" />
<Midl Include="FilteredTask.idl" />
<Midl Include="IPaneContent.idl" />
<Midl Include="TerminalPaneContent.idl" >
<DependentUpon>TaskPaneContent.xaml</DependentUpon>
@@ -502,4 +504,4 @@
</ItemGroup>
</Target>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
</Project>
</Project>

View File

@@ -3,7 +3,6 @@
import "IPaneContent.idl";
import "TerminalSettingsCache.idl";
import "FilteredCommand.idl";
namespace TerminalApp
{
@@ -18,16 +17,6 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<TerminalPaneContent, Object> RestartTerminalRequested;
}
[default_interface] runtimeclass FilteredTask : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
String Input{ get; };
Windows.Foundation.Collections.IObservableVector<FilteredTask> Children { get; };
Boolean HasChildren { get; };
Int32 Row { get; };
Windows.UI.Xaml.Visibility Visibility { get; };
TerminalApp.FilteredCommand FilteredCommand{ get; };
}
[default_interface] runtimeclass SnippetsPaneContent : Windows.UI.Xaml.Controls.UserControl, IPaneContent, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
SnippetsPaneContent();