2020-06-26 22:38:02 +02:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
|
|
// Licensed under the MIT license.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2020-11-06 02:37:45 +01:00
|
|
|
#include "FilteredCommand.h"
|
2020-06-26 22:38:02 +02:00
|
|
|
#include "CommandPalette.g.h"
|
2020-12-16 03:03:13 +01:00
|
|
|
#include "AppCommandlineArgs.h"
|
2020-06-26 22:38:02 +02:00
|
|
|
#include "../../cascadia/inc/cppwinrt_utils.h"
|
|
|
|
|
2020-11-06 02:37:45 +01:00
|
|
|
// fwdecl unittest classes
|
|
|
|
namespace TerminalAppLocalTests
|
|
|
|
{
|
2020-11-09 19:37:19 +01:00
|
|
|
class TabTests;
|
2020-11-06 02:37:45 +01:00
|
|
|
};
|
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
namespace winrt::TerminalApp::implementation
|
|
|
|
{
|
2020-08-11 16:03:12 +02:00
|
|
|
enum class CommandPaletteMode
|
|
|
|
{
|
|
|
|
ActionMode = 0,
|
2020-08-21 17:39:40 +02:00
|
|
|
TabSearchMode,
|
2020-08-24 23:39:07 +02:00
|
|
|
TabSwitchMode,
|
|
|
|
CommandlineMode
|
2020-08-11 16:03:12 +02:00
|
|
|
};
|
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
struct CommandPalette : CommandPaletteT<CommandPalette>
|
|
|
|
{
|
|
|
|
CommandPalette();
|
|
|
|
|
2020-11-06 02:37:45 +01:00
|
|
|
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::FilteredCommand> FilteredActions();
|
2020-08-11 16:03:12 +02:00
|
|
|
|
2020-10-06 18:56:59 +02:00
|
|
|
void SetCommands(Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::Command> const& actions);
|
2021-01-19 23:18:10 +01:00
|
|
|
void SetTabs(Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase> const& tabs, Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase> const& mruTabs);
|
Introduce ActionMap to Terminal Settings Model (#9621)
This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`).
## References
#9428 - Spec
#6900 - Actions page
Closes #7441
## Detailed Description of the Pull Request / Additional comments
The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item.
#9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`.
Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette.
Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller.
The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands.
## Validation Steps Performed
All local tests pass.
2021-05-05 06:50:13 +02:00
|
|
|
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
|
2020-08-21 17:39:40 +02:00
|
|
|
|
|
|
|
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
|
|
|
|
|
|
|
void SelectNextItem(const bool moveDown);
|
|
|
|
|
2020-11-09 22:55:11 +01:00
|
|
|
void ScrollPageUp();
|
|
|
|
void ScrollPageDown();
|
|
|
|
void ScrollToTop();
|
|
|
|
void ScrollToBottom();
|
2020-10-22 06:40:57 +02:00
|
|
|
|
2021-01-19 23:18:10 +01:00
|
|
|
void EnableCommandPaletteMode(Microsoft::Terminal::Settings::Model::CommandPaletteLaunchMode const launchMode);
|
|
|
|
void EnableTabSwitcherMode(const uint32_t startIdx, Microsoft::Terminal::Settings::Model::TabSwitcherMode tabSwitcherMode);
|
|
|
|
void EnableTabSearchMode();
|
2020-08-11 16:03:12 +02:00
|
|
|
|
|
|
|
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
2021-03-04 20:27:03 +01:00
|
|
|
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, NoMatchesText, _PropertyChangedHandlers);
|
|
|
|
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SearchBoxPlaceholderText, _PropertyChangedHandlers);
|
|
|
|
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, PrefixCharacter, _PropertyChangedHandlers);
|
|
|
|
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ControlName, _PropertyChangedHandlers);
|
|
|
|
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParentCommandName, _PropertyChangedHandlers);
|
|
|
|
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParsedCommandLineText, _PropertyChangedHandlers);
|
2020-08-11 16:03:12 +02:00
|
|
|
|
2020-12-10 01:36:28 +01:00
|
|
|
TYPED_EVENT(SwitchToTabRequested, winrt::TerminalApp::CommandPalette, winrt::TerminalApp::TabBase);
|
|
|
|
TYPED_EVENT(CommandLineExecutionRequested, winrt::TerminalApp::CommandPalette, winrt::hstring);
|
|
|
|
TYPED_EVENT(DispatchCommandRequested, winrt::TerminalApp::CommandPalette, Microsoft::Terminal::Settings::Model::Command);
|
2021-04-21 22:35:06 +02:00
|
|
|
TYPED_EVENT(PreviewAction, Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::Command);
|
2020-12-10 01:36:28 +01:00
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
private:
|
|
|
|
friend struct CommandPaletteT<CommandPalette>; // for Xaml to bind events
|
|
|
|
|
2020-11-06 02:37:45 +01:00
|
|
|
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 };
|
2020-08-11 16:03:12 +02:00
|
|
|
|
2020-11-06 02:37:45 +01:00
|
|
|
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _commandsToFilter();
|
2020-08-11 16:03:12 +02:00
|
|
|
|
2020-10-16 00:58:35 +02:00
|
|
|
bool _lastFilterTextWasEmpty{ true };
|
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
void _filterTextChanged(Windows::Foundation::IInspectable const& sender,
|
|
|
|
Windows::UI::Xaml::RoutedEventArgs const& args);
|
2020-08-11 16:03:12 +02:00
|
|
|
void _previewKeyDownHandler(Windows::Foundation::IInspectable const& sender,
|
|
|
|
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
2021-02-10 21:35:46 +01:00
|
|
|
|
2020-08-11 16:03:12 +02:00
|
|
|
void _keyUpHandler(Windows::Foundation::IInspectable const& sender,
|
|
|
|
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
2020-06-26 22:38:02 +02:00
|
|
|
|
2020-10-08 00:49:10 +02:00
|
|
|
void _selectedCommandChanged(Windows::Foundation::IInspectable const& sender,
|
|
|
|
Windows::UI::Xaml::RoutedEventArgs const& args);
|
|
|
|
|
Add support for iterable, nested commands (#6856)
## Summary of the Pull Request
This PR adds support for both _nested_ and _iterable_ commands in the Command palette.
![nested-commands-000](https://user-images.githubusercontent.com/18356694/87072916-2d991c00-c1e2-11ea-8917-a70e8b8b9803.gif)
* **Nested commands**: These are commands that include additional sub-commands. When the user selects on of these, the palette will update to only show the nested commands.
* **Iterable commands**: These are commands what allow the user to define only a single command, which is repeated once for every profile. (in the future, also repeated for color schemes, themes, etc.)
The above gif uses the following json:
```json
{
"name": "Split Pane...",
"commands": [
{
"iterateOn": "profiles",
"name": "Split with ${profile.name}...",
"commands": [
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "automatic" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } }
]
}
]
},
```
## References
## PR Checklist
* [x] Closes #3994
* [x] I work here
* [x] Tests added/passed
* [ ] Requires documentation to be updated - Sure does, but we'll finish polishing this first.
## Detailed Description of the Pull Request / Additional comments
We've now gotta keep the original json for a command around, so that once we know what all the profiles will be, we can expand the commands that need it.
We've also got to parse commands recursively, because they might have any number of child commands.
These together made the command parsing a _lot_ more complicated, but it feels good so far.
## Validation Steps Performed
* wrote a bunch of tests
* Played with it a bunch
2020-08-13 23:22:46 +02:00
|
|
|
void _updateUIForStackChange();
|
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
void _rootPointerPressed(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
|
2020-12-09 23:01:08 +01:00
|
|
|
|
|
|
|
void _lostFocusHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
|
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
void _backdropPointerPressed(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
|
|
|
|
|
|
|
|
void _listItemClicked(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::ItemClickEventArgs const& e);
|
|
|
|
|
2020-11-05 01:19:52 +01:00
|
|
|
void _moveBackButtonClicked(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const&);
|
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
void _updateFilteredActions();
|
Add support for iterable, nested commands (#6856)
## Summary of the Pull Request
This PR adds support for both _nested_ and _iterable_ commands in the Command palette.
![nested-commands-000](https://user-images.githubusercontent.com/18356694/87072916-2d991c00-c1e2-11ea-8917-a70e8b8b9803.gif)
* **Nested commands**: These are commands that include additional sub-commands. When the user selects on of these, the palette will update to only show the nested commands.
* **Iterable commands**: These are commands what allow the user to define only a single command, which is repeated once for every profile. (in the future, also repeated for color schemes, themes, etc.)
The above gif uses the following json:
```json
{
"name": "Split Pane...",
"commands": [
{
"iterateOn": "profiles",
"name": "Split with ${profile.name}...",
"commands": [
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "automatic" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } }
]
}
]
},
```
## References
## PR Checklist
* [x] Closes #3994
* [x] I work here
* [x] Tests added/passed
* [ ] Requires documentation to be updated - Sure does, but we'll finish polishing this first.
## Detailed Description of the Pull Request / Additional comments
We've now gotta keep the original json for a command around, so that once we know what all the profiles will be, we can expand the commands that need it.
We've also got to parse commands recursively, because they might have any number of child commands.
These together made the command parsing a _lot_ more complicated, but it feels good so far.
## Validation Steps Performed
* wrote a bunch of tests
* Played with it a bunch
2020-08-13 23:22:46 +02:00
|
|
|
|
2020-11-06 02:37:45 +01:00
|
|
|
std::vector<winrt::TerminalApp::FilteredCommand> _collectFilteredActions();
|
Add support for iterable, nested commands (#6856)
## Summary of the Pull Request
This PR adds support for both _nested_ and _iterable_ commands in the Command palette.
![nested-commands-000](https://user-images.githubusercontent.com/18356694/87072916-2d991c00-c1e2-11ea-8917-a70e8b8b9803.gif)
* **Nested commands**: These are commands that include additional sub-commands. When the user selects on of these, the palette will update to only show the nested commands.
* **Iterable commands**: These are commands what allow the user to define only a single command, which is repeated once for every profile. (in the future, also repeated for color schemes, themes, etc.)
The above gif uses the following json:
```json
{
"name": "Split Pane...",
"commands": [
{
"iterateOn": "profiles",
"name": "Split with ${profile.name}...",
"commands": [
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "automatic" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } },
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } }
]
}
]
},
```
## References
## PR Checklist
* [x] Closes #3994
* [x] I work here
* [x] Tests added/passed
* [ ] Requires documentation to be updated - Sure does, but we'll finish polishing this first.
## Detailed Description of the Pull Request / Additional comments
We've now gotta keep the original json for a command around, so that once we know what all the profiles will be, we can expand the commands that need it.
We've also got to parse commands recursively, because they might have any number of child commands.
These together made the command parsing a _lot_ more complicated, but it feels good so far.
## Validation Steps Performed
* wrote a bunch of tests
* Played with it a bunch
2020-08-13 23:22:46 +02:00
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
void _close();
|
2020-07-08 01:31:31 +02:00
|
|
|
|
2020-08-11 16:03:12 +02:00
|
|
|
CommandPaletteMode _currentMode;
|
|
|
|
void _switchToMode(CommandPaletteMode mode);
|
|
|
|
|
2020-10-16 00:58:35 +02:00
|
|
|
std::wstring _getTrimmedInput();
|
2020-08-24 23:39:07 +02:00
|
|
|
void _evaluatePrefix();
|
|
|
|
|
Introduce ActionMap to Terminal Settings Model (#9621)
This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`).
## References
#9428 - Spec
#6900 - Actions page
Closes #7441
## Detailed Description of the Pull Request / Additional comments
The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item.
#9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`.
Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette.
Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller.
The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands.
## Validation Steps Performed
All local tests pass.
2021-05-05 06:50:13 +02:00
|
|
|
Microsoft::Terminal::Settings::Model::IActionMapView _actionMap{ nullptr };
|
2020-08-21 17:39:40 +02:00
|
|
|
|
2020-08-11 16:03:12 +02:00
|
|
|
// Tab Switcher
|
2020-11-06 02:37:45 +01:00
|
|
|
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _tabActions{ nullptr };
|
2021-01-19 23:18:10 +01:00
|
|
|
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _mruTabActions{ nullptr };
|
|
|
|
Microsoft::Terminal::Settings::Model::TabSwitcherMode _tabSwitcherMode;
|
2020-08-11 16:03:12 +02:00
|
|
|
uint32_t _switcherStartIdx;
|
2021-01-19 23:18:10 +01:00
|
|
|
|
|
|
|
void _bindTabs(Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase> const& source, Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> const& target);
|
2020-08-21 17:39:40 +02:00
|
|
|
void _anchorKeyUpHandler();
|
2020-08-11 16:03:12 +02:00
|
|
|
|
|
|
|
winrt::Windows::UI::Xaml::Controls::ListView::SizeChanged_revoker _sizeChangedRevoker;
|
|
|
|
|
2020-11-06 02:37:45 +01:00
|
|
|
void _dispatchCommand(winrt::TerminalApp::FilteredCommand const& command);
|
2020-11-25 21:30:36 +01:00
|
|
|
void _dispatchCommandline(winrt::TerminalApp::FilteredCommand const& command);
|
2020-12-10 01:36:28 +01:00
|
|
|
void _switchToTab(winrt::TerminalApp::FilteredCommand const& command);
|
2021-08-26 21:04:35 +02:00
|
|
|
static std::optional<winrt::TerminalApp::FilteredCommand> _buildCommandLineCommand(const winrt::hstring& commandLine);
|
2020-11-25 21:30:36 +01:00
|
|
|
|
2020-07-08 01:31:31 +02:00
|
|
|
void _dismissPalette();
|
2020-11-09 19:37:19 +01:00
|
|
|
|
2020-11-09 22:55:11 +01:00
|
|
|
void _scrollToIndex(uint32_t index);
|
|
|
|
uint32_t _getNumVisibleItems();
|
|
|
|
|
2021-08-26 21:04:35 +02:00
|
|
|
static constexpr uint32_t CommandLineHistoryLength = 20;
|
|
|
|
static Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _loadRecentCommands();
|
|
|
|
static void _updateRecentCommands(const winrt::hstring& command);
|
2020-12-16 03:03:13 +01:00
|
|
|
::TerminalApp::AppCommandlineArgs _appArgs;
|
2020-11-25 21:30:36 +01:00
|
|
|
|
2021-03-25 02:11:35 +01:00
|
|
|
void _choosingItemContainer(Windows::UI::Xaml::Controls::ListViewBase const& sender, Windows::UI::Xaml::Controls::ChoosingItemContainerEventArgs const& args);
|
|
|
|
void _containerContentChanging(Windows::UI::Xaml::Controls::ListViewBase const& sender, Windows::UI::Xaml::Controls::ContainerContentChangingEventArgs const& args);
|
|
|
|
winrt::TerminalApp::PaletteItemTemplateSelector _itemTemplateSelector{ nullptr };
|
|
|
|
std::unordered_map<Windows::UI::Xaml::DataTemplate, std::unordered_set<Windows::UI::Xaml::Controls::Primitives::SelectorItem>> _listViewItemsCache;
|
|
|
|
Windows::UI::Xaml::DataTemplate _listItemTemplate;
|
|
|
|
|
2020-11-09 19:37:19 +01:00
|
|
|
friend class TerminalAppLocalTests::TabTests;
|
2020-06-26 22:38:02 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace winrt::TerminalApp::factory_implementation
|
|
|
|
{
|
|
|
|
BASIC_FACTORY(CommandPalette);
|
|
|
|
}
|