Move Tab Switcher mode handling into CommandPalette (#8656)
A part of the #8415. Includes: * Moving `TabSwitcherMode` related decisions into `CommandPalette` (simplifying the logic of `TerminalPage::SelectNextTab`) * Fix a bug where the index of first tab switch is incorrect (since bindings are not updated) * Removing redundant `CommandPalette` updates * Preparations for tabs binding
This commit is contained in:
parent
9fed14a95e
commit
f196285824
|
@ -521,13 +521,8 @@ namespace winrt::TerminalApp::implementation
|
|||
void TerminalPage::_HandleOpenTabSearch(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
// Tab search is always in-order.
|
||||
CommandPalette().SetTabs(_tabs, true);
|
||||
|
||||
auto opt = _GetFocusedTabIndex();
|
||||
uint32_t startIdx = opt.value_or(0);
|
||||
|
||||
CommandPalette().EnableTabSwitcherMode(true, startIdx);
|
||||
CommandPalette().SetTabs(_tabs, _mruTabs);
|
||||
CommandPalette().EnableTabSearchMode();
|
||||
CommandPalette().Visibility(Visibility::Visible);
|
||||
|
||||
args.Handled(true);
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace winrt::TerminalApp::implementation
|
|||
_currentNestedCommands = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
|
||||
_allCommands = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
|
||||
_tabActions = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
|
||||
_mruTabActions = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
|
||||
_commandLineHistory = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
|
||||
|
||||
_switchToMode(CommandPaletteMode::ActionMode);
|
||||
|
@ -51,6 +52,12 @@ namespace winrt::TerminalApp::implementation
|
|||
RegisterPropertyChangedCallback(UIElement::VisibilityProperty(), [this](auto&&, auto&&) {
|
||||
if (Visibility() == Visibility::Visible)
|
||||
{
|
||||
if (_filteredActionsView().Items().Size() == 0 && _filteredActions.Size() > 0)
|
||||
{
|
||||
// Force immediate binding update so we can select an item
|
||||
Bindings->Update();
|
||||
}
|
||||
|
||||
if (_currentMode == CommandPaletteMode::TabSwitchMode)
|
||||
{
|
||||
_searchBox().Visibility(Visibility::Collapsed);
|
||||
|
@ -66,7 +73,6 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
_filteredActionsView().SelectedIndex(0);
|
||||
_searchBox().Focus(FocusState::Programmatic);
|
||||
_updateFilteredActions();
|
||||
}
|
||||
|
||||
TraceLoggingWrite(
|
||||
|
@ -112,7 +118,7 @@ namespace winrt::TerminalApp::implementation
|
|||
// - <none>
|
||||
void CommandPalette::SelectNextItem(const bool moveDown)
|
||||
{
|
||||
const auto selected = _filteredActionsView().SelectedIndex();
|
||||
auto selected = _filteredActionsView().SelectedIndex();
|
||||
const int numItems = ::base::saturated_cast<int>(_filteredActionsView().Items().Size());
|
||||
|
||||
// Do not try to select an item if
|
||||
|
@ -561,7 +567,7 @@ namespace winrt::TerminalApp::implementation
|
|||
case CommandPaletteMode::TabSearchMode:
|
||||
return _tabActions;
|
||||
case CommandPaletteMode::TabSwitchMode:
|
||||
return _tabActions;
|
||||
return _tabSwitcherMode == TabSwitcherMode::MostRecentlyUsed ? _mruTabActions : _tabActions;
|
||||
case CommandPaletteMode::CommandlineMode:
|
||||
return _commandLineHistory;
|
||||
default:
|
||||
|
@ -854,31 +860,40 @@ namespace winrt::TerminalApp::implementation
|
|||
_allCommands.Append(filteredCommand);
|
||||
}
|
||||
|
||||
_updateFilteredActions();
|
||||
if (Visibility() == Visibility::Visible && _currentMode == CommandPaletteMode::ActionMode)
|
||||
{
|
||||
_updateFilteredActions();
|
||||
}
|
||||
}
|
||||
|
||||
void CommandPalette::SetTabs(Collections::IVector<TabBase> const& tabs, const bool clearList)
|
||||
// Method Description:
|
||||
// - Replaces a list of filtered commands in the target collection with new
|
||||
// commands based on the tabs in the source collection.
|
||||
// Although the source observable we still don't register on it,
|
||||
// so the palette user will need to reset the binding manually every time
|
||||
// the source collection changes
|
||||
// Arguments:
|
||||
// - source: the tabs to use for creation filtered commands
|
||||
// - target: the collection to store newly created filtered commands
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void CommandPalette::_bindTabs(
|
||||
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase> const& source,
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> const& target)
|
||||
{
|
||||
_tabActions.Clear();
|
||||
for (const auto& tab : tabs)
|
||||
target.Clear();
|
||||
for (const auto& tab : source)
|
||||
{
|
||||
auto tabPaletteItem{ winrt::make<winrt::TerminalApp::implementation::TabPaletteItem>(tab) };
|
||||
auto filteredCommand{ winrt::make<FilteredCommand>(tabPaletteItem) };
|
||||
_tabActions.Append(filteredCommand);
|
||||
target.Append(filteredCommand);
|
||||
}
|
||||
}
|
||||
|
||||
// The smooth remove/add animations that happen during
|
||||
// UpdateFilteredActions don't work very well with changing the tab
|
||||
// order, because of the sheer amount of remove/adds. So, let's just
|
||||
// clear & rebuild the list when we change the set of tabs.
|
||||
//
|
||||
// Some callers might actually want smooth updating, like when the list
|
||||
// of tabs changes.
|
||||
if (clearList && _currentMode == CommandPaletteMode::TabSwitchMode)
|
||||
{
|
||||
_filteredActions.Clear();
|
||||
}
|
||||
_updateFilteredActions();
|
||||
void CommandPalette::SetTabs(Collections::IObservableVector<TabBase> const& tabs, Collections::IObservableVector<TabBase> const& mruTabs)
|
||||
{
|
||||
_bindTabs(tabs, _tabActions);
|
||||
_bindTabs(mruTabs, _mruTabActions);
|
||||
}
|
||||
|
||||
void CommandPalette::EnableCommandPaletteMode(CommandPaletteLaunchMode const launchMode)
|
||||
|
@ -888,26 +903,11 @@ namespace winrt::TerminalApp::implementation
|
|||
CommandPaletteMode::ActionMode;
|
||||
|
||||
_switchToMode(mode);
|
||||
_updateFilteredActions();
|
||||
}
|
||||
|
||||
void CommandPalette::_switchToMode(CommandPaletteMode mode)
|
||||
{
|
||||
// The smooth remove/add animations that happen during
|
||||
// UpdateFilteredActions don't work very well when switching between
|
||||
// modes because of the sheer amount of remove/adds. So, let's just
|
||||
// clear + append when switching between modes.
|
||||
if (mode != _currentMode)
|
||||
{
|
||||
_currentMode = mode;
|
||||
_filteredActions.Clear();
|
||||
auto commandsToFilter = _commandsToFilter();
|
||||
|
||||
for (auto action : commandsToFilter)
|
||||
{
|
||||
_filteredActions.Append(action);
|
||||
}
|
||||
}
|
||||
_currentMode = mode;
|
||||
|
||||
ParsedCommandLineText(L"");
|
||||
_searchBox().Text(L"");
|
||||
|
@ -940,6 +940,13 @@ namespace winrt::TerminalApp::implementation
|
|||
PrefixCharacter(L">");
|
||||
break;
|
||||
}
|
||||
|
||||
// The smooth remove/add animations that happen during
|
||||
// UpdateFilteredActions don't work very well when switching between
|
||||
// modes because of the sheer amount of remove/adds. So, let's just
|
||||
// clear + append when switching between modes.
|
||||
_filteredActions.Clear();
|
||||
_updateFilteredActions();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -956,27 +963,34 @@ namespace winrt::TerminalApp::implementation
|
|||
winrt::hstring searchText{ _getTrimmedInput() };
|
||||
|
||||
auto commandsToFilter = _commandsToFilter();
|
||||
for (const auto& action : commandsToFilter)
|
||||
{
|
||||
// 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);
|
||||
|
||||
// if there is active search we skip commands with 0 weight
|
||||
if (searchText.empty() || action.Weight() > 0)
|
||||
if (_currentMode == CommandPaletteMode::TabSwitchMode)
|
||||
{
|
||||
std::copy(begin(commandsToFilter), end(commandsToFilter), std::back_inserter(actions));
|
||||
}
|
||||
else if (_currentMode == CommandPaletteMode::TabSearchMode || _currentMode == CommandPaletteMode::ActionMode || _currentMode == CommandPaletteMode::CommandlineMode)
|
||||
{
|
||||
for (const auto& action : commandsToFilter)
|
||||
{
|
||||
actions.push_back(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);
|
||||
|
||||
// if there is active search we skip commands with 0 weight
|
||||
if (searchText.empty() || action.Weight() > 0)
|
||||
{
|
||||
actions.push_back(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We want to present the commands sorted,
|
||||
// unless we are in the TabSwitcherMode and TabSearchMode,
|
||||
// in which we want to preserve the original order (to be aligned with the tab view)
|
||||
if (_currentMode != CommandPaletteMode::TabSearchMode && _currentMode != CommandPaletteMode::TabSwitchMode && _currentMode != CommandPaletteMode::CommandlineMode)
|
||||
// We want to present the commands sorted
|
||||
if (_currentMode == CommandPaletteMode::ActionMode)
|
||||
{
|
||||
std::sort(actions.begin(), actions.end(), FilteredCommand::Compare);
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
@ -1051,20 +1065,18 @@ namespace winrt::TerminalApp::implementation
|
|||
_currentNestedCommands.Clear();
|
||||
}
|
||||
|
||||
void CommandPalette::EnableTabSwitcherMode(const bool searchMode, const uint32_t startIdx)
|
||||
void CommandPalette::EnableTabSwitcherMode(const uint32_t startIdx, TabSwitcherMode tabSwitcherMode)
|
||||
{
|
||||
_switcherStartIdx = startIdx;
|
||||
|
||||
if (searchMode)
|
||||
{
|
||||
_switchToMode(CommandPaletteMode::TabSearchMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
_switchToMode(CommandPaletteMode::TabSwitchMode);
|
||||
}
|
||||
|
||||
_updateFilteredActions();
|
||||
// The _switcherStartIdx field allows us to select the current tab
|
||||
// We need to take it into account only in the in-order mode,
|
||||
// as an MRU mode the current tab is on top by definition.
|
||||
_switcherStartIdx = tabSwitcherMode == TabSwitcherMode::InOrder ? startIdx : 0;
|
||||
_tabSwitcherMode = tabSwitcherMode;
|
||||
_switchToMode(CommandPaletteMode::TabSwitchMode);
|
||||
}
|
||||
|
||||
void CommandPalette::EnableTabSearchMode()
|
||||
{
|
||||
_switchToMode(CommandPaletteMode::TabSearchMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,11 +31,9 @@ namespace winrt::TerminalApp::implementation
|
|||
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::FilteredCommand> FilteredActions();
|
||||
|
||||
void SetCommands(Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::Command> const& actions);
|
||||
void SetTabs(Windows::Foundation::Collections::IVector<winrt::TerminalApp::TabBase> const& tabs, const bool clearList);
|
||||
void SetTabs(Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase> const& tabs, Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase> const& mruTabs);
|
||||
void SetKeyMap(const Microsoft::Terminal::Settings::Model::KeyMapping& keymap);
|
||||
|
||||
void EnableCommandPaletteMode(Microsoft::Terminal::Settings::Model::CommandPaletteLaunchMode const launchMode);
|
||||
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
void SelectNextItem(const bool moveDown);
|
||||
|
@ -45,8 +43,9 @@ namespace winrt::TerminalApp::implementation
|
|||
void ScrollToTop();
|
||||
void ScrollToBottom();
|
||||
|
||||
// Tab Switcher
|
||||
void EnableTabSwitcherMode(const bool searchMode, const uint32_t startIdx);
|
||||
void EnableCommandPaletteMode(Microsoft::Terminal::Settings::Model::CommandPaletteLaunchMode const launchMode);
|
||||
void EnableTabSwitcherMode(const uint32_t startIdx, Microsoft::Terminal::Settings::Model::TabSwitcherMode tabSwitcherMode);
|
||||
void EnableTabSearchMode();
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, NoMatchesText, _PropertyChangedHandlers);
|
||||
|
@ -112,7 +111,11 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
// Tab Switcher
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _tabActions{ nullptr };
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _mruTabActions{ nullptr };
|
||||
Microsoft::Terminal::Settings::Model::TabSwitcherMode _tabSwitcherMode;
|
||||
uint32_t _switcherStartIdx;
|
||||
|
||||
void _bindTabs(Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase> const& source, Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> const& target);
|
||||
void _anchorKeyUpHandler();
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::ListView::SizeChanged_revoker _sizeChangedRevoker;
|
||||
|
|
|
@ -22,13 +22,16 @@ namespace TerminalApp
|
|||
Windows.Foundation.Collections.IObservableVector<FilteredCommand> FilteredActions { get; };
|
||||
|
||||
void SetCommands(Windows.Foundation.Collections.IVector<Microsoft.Terminal.Settings.Model.Command> actions);
|
||||
void SetTabs(Windows.Foundation.Collections.IVector<TabBase> tabs, Boolean clearList);
|
||||
|
||||
void SetTabs(Windows.Foundation.Collections.IObservableVector<TabBase> tabs, Windows.Foundation.Collections.IObservableVector<TabBase> mruTabs);
|
||||
|
||||
void SetKeyMap(Microsoft.Terminal.Settings.Model.KeyMapping keymap);
|
||||
void EnableCommandPaletteMode(Microsoft.Terminal.Settings.Model.CommandPaletteLaunchMode launchMode);
|
||||
|
||||
void SelectNextItem(Boolean moveDown);
|
||||
|
||||
void EnableTabSwitcherMode(Boolean searchMode, UInt32 startIdx);
|
||||
void EnableCommandPaletteMode(Microsoft.Terminal.Settings.Model.CommandPaletteLaunchMode launchMode);
|
||||
void EnableTabSwitcherMode(UInt32 startIdx, Microsoft.Terminal.Settings.Model.TabSwitcherMode tabSwitcherMode);
|
||||
void EnableTabSearchMode();
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<CommandPalette, TabBase> SwitchToTabRequested;
|
||||
event Windows.Foundation.TypedEventHandler<CommandPalette, Microsoft.Terminal.Settings.Model.Command> DispatchCommandRequested;
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
TerminalPage::TerminalPage() :
|
||||
_tabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
|
||||
_mruTabs{ winrt::single_threaded_vector<TerminalApp::TabBase>() },
|
||||
_mruTabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
|
||||
_startupActions{ winrt::single_threaded_vector<ActionAndArgs>() },
|
||||
_hostingHwnd{}
|
||||
{
|
||||
|
@ -1323,49 +1323,27 @@ namespace winrt::TerminalApp::implementation
|
|||
// - Sets focus to the tab to the right or left the currently selected tab.
|
||||
void TerminalPage::_SelectNextTab(const bool bMoveRight)
|
||||
{
|
||||
const auto index{ _GetFocusedTabIndex().value_or(0) };
|
||||
const auto tabSwitchMode = _settings.GlobalSettings().TabSwitcherMode();
|
||||
const bool useInOrderTabIndex = tabSwitchMode != TabSwitcherMode::MostRecentlyUsed;
|
||||
|
||||
// First, determine what the index of the newly selected tab should be.
|
||||
// This changes if we're doing an in-order traversal vs a MRU traversal.
|
||||
auto newTabIndex = 0;
|
||||
if (useInOrderTabIndex)
|
||||
if (tabSwitchMode == TabSwitcherMode::Disabled)
|
||||
{
|
||||
// Determine what the next in-order tab index is
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
{
|
||||
uint32_t tabCount = _tabs.Size();
|
||||
// Wraparound math. By adding tabCount and then calculating
|
||||
// modulo tabCount, we clamp the values to the range [0,
|
||||
// tabCount) while still supporting moving leftward from 0 to
|
||||
// tabCount - 1.
|
||||
newTabIndex = ((tabCount + *index + (bMoveRight ? 1 : -1)) % tabCount);
|
||||
}
|
||||
uint32_t tabCount = _tabs.Size();
|
||||
// Wraparound math. By adding tabCount and then calculating
|
||||
// modulo tabCount, we clamp the values to the range [0,
|
||||
// tabCount) while still supporting moving leftward from 0 to
|
||||
// tabCount - 1.
|
||||
const auto newTabIndex = ((tabCount + index + (bMoveRight ? 1 : -1)) % tabCount);
|
||||
_SelectTab(newTabIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Determine what the next "most recently used" index is.
|
||||
// In this case, our focused tab index (in the MRU ordering) is
|
||||
// always 0. So, going next should go to index 1, and going prev
|
||||
// should wrap to the end.
|
||||
uint32_t tabCount = _mruTabs.Size();
|
||||
newTabIndex = ((tabCount + (bMoveRight ? 1 : -1)) % tabCount);
|
||||
}
|
||||
|
||||
const bool useTabSwitcher = tabSwitchMode != TabSwitcherMode::Disabled;
|
||||
|
||||
if (useTabSwitcher)
|
||||
{
|
||||
CommandPalette().SetTabs(useInOrderTabIndex ? _tabs : _mruTabs, true);
|
||||
CommandPalette().SetTabs(_tabs, _mruTabs);
|
||||
|
||||
// Otherwise, set up the tab switcher in the selected mode, with
|
||||
// the given ordering, and make it visible.
|
||||
CommandPalette().EnableTabSwitcherMode(false, newTabIndex);
|
||||
CommandPalette().EnableTabSwitcherMode(index, tabSwitchMode);
|
||||
CommandPalette().Visibility(Visibility::Visible);
|
||||
}
|
||||
else if (auto index{ _GetFocusedTabIndex() })
|
||||
{
|
||||
_SelectTab(newTabIndex);
|
||||
CommandPalette().SelectNextItem(bMoveRight);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ namespace winrt::TerminalApp::implementation
|
|||
Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<TerminalApp::TabBase> _tabs;
|
||||
Windows::Foundation::Collections::IVector<TerminalApp::TabBase> _mruTabs;
|
||||
Windows::Foundation::Collections::IObservableVector<TerminalApp::TabBase> _mruTabs;
|
||||
static winrt::com_ptr<TerminalTab> _GetTerminalTabImpl(const TerminalApp::TabBase& tab);
|
||||
|
||||
void _UpdateTabIndices();
|
||||
|
|
Loading…
Reference in a new issue