mirror of
https://github.com/microsoft/terminal.git
synced 2026-07-09 01:56:07 +00:00
218 lines
7.9 KiB
C++
218 lines
7.9 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "pch.h"
|
|
#include "SnippetsPaneContent.h"
|
|
#include "SnippetsPaneContent.g.cpp"
|
|
#include "FilteredTask.g.cpp"
|
|
#include "Utils.h"
|
|
|
|
using namespace winrt::Windows::Foundation;
|
|
using namespace winrt::Windows::System;
|
|
using namespace winrt::Microsoft::Terminal::Settings;
|
|
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
|
|
|
namespace winrt
|
|
{
|
|
namespace WUX = Windows::UI::Xaml;
|
|
namespace MUX = Microsoft::UI::Xaml;
|
|
using IInspectable = Windows::Foundation::IInspectable;
|
|
}
|
|
|
|
namespace winrt::TerminalApp::implementation
|
|
{
|
|
SnippetsPaneContent::SnippetsPaneContent() :
|
|
_allTasks{ winrt::single_threaded_observable_vector<TerminalApp::FilteredTask>() }
|
|
{
|
|
InitializeComponent();
|
|
|
|
WUX::Automation::AutomationProperties::SetName(*this, RS_(L"SnippetPaneTitle/Text"));
|
|
}
|
|
|
|
void SnippetsPaneContent::_updateFilteredCommands()
|
|
{
|
|
const auto& queryString = _filterBox().Text();
|
|
auto pattern = std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(queryString));
|
|
|
|
// DON'T replace the itemSource here. If you do, it'll un-expand all the
|
|
// nested items the user has expanded. Instead, just update the filter.
|
|
// That'll also trigger a PropertyChanged for the Visibility property.
|
|
for (const auto& t : _allTasks)
|
|
{
|
|
auto impl = winrt::get_self<implementation::FilteredTask>(t);
|
|
impl->UpdateFilter(pattern);
|
|
}
|
|
}
|
|
|
|
safe_void_coroutine SnippetsPaneContent::UpdateSettings(const CascadiaSettings& settings)
|
|
{
|
|
_settings = settings;
|
|
|
|
const auto dispatcher = Dispatcher();
|
|
const auto weak = get_weak();
|
|
|
|
// You'd think that `FilterToSendInput(queryString)` would work. It
|
|
// doesn't! That uses the queryString as the current command the user
|
|
// has typed, then relies on the suggestions UI to _also_ filter with that
|
|
// string.
|
|
|
|
const auto tasks = co_await _settings.GlobalSettings().ActionMap().FilterToSnippets(winrt::hstring{}, winrt::hstring{}); // IVector<Model::Command>
|
|
co_await wil::resume_foreground(dispatcher);
|
|
|
|
const auto strong = weak.get();
|
|
if (!strong)
|
|
{
|
|
co_return;
|
|
}
|
|
|
|
_allTasks.Clear();
|
|
for (const auto& t : tasks)
|
|
{
|
|
const auto& filtered{ winrt::make<FilteredTask>(t) };
|
|
_allTasks.Append(filtered);
|
|
}
|
|
_treeView().ItemsSource(_allTasks);
|
|
|
|
_updateFilteredCommands();
|
|
|
|
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"HasSnippets" });
|
|
}
|
|
|
|
bool SnippetsPaneContent::HasSnippets() const
|
|
{
|
|
return _allTasks.Size() != 0;
|
|
}
|
|
|
|
void SnippetsPaneContent::_filterTextChanged(const IInspectable& /*sender*/,
|
|
const Windows::UI::Xaml::RoutedEventArgs& /*args*/)
|
|
{
|
|
_updateFilteredCommands();
|
|
}
|
|
|
|
winrt::Windows::UI::Xaml::FrameworkElement SnippetsPaneContent::GetRoot()
|
|
{
|
|
return *this;
|
|
}
|
|
winrt::Windows::Foundation::Size SnippetsPaneContent::MinimumSize()
|
|
{
|
|
return { 200, 200 };
|
|
}
|
|
void SnippetsPaneContent::Focus(winrt::Windows::UI::Xaml::FocusState reason)
|
|
{
|
|
_filterBox().Focus(reason);
|
|
}
|
|
void SnippetsPaneContent::Close()
|
|
{
|
|
CloseRequested.raise(*this, nullptr);
|
|
}
|
|
|
|
INewContentArgs SnippetsPaneContent::GetNewTerminalArgs(BuildStartupKind /*kind*/) const
|
|
{
|
|
return BaseContentArgs(L"snippets");
|
|
}
|
|
|
|
winrt::hstring SnippetsPaneContent::Icon() const
|
|
{
|
|
static constexpr std::wstring_view glyph{ L"\xe70b" }; // QuickNote
|
|
return winrt::hstring{ glyph };
|
|
}
|
|
|
|
winrt::WUX::Media::Brush SnippetsPaneContent::BackgroundBrush()
|
|
{
|
|
static const auto key = winrt::box_value(L"SettingsUiTabBrush");
|
|
return ThemeLookup(WUX::Application::Current().Resources(),
|
|
_settings.GlobalSettings().CurrentTheme(_settings.WindowSettingsDefaults()).RequestedTheme(),
|
|
key)
|
|
.try_as<winrt::WUX::Media::Brush>();
|
|
}
|
|
|
|
void SnippetsPaneContent::SetLastActiveControl(const Microsoft::Terminal::Control::TermControl& control)
|
|
{
|
|
_control = control;
|
|
}
|
|
|
|
void SnippetsPaneContent::_runCommand(const Microsoft::Terminal::Settings::Model::Command& command)
|
|
{
|
|
if (const auto& strongControl{ _control.get() })
|
|
{
|
|
// By using the last active control as the sender here, the
|
|
// action dispatch will send this to the active control,
|
|
// thinking that it is the control that requested this event.
|
|
strongControl.Focus(winrt::WUX::FocusState::Programmatic);
|
|
DispatchCommandRequested.raise(strongControl, command);
|
|
}
|
|
}
|
|
|
|
void SnippetsPaneContent::_runCommandButtonClicked(const Windows::Foundation::IInspectable& sender,
|
|
const Windows::UI::Xaml::RoutedEventArgs&)
|
|
{
|
|
if (const auto& taskVM{ sender.try_as<WUX::Controls::Button>().DataContext().try_as<FilteredTask>() })
|
|
{
|
|
_runCommand(taskVM->Command());
|
|
}
|
|
}
|
|
void SnippetsPaneContent::_closePaneClick(const Windows::Foundation::IInspectable& /*sender*/,
|
|
const Windows::UI::Xaml::RoutedEventArgs&)
|
|
{
|
|
Close();
|
|
}
|
|
|
|
// Called when one of the items in the list is tapped, or enter/space is
|
|
// pressed on it while focused. Notably, this isn't the Tapped event - it
|
|
// isn't called when the user clicks the dropdown arrow (that does usually
|
|
// also trigger a Tapped).
|
|
//
|
|
// We'll use this to toggle the expanded state of nested items, since the
|
|
// tree view arrow is so little
|
|
void SnippetsPaneContent::_treeItemInvokedHandler(const IInspectable& /*sender*/,
|
|
const MUX::Controls::TreeViewItemInvokedEventArgs& e)
|
|
{
|
|
// The InvokedItem here is the item in the data collection that was
|
|
// bound itself.
|
|
if (const auto& taskVM{ e.InvokedItem().try_as<FilteredTask>() })
|
|
{
|
|
if (taskVM->HasChildren())
|
|
{
|
|
// We then need to find the actual TreeViewItem for that
|
|
// FilteredTask.
|
|
if (const auto& item{ _treeView().ContainerFromItem(*taskVM).try_as<MUX::Controls::TreeViewItem>() })
|
|
{
|
|
item.IsExpanded(!item.IsExpanded());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Raised on individual TreeViewItems. We'll use this event to send the
|
|
// input on an Enter/Space keypress, when a leaf item is selected.
|
|
void SnippetsPaneContent::_treeItemKeyUpHandler(const IInspectable& sender,
|
|
const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e)
|
|
{
|
|
const auto& item{ sender.try_as<MUX::Controls::TreeViewItem>() };
|
|
if (!item)
|
|
{
|
|
return;
|
|
}
|
|
const auto& taskVM{ item.DataContext().try_as<FilteredTask>() };
|
|
if (!taskVM || taskVM->HasChildren())
|
|
{
|
|
return;
|
|
}
|
|
|
|
const auto& key = e.OriginalKey();
|
|
if (key == VirtualKey::Enter || key == VirtualKey::Space)
|
|
{
|
|
if (const auto& button = e.OriginalSource().try_as<WUX::Controls::Button>())
|
|
{
|
|
// Let the button handle the Enter key so an eventually attached click handler will be called
|
|
e.Handled(false);
|
|
return;
|
|
}
|
|
|
|
_runCommand(taskVM->Command());
|
|
e.Handled(true);
|
|
}
|
|
}
|
|
|
|
}
|