Remove WinRT composition (inheritance) from PaletteItem (#19132)

Right now, we construct **two objects** for every palette item: the
derived type and the base type. It's unnnecessary.

This pull request replaces WinRT composition with a good old-fashioned
`enum ThingType`.

This also removes many of our palette items from our IDL. The only ones
that are necessary to expose via our WinRT API surface are the ones that
are used in XAML documents.

I originally removed the caching for `Command.Name`, but it turns out
that something calls `Name` roughly 17 times **per command** and having
the generator running that often is a serious waste of CPU.

## Validation Steps
- [x] Tab Switcher still live-updates when it is in use
- [x] Command searching still works
- [x] Commandline mode still works
- [x] Suggestions control still works
This commit is contained in:
Dustin L. Howett
2025-07-16 15:09:17 -05:00
committed by GitHub
parent bdf44322f8
commit e7939bb4e3
25 changed files with 322 additions and 367 deletions

View File

@@ -2,8 +2,8 @@
// Licensed under the MIT license.
#include "pch.h"
#include "../TerminalApp/CommandLinePaletteItem.h"
#include "../TerminalApp/CommandPalette.h"
#include "../TerminalApp/BasePaletteItem.h"
#include "CppWinrtTailored.h"
using namespace Microsoft::Console;
@@ -15,6 +15,19 @@ using namespace winrt::Microsoft::Terminal::Control;
namespace TerminalAppLocalTests
{
struct StringPaletteItem : winrt::implements<StringPaletteItem, winrt::TerminalApp::IPaletteItem, winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged>, winrt::TerminalApp::implementation::BasePaletteItem<StringPaletteItem, winrt::TerminalApp::PaletteItemType::CommandLine>
{
StringPaletteItem(std::wstring_view value) :
_value{ value } {}
winrt::hstring Name() { return _value; }
winrt::hstring KeyChordText() { return {}; }
winrt::hstring Icon() { return {}; }
private:
winrt::hstring _value;
};
class FilteredCommandTests
{
BEGIN_TEST_CLASS(FilteredCommandTests)
@@ -40,7 +53,7 @@ namespace TerminalAppLocalTests
auto result = RunOnUIThread([]() {
const WEX::TestExecution::DisableVerifyExceptions disableExceptionsScope;
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"AAAAAABBBBBBCCC") };
const auto paletteItem{ winrt::make<StringPaletteItem>(L"AAAAAABBBBBBCCC") };
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
{
@@ -112,7 +125,7 @@ namespace TerminalAppLocalTests
void FilteredCommandTests::VerifyWeight()
{
auto result = RunOnUIThread([]() {
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"AAAAAABBBBBBCCC") };
const auto paletteItem{ winrt::make<StringPaletteItem>(L"AAAAAABBBBBBCCC") };
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
const auto weigh = [&](const wchar_t* str) {
@@ -152,8 +165,8 @@ namespace TerminalAppLocalTests
void FilteredCommandTests::VerifyCompare()
{
auto result = RunOnUIThread([]() {
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"AAAAAABBBBBBCCC") };
const auto paletteItem2{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"BBBBBCCC") };
const auto paletteItem{ winrt::make<StringPaletteItem>(L"AAAAAABBBBBBCCC") };
const auto paletteItem2{ winrt::make<StringPaletteItem>(L"BBBBBCCC") };
{
Log::Comment(L"Testing comparison of commands with no filter");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
@@ -192,8 +205,8 @@ namespace TerminalAppLocalTests
void FilteredCommandTests::VerifyCompareIgnoreCase()
{
auto result = RunOnUIThread([]() {
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"a") };
const auto paletteItem2{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"B") };
const auto paletteItem{ winrt::make<StringPaletteItem>(L"a") };
const auto paletteItem2{ winrt::make<StringPaletteItem>(L"B") };
{
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem2);

View File

@@ -1,28 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "ActionPaletteItem.h"
#include <LibraryResources.h>
#include "ActionPaletteItem.g.cpp"
using namespace winrt;
using namespace winrt::TerminalApp;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::System;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
ActionPaletteItem::ActionPaletteItem(const Microsoft::Terminal::Settings::Model::Command& command, const winrt::hstring keyChordText) :
_Command(command)
{
Name(command.Name());
KeyChordText(keyChordText);
Icon(command.IconPath());
}
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PaletteItem.h"
#include "ActionPaletteItem.g.h"
namespace winrt::TerminalApp::implementation
{
struct ActionPaletteItem : ActionPaletteItemT<ActionPaletteItem, PaletteItem>
{
ActionPaletteItem() = default;
ActionPaletteItem(const Microsoft::Terminal::Settings::Model::Command& command, const winrt::hstring keyChordText);
WINRT_PROPERTY(Microsoft::Terminal::Settings::Model::Command, Command, nullptr);
private:
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _commandChangedRevoker;
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(ActionPaletteItem);
}

View File

@@ -1,14 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "PaletteItem.idl";
namespace TerminalApp
{
[default_interface] runtimeclass ActionPaletteItem : PaletteItem
{
ActionPaletteItem(Microsoft.Terminal.Settings.Model.Command command, String keyChordText);
Microsoft.Terminal.Settings.Model.Command Command { get; };
}
}

View File

@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
namespace winrt::TerminalApp::implementation
{
template<typename T, winrt::TerminalApp::PaletteItemType Ty>
struct BasePaletteItem
{
public:
winrt::TerminalApp::PaletteItemType Type() { return Ty; }
Windows::UI::Xaml::Controls::IconElement ResolvedIcon()
{
const auto icon{ static_cast<T*>(this)->Icon() };
if (!_resolvedIcon && !icon.empty())
{
const auto resolvedIcon{ Microsoft::Terminal::UI::IconPathConverter::IconWUX(icon) };
resolvedIcon.Width(16);
resolvedIcon.Height(16);
_resolvedIcon = resolvedIcon;
}
return _resolvedIcon;
}
til::property_changed_event PropertyChanged;
protected:
void BaseRaisePropertyChanged(wil::zwstring_view property)
{
PropertyChanged.raise(*static_cast<T*>(this), winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs{ property });
}
void InvalidateResolvedIcon()
{
_resolvedIcon = nullptr;
BaseRaisePropertyChanged(L"ResolvedIcon");
}
private:
Windows::UI::Xaml::Controls::IconElement _resolvedIcon{ nullptr };
};
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "CommandLinePaletteItem.h"
#include <LibraryResources.h>
#include "CommandLinePaletteItem.g.cpp"
using namespace winrt;
using namespace winrt::TerminalApp;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::System;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
CommandLinePaletteItem::CommandLinePaletteItem(const winrt::hstring& commandLine) :
_CommandLine(commandLine)
{
Name(commandLine);
}
}

View File

@@ -1,23 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PaletteItem.h"
#include "CommandLinePaletteItem.g.h"
namespace winrt::TerminalApp::implementation
{
struct CommandLinePaletteItem : CommandLinePaletteItemT<CommandLinePaletteItem, PaletteItem>
{
CommandLinePaletteItem() = default;
CommandLinePaletteItem(const winrt::hstring& commandLine);
WINRT_PROPERTY(winrt::hstring, CommandLine);
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(CommandLinePaletteItem);
}

View File

@@ -1,12 +0,0 @@
import "PaletteItem.idl";
import "TabBase.idl";
namespace TerminalApp
{
[default_interface] runtimeclass CommandLinePaletteItem : PaletteItem
{
CommandLinePaletteItem(String commandLine);
String CommandLine { get; };
}
}

View File

@@ -2,10 +2,8 @@
// Licensed under the MIT license.
#include "pch.h"
#include "ActionPaletteItem.h"
#include "TabPaletteItem.h"
#include "CommandLinePaletteItem.h"
#include "CommandPalette.h"
#include "CommandPaletteItems.h"
#include <LibraryResources.h>
#include "CommandPalette.g.cpp"
@@ -233,9 +231,11 @@ namespace winrt::TerminalApp::implementation
}
else if (_currentMode == CommandPaletteMode::ActionMode && filteredCommand != nullptr)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
PreviewAction.raise(*this, actionPaletteItem.Command());
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
PreviewAction.raise(*this, actionPaletteItem->Command());
}
}
else if (_currentMode == CommandPaletteMode::CommandlineMode)
@@ -555,10 +555,11 @@ namespace winrt::TerminalApp::implementation
const auto enteredItem = listViewItem.Content();
if (const auto filteredCommand{ enteredItem.try_as<winrt::TerminalApp::FilteredCommand>() })
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
// immediately preview the hovered command
PreviewAction.raise(*this, actionPaletteItem.Command());
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
PreviewAction.raise(*this, actionPaletteItem->Command());
}
}
}
@@ -589,9 +590,11 @@ namespace winrt::TerminalApp::implementation
{
if (_currentMode == CommandPaletteMode::ActionMode && filteredCommand)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
PreviewAction.raise(*this, actionPaletteItem.Command());
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
PreviewAction.raise(*this, actionPaletteItem->Command());
}
}
}
@@ -617,7 +620,7 @@ namespace winrt::TerminalApp::implementation
const auto selectedCommand = selectedList.GetAt(0);
if (const auto filteredCmd = selectedCommand.try_as<TerminalApp::FilteredCommand>())
{
if (const auto paletteItem = filteredCmd.Item().try_as<TerminalApp::PaletteItem>())
if (const auto paletteItem = filteredCmd.Item())
{
automationPeer.RaiseNotificationEvent(
Automation::Peers::AutomationNotificationKind::ItemAdded,
@@ -652,10 +655,13 @@ namespace winrt::TerminalApp::implementation
if (_nestedActionStack.Size() > 0)
{
const auto newPreviousAction{ _nestedActionStack.GetAt(_nestedActionStack.Size() - 1) };
const auto actionPaletteItem{ newPreviousAction.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() };
ParentCommandName(actionPaletteItem.Command().Name());
_updateCurrentNestedCommands(actionPaletteItem.Command());
const auto item{ newPreviousAction.Item() };
if (item.Type() == PaletteItemType::Action)
{
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
ParentCommandName(actionPaletteItem->Command().Name());
_updateCurrentNestedCommands(actionPaletteItem->Command());
}
}
else
{
@@ -757,16 +763,19 @@ namespace winrt::TerminalApp::implementation
}
else if (filteredCommand)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
if (actionPaletteItem.Command().HasNestedCommands())
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
auto command{ actionPaletteItem->Command() };
if (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());
ParentCommandName(command.Name());
_updateCurrentNestedCommands(command);
_updateUIForStackChange();
}
@@ -785,9 +794,9 @@ namespace winrt::TerminalApp::implementation
// But make an exception for the Toggle Command Palette action: we don't want the dispatch
// make the command palette - that was just closed - visible again.
// All other actions can just be dispatched.
if (actionPaletteItem.Command().ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
if (command.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
{
DispatchCommandRequested.raise(*this, actionPaletteItem.Command());
DispatchCommandRequested.raise(*this, command);
}
TraceLoggingWrite(
@@ -837,9 +846,11 @@ namespace winrt::TerminalApp::implementation
{
if (filteredCommand)
{
if (const auto tabPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::TabPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Tab)
{
if (const auto tab{ tabPaletteItem.Tab() })
const auto tabPaletteItem{ winrt::get_self<TabPaletteItem>(item) };
if (const auto tab{ tabPaletteItem->Tab() })
{
SwitchToTabRequested.raise(*this, tab);
}
@@ -867,9 +878,11 @@ namespace winrt::TerminalApp::implementation
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
if (const auto commandLinePaletteItem{ filteredCommand.value().Item().try_as<winrt::TerminalApp::CommandLinePaletteItem>() })
const auto item{ filteredCommand->Item() };
if (item.Type() == PaletteItemType::CommandLine)
{
CommandLineExecutionRequested.raise(*this, commandLinePaletteItem.CommandLine());
const auto commandLinePaletteItem{ winrt::get_self<CommandLinePaletteItem>(item) };
CommandLineExecutionRequested.raise(*this, commandLinePaletteItem->CommandLine());
_close();
}
}

View File

@@ -2,11 +2,11 @@
// Licensed under the MIT license.
#include "pch.h"
#include "TabPaletteItem.h"
#include "TerminalTab.h"
#include <LibraryResources.h>
#include "TabPaletteItem.g.cpp"
#include "CommandPaletteItems.h"
using namespace winrt;
using namespace winrt::TerminalApp;
@@ -20,25 +20,20 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
TabPaletteItem::TabPaletteItem(const winrt::TerminalApp::TabBase& tab) :
_tab(tab)
_tab{ tab }
{
Name(tab.Title());
Icon(tab.Icon());
_tabChangedRevoker = tab.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& sender, auto& e) {
auto item{ weakThis.get() };
auto senderTab{ sender.try_as<winrt::TerminalApp::TabBase>() };
if (item && senderTab)
_tabChangedRevoker = tab.PropertyChanged(winrt::auto_revoke, [=](auto& sender, auto& e) {
if (auto senderTab{ sender.try_as<winrt::TerminalApp::TabBase>() })
{
auto changedProperty = e.PropertyName();
if (changedProperty == L"Title")
{
item->Name(senderTab.Title());
BaseRaisePropertyChanged(L"Name");
}
else if (changedProperty == L"Icon")
{
item->Icon(senderTab.Icon());
BaseRaisePropertyChanged(L"Icon");
InvalidateResolvedIcon();
}
}
});
@@ -46,15 +41,11 @@ namespace winrt::TerminalApp::implementation
if (const auto terminalTab{ tab.try_as<winrt::TerminalApp::TerminalTab>() })
{
const auto status = terminalTab.TabStatus();
TabStatus(status);
_tabStatusChangedRevoker = status.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& /*sender*/, auto& /*e*/) {
_tabStatusChangedRevoker = status.PropertyChanged(winrt::auto_revoke, [=](auto& /*sender*/, auto& /*e*/) {
// Sometimes nested bindings do not get updated,
// thus let's notify property changed on TabStatus when one of its properties changes
if (auto item{ weakThis.get() })
{
item->PropertyChanged.raise(*item, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"TabStatus" });
}
BaseRaisePropertyChanged(L"TabStatus");
});
}
}

View File

@@ -0,0 +1,121 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "BasePaletteItem.h"
#include "TabPaletteItem.g.h"
#include "../inc/cppwinrt_utils.h"
namespace winrt::TerminalApp::implementation
{
struct ActionPaletteItem :
public winrt::implements<ActionPaletteItem, IPaletteItem, winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged>,
BasePaletteItem<ActionPaletteItem, winrt::TerminalApp::PaletteItemType::Action>
{
ActionPaletteItem(const Microsoft::Terminal::Settings::Model::Command& command, const winrt::hstring keyChordText) :
_Command{ command }, _name{ command.Name() }, _keyChordText{ keyChordText }
{
}
winrt::hstring Name()
{
return _name;
}
winrt::hstring KeyChordText()
{
return _keyChordText;
}
winrt::hstring Icon()
{
return _Command.IconPath();
}
WINRT_PROPERTY(Microsoft::Terminal::Settings::Model::Command, Command, nullptr);
private:
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _commandChangedRevoker;
winrt::hstring _name;
winrt::hstring _keyChordText;
};
struct CommandLinePaletteItem :
public winrt::implements<CommandLinePaletteItem, IPaletteItem, winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged>,
BasePaletteItem<CommandLinePaletteItem, winrt::TerminalApp::PaletteItemType::CommandLine>
{
CommandLinePaletteItem(const winrt::hstring& commandLine) :
_CommandLine{ commandLine } {}
winrt::hstring Name()
{
return _CommandLine;
}
winrt::hstring KeyChordText()
{
return {};
}
winrt::hstring Icon()
{
return {};
}
WINRT_PROPERTY(winrt::hstring, CommandLine);
};
struct TabPaletteItem :
public TabPaletteItemT<TabPaletteItem>,
BasePaletteItem<TabPaletteItem, winrt::TerminalApp::PaletteItemType::Tab>
{
TabPaletteItem(const winrt::TerminalApp::TabBase& tab);
winrt::TerminalApp::TabBase Tab() const noexcept
{
return _tab.get();
}
winrt::hstring Name()
{
if (auto tab = _tab.get())
{
return tab.Title();
}
return {};
}
winrt::hstring KeyChordText()
{
return {};
}
winrt::hstring Icon()
{
if (auto tab = _tab.get())
{
return tab.Icon();
}
return {};
}
winrt::TerminalApp::TerminalTabStatus TabStatus()
{
if (auto tab = _tab.get())
{
if (auto terminalTab = tab.try_as<winrt::TerminalApp::TerminalTab>())
{
return terminalTab.TabStatus();
}
}
return { nullptr };
}
private:
winrt::weak_ref<winrt::TerminalApp::TabBase> _tab;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _tabChangedRevoker;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _tabStatusChangedRevoker;
};
}

View File

@@ -19,9 +19,9 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
// This class is a wrapper of PaletteItem, that is used as an item of a filterable list in CommandPalette.
// This class is a wrapper of IPaletteItem, that is used as an item of a filterable list in CommandPalette.
// It manages a highlighted text that is computed by matching search filter characters to item name
FilteredCommand::FilteredCommand(const winrt::TerminalApp::PaletteItem& item)
FilteredCommand::FilteredCommand(const winrt::TerminalApp::IPaletteItem& item)
{
// Actually implement the ctor in _constructFilteredCommand
_constructFilteredCommand(item);
@@ -32,7 +32,7 @@ namespace winrt::TerminalApp::implementation
// HOWEVER, for cppwinrt ~ r e a s o n s ~, it doesn't actually derive from
// FilteredCommand directly, so we can't just use the FilteredCommand ctor
// directly in the base class.
void FilteredCommand::_constructFilteredCommand(const winrt::TerminalApp::PaletteItem& item)
void FilteredCommand::_constructFilteredCommand(const winrt::TerminalApp::IPaletteItem& item)
{
_Item = item;
_Weight = 0;
@@ -40,7 +40,7 @@ namespace winrt::TerminalApp::implementation
_update();
// Recompute the highlighted name if the item name changes
_itemChangedRevoker = _Item.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& /*sender*/, auto& e) {
_itemChangedRevoker = _Item.as<winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged>().PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& /*sender*/, auto& e) {
auto filteredCommand{ weakThis.get() };
if (filteredCommand && e.PropertyName() == L"Name")
{

View File

@@ -18,19 +18,19 @@ namespace winrt::TerminalApp::implementation
struct FilteredCommand : FilteredCommandT<FilteredCommand>
{
FilteredCommand() = default;
FilteredCommand(const winrt::TerminalApp::PaletteItem& item);
FilteredCommand(const winrt::TerminalApp::IPaletteItem& item);
virtual void UpdateFilter(std::shared_ptr<fzf::matcher::Pattern> pattern);
static int Compare(const winrt::TerminalApp::FilteredCommand& first, const winrt::TerminalApp::FilteredCommand& second);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::PaletteItem, Item, PropertyChanged.raise, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::IPaletteItem, Item, PropertyChanged.raise, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::Foundation::Collections::IVector<winrt::TerminalApp::HighlightedRun>, NameHighlights, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(int, Weight, PropertyChanged.raise);
protected:
void _constructFilteredCommand(const winrt::TerminalApp::PaletteItem& item);
void _constructFilteredCommand(const winrt::TerminalApp::IPaletteItem& item);
private:
std::shared_ptr<fzf::matcher::Pattern> _pattern;

View File

@@ -1,17 +1,17 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "PaletteItem.idl";
import "IPaletteItem.idl";
import "HighlightedTextControl.idl";
namespace TerminalApp
{
[default_interface] unsealed runtimeclass FilteredCommand : Windows.UI.Xaml.Data.INotifyPropertyChanged
runtimeclass FilteredCommand : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
FilteredCommand();
FilteredCommand(PaletteItem item);
FilteredCommand(IPaletteItem item);
PaletteItem Item { get; };
IPaletteItem Item { get; };
IVector<HighlightedRun> NameHighlights { get; };
Int32 Weight;
}

View File

@@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "TerminalTabStatus.idl";
namespace TerminalApp
{
enum PaletteItemType
{
Action,
CommandLine,
Tab,
};
interface IPaletteItem requires Windows.UI.Xaml.Data.INotifyPropertyChanged
{
PaletteItemType Type { get; };
String Name { get; };
String KeyChordText { get; };
String Icon { get; };
Windows.UI.Xaml.Controls.IconElement ResolvedIcon { get; };
}
runtimeclass TabPaletteItem : [default] IPaletteItem, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
TerminalTabStatus TabStatus{ get; };
}
}

View File

@@ -1,25 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include <LibraryResources.h>
#include "PaletteItem.h"
#include "PaletteItem.g.cpp"
using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Microsoft::Terminal::Control;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Windows::System;
namespace winrt::TerminalApp::implementation
{
Controls::IconElement PaletteItem::ResolvedIcon()
{
const auto icon = Microsoft::Terminal::UI::IconPathConverter::IconWUX(Icon());
icon.Width(16);
icon.Height(16);
return icon;
}
}

View File

@@ -1,20 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PaletteItem.g.h"
namespace winrt::TerminalApp::implementation
{
struct PaletteItem : PaletteItemT<PaletteItem>
{
public:
Windows::UI::Xaml::Controls::IconElement ResolvedIcon();
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Name, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, KeyChordText, PropertyChanged.raise);
};
}

View File

@@ -1,13 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace TerminalApp
{
unsealed runtimeclass PaletteItem : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
String Name;
String KeyChordText;
String Icon;
Windows.UI.Xaml.Controls.IconElement ResolvedIcon { get; };
}
}

View File

@@ -2,10 +2,11 @@
// Licensed under the MIT license.
#include "pch.h"
#include "TabPaletteItem.h"
#include "PaletteItemTemplateSelector.h"
#include "PaletteItemTemplateSelector.g.cpp"
#include "CommandPaletteItems.h"
namespace winrt::TerminalApp::implementation
{
Windows::UI::Xaml::DataTemplate PaletteItemTemplateSelector::SelectTemplateCore(const winrt::Windows::Foundation::IInspectable& item, const winrt::Windows::UI::Xaml::DependencyObject& /*container*/)
@@ -26,16 +27,22 @@ namespace winrt::TerminalApp::implementation
{
if (const auto filteredCommand{ item.try_as<winrt::TerminalApp::FilteredCommand>() })
{
if (filteredCommand.Item().try_as<winrt::TerminalApp::TabPaletteItem>())
switch (filteredCommand.Item().Type())
{
case PaletteItemType::Tab:
return TabItemTemplate();
}
else if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
case PaletteItemType::Action:
{
if (actionPaletteItem.Command().HasNestedCommands())
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(filteredCommand.Item()) };
if (actionPaletteItem->Command().HasNestedCommands())
{
return NestedItemTemplate();
}
break; // Fall back to the general template
}
case PaletteItemType::CommandLine:
default:
break; // Fall back to the general template
}
}

View File

@@ -6,7 +6,7 @@
#include "FilteredTask.g.h"
#include "BasicPaneEvents.h"
#include "FilteredCommand.h"
#include "ActionPaletteItem.h"
#include "CommandPaletteItems.h"
#include <LibraryResources.h>
namespace winrt::TerminalApp::implementation
@@ -62,7 +62,7 @@ namespace winrt::TerminalApp::implementation
FilteredTask(const winrt::Microsoft::Terminal::Settings::Model::Command& command)
{
_filteredCommand = winrt::make_self<implementation::FilteredCommand>(winrt::make<winrt::TerminalApp::implementation::ActionPaletteItem>(command, winrt::hstring{}));
_filteredCommand = winrt::make_self<implementation::FilteredCommand>(winrt::make<ActionPaletteItem>(command, winrt::hstring{}));
_command = command;
// The Children() method must always return a non-null vector
@@ -92,14 +92,13 @@ namespace winrt::TerminalApp::implementation
winrt::hstring Input()
{
if (const auto& actionItem{ _filteredCommand->Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
// **SAFETY GUARANTEE** We constructed this filtered command ourselves; we know what's inside it.
const auto actionItem{ winrt::get_self<ActionPaletteItem>(_filteredCommand->Item()) };
if (const auto& command{ actionItem->Command() })
{
if (const auto& command{ actionItem.Command() })
if (const auto& sendInput{ command.ActionAndArgs().Args().try_as<winrt::Microsoft::Terminal::Settings::Model::SendInputArgs>() })
{
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{ til::visualize_nonspace_control_codes(std::wstring{ sendInput.Input() }) };
}
}
return winrt::hstring{};

View File

@@ -2,11 +2,11 @@
// Licensed under the MIT license.
#include "pch.h"
#include "ActionPaletteItem.h"
#include "CommandLinePaletteItem.h"
#include "SuggestionsControl.h"
#include <LibraryResources.h>
#include "CommandPaletteItems.h"
#include "SuggestionsControl.g.cpp"
#include "../../types/inc/utils.hpp"
@@ -282,9 +282,11 @@ namespace winrt::TerminalApp::implementation
if (filteredCommand != nullptr &&
isVisible)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
const auto& cmd = actionPaletteItem.Command();
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
const auto& cmd = actionPaletteItem->Command();
PreviewAction.raise(*this, cmd);
const auto description{ cmd.Description() };
@@ -575,7 +577,7 @@ namespace winrt::TerminalApp::implementation
const auto selectedCommand = selectedList.GetAt(0);
if (const auto filteredCmd = selectedCommand.try_as<TerminalApp::FilteredCommand>())
{
if (const auto paletteItem = filteredCmd.Item().try_as<TerminalApp::PaletteItem>())
if (const auto paletteItem = filteredCmd.Item())
{
automationPeer.RaiseNotificationEvent(
Automation::Peers::AutomationNotificationKind::ItemAdded,
@@ -609,10 +611,14 @@ namespace winrt::TerminalApp::implementation
if (_nestedActionStack.Size() > 0)
{
const auto newPreviousAction{ _nestedActionStack.GetAt(_nestedActionStack.Size() - 1) };
const auto actionPaletteItem{ newPreviousAction.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() };
const auto item{ newPreviousAction.Item() };
if (item.Type() == PaletteItemType::Action)
{
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
ParentCommandName(actionPaletteItem.Command().Name());
_updateCurrentNestedCommands(actionPaletteItem.Command());
ParentCommandName(actionPaletteItem->Command().Name());
_updateCurrentNestedCommands(actionPaletteItem->Command());
}
}
else
{
@@ -693,16 +699,19 @@ namespace winrt::TerminalApp::implementation
{
if (filteredCommand)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
if (actionPaletteItem.Command().HasNestedCommands())
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
const auto command{ actionPaletteItem->Command() };
if (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());
ParentCommandName(command.Name());
_updateCurrentNestedCommands(command);
_updateUIForStackChange();
}
@@ -722,9 +731,9 @@ namespace winrt::TerminalApp::implementation
// "ToggleCommandPalette" actions. We may want to do the
// same with "Suggestions" actions in the future, should we
// ever allow non-sendInput actions.
DispatchCommandRequested.raise(*this, actionPaletteItem.Command());
DispatchCommandRequested.raise(*this, command);
if (const auto& sendInputCmd = actionPaletteItem.Command().ActionAndArgs().Args().try_as<SendInputArgs>())
if (const auto& sendInputCmd = command.ActionAndArgs().Args().try_as<SendInputArgs>())
{
if (til::starts_with(sendInputCmd.Input(), L"winget"))
{

View File

@@ -1,33 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PaletteItem.h"
#include "TabPaletteItem.g.h"
namespace winrt::TerminalApp::implementation
{
struct TabPaletteItem : TabPaletteItemT<TabPaletteItem, PaletteItem>
{
TabPaletteItem() = default;
TabPaletteItem(const winrt::TerminalApp::TabBase& tab);
winrt::TerminalApp::TabBase Tab() const noexcept
{
return _tab.get();
}
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::TerminalTabStatus, TabStatus, PropertyChanged.raise);
private:
winrt::weak_ref<winrt::TerminalApp::TabBase> _tab;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _tabChangedRevoker;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _tabStatusChangedRevoker;
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(TabPaletteItem);
}

View File

@@ -1,18 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "PaletteItem.idl";
import "TabBase.idl";
import "TerminalTabStatus.idl";
namespace TerminalApp
{
[default_interface] runtimeclass TabPaletteItem : PaletteItem
{
TabPaletteItem(TabBase tab);
TabBase Tab { get; };
TerminalTabStatus TabStatus { get; };
}
}

View File

@@ -82,11 +82,10 @@
</ItemGroup>
<!-- ========================= Headers ======================== -->
<ItemGroup>
<ClInclude Include="ActionPaletteItem.h" />
<ClInclude Include="App.base.h" />
<ClInclude Include="AppCommandlineArgs.h" />
<ClInclude Include="Commandline.h" />
<ClInclude Include="CommandLinePaletteItem.h" />
<ClInclude Include="CommandPaletteItems.h" />
<ClInclude Include="Jumplist.h" />
<ClInclude Include="LanguageProfileNotifier.h" />
<ClInclude Include="MinMaxCloseControl.h">
@@ -99,11 +98,10 @@
<DependentUpon>PaletteItemTemplateSelector.idl</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="PaletteItem.h" />
<ClInclude Include="BasePaletteItem.h" />
<ClInclude Include="TabBase.h">
<DependentUpon>TabBase.idl</DependentUpon>
</ClInclude>
<ClInclude Include="TabPaletteItem.h" />
<ClInclude Include="TaskbarState.h">
<DependentUpon>TaskbarState.idl</DependentUpon>
</ClInclude>
@@ -192,11 +190,10 @@
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
<ClCompile Include="ActionPaletteItem.cpp" />
<ClCompile Include="CommandLinePaletteItem.cpp" />
<ClCompile Include="init.cpp" />
<ClCompile Include="AppCommandlineArgs.cpp" />
<ClCompile Include="Commandline.cpp" />
<ClCompile Include="CommandPaletteItems.cpp" />
<ClCompile Include="Jumplist.cpp" />
<ClCompile Include="LanguageProfileNotifier.cpp" />
<ClCompile Include="MinMaxCloseControl.cpp">
@@ -209,12 +206,10 @@
<DependentUpon>PaletteItemTemplateSelector.idl</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="PaletteItem.cpp" />
<ClCompile Include="TabBase.cpp">
<DependentUpon>TabBase.idl</DependentUpon>
</ClCompile>
<ClCompile Include="fzf/fzf.cpp" />
<ClCompile Include="TabPaletteItem.cpp" />
<ClCompile Include="TaskbarState.cpp">
<DependentUpon>TaskbarState.idl</DependentUpon>
</ClCompile>
@@ -319,8 +314,6 @@
<ItemGroup>
<!-- If you add idl files here, make sure to include their implementation's
header in TerminalApp.vcxproj (as well as in this file) -->
<Midl Include="ActionPaletteItem.idl" />
<Midl Include="CommandLinePaletteItem.idl" />
<Midl Include="AboutDialog.idl">
<DependentUpon>AboutDialog.xaml</DependentUpon>
</Midl>
@@ -331,7 +324,7 @@
<Midl Include="PaletteItemTemplateSelector.idl">
<SubType>Designer</SubType>
</Midl>
<Midl Include="PaletteItem.idl" />
<Midl Include="IPaletteItem.idl" />
<Midl Include="ShortcutActionDispatch.idl" />
<Midl Include="AppKeyBindings.idl" />
<Midl Include="AppLogic.idl" />
@@ -341,7 +334,6 @@
<SubType>Code</SubType>
</Midl>
<Midl Include="TabBase.idl" />
<Midl Include="TabPaletteItem.idl" />
<Midl Include="TaskbarState.idl" />
<Midl Include="TerminalTab.idl" />
<Midl Include="TerminalPage.idl">

View File

@@ -26,16 +26,7 @@
<ClCompile Include="FilteredCommand.cpp">
<Filter>commandPalette</Filter>
</ClCompile>
<ClCompile Include="ActionPaletteItem.cpp">
<Filter>commandPalette</Filter>
</ClCompile>
<ClCompile Include="PaletteItem.cpp">
<Filter>commandPalette</Filter>
</ClCompile>
<ClCompile Include="TabPaletteItem.cpp">
<Filter>commandPalette</Filter>
</ClCompile>
<ClCompile Include="CommandLinePaletteItem.cpp">
<ClCompile Include="CommandPaletteItems.cpp">
<Filter>commandPalette</Filter>
</ClCompile>
<ClCompile Include="fzf/fzf.cpp">
@@ -62,16 +53,10 @@
<ClInclude Include="FilteredCommand.h">
<Filter>commandPalette</Filter>
</ClInclude>
<ClInclude Include="ActionPaletteItem.h">
<ClInclude Include="CommandPaletteItems.h">
<Filter>commandPalette</Filter>
</ClInclude>
<ClInclude Include="PaletteItem.h">
<Filter>commandPalette</Filter>
</ClInclude>
<ClInclude Include="TabPaletteItem.h">
<Filter>commandPalette</Filter>
</ClInclude>
<ClInclude Include="CommandLinePaletteItem.h">
<ClInclude Include="BasePaletteItem.h">
<Filter>commandPalette</Filter>
</ClInclude>
<ClInclude Include="fzf/fzf.h">
@@ -135,16 +120,7 @@
<Page Include="CommandPalette.xaml">
<Filter>commandPalette</Filter>
</Page>
<Midl Include="PaletteItem.idl">
<Filter>commandPalette</Filter>
</Midl>
<Midl Include="TabPaletteItem.idl">
<Filter>commandPalette</Filter>
</Midl>
<Midl Include="ActionPaletteItem.idl">
<Filter>commandPalette</Filter>
</Midl>
<Midl Include="CommandLinePaletteItem.idl">
<Midl Include="IPaletteItem.idl">
<Filter>commandPalette</Filter>
</Midl>
<Page Include="HighlightedTextControlStyle.xaml">