mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Add a snippets pane (#17330)
This adds a snippets pane, which can be a static pane with all your snippets (`sendInput` actions) in it. (See #17329) This pane has a treeview with these actions in it, that we can filter with a textbox at the top. Play buttons next to entries make it quick to run the command you found. Bound in the default actions with ```json { "command": { "action": "splitPane", "type": "snippets" }, "id": "Terminal.OpenSnippetsPane", "name": { "key": "SnippetsPaneCommandName" } }, ``` re: #1595 ---- TODO, from 06-04 bug bash * [x] Snippets pane doesn't display some "no snippets found" text if there aren't any yet * [x] open snippets pane; find a "send input"; click the play button on it; input is sent to active pane; begin typing * [x] I can open an infinite amount of suggestions panes * ~I'm closing this as by-design for now at least. Nothing stopping anyone from opening infinite of any kind of pane.~ * ~This would require kind of a lot of refactoring in this PR to mark a kind of pane as being a singleton or singleton-per-tab~ * Okay everyone hates infinite suggestions panes, so I got rid of that * [x] Ctrl+Shift+W should still work in the snippets pane even if focus isn't in textbox * [ ] open snippets pane; click on text box; press TAB key; * [ ] If you press TAB again, I have no idea where focus went * [x] some previews don't work. Like `^c` (`"input": "\u0003"`) * [x] nested items just give you a bit of extra space for no reason and it looks a little awkward * [x] UI Suggestion: add padding on the right side * [ ] [Accessibility] Narrator says "Clear buffer; Suggestions found 132" when you open the snippets pane - Note: this is probably Narrator reading out the command palette (since that's where I opened it from) - We should probably expect something like "Snippets", then (assuming focus is thrown into text box) "Type to filter snippets" or something like that
This commit is contained in:
parent
ec9289288e
commit
02a7c02548
@ -21,11 +21,22 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// This class is a wrapper of PaletteItem, 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) :
|
||||
_Item(item),
|
||||
_Filter(L""),
|
||||
_Weight(0)
|
||||
FilteredCommand::FilteredCommand(const winrt::TerminalApp::PaletteItem& item)
|
||||
{
|
||||
// Actually implement the ctor in _constructFilteredCommand
|
||||
_constructFilteredCommand(item);
|
||||
}
|
||||
|
||||
// We need to actually implement the ctor in a separate helper. This is
|
||||
// because we have a FilteredTask class which derives from FilteredCommand.
|
||||
// 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)
|
||||
{
|
||||
_Item = item;
|
||||
_Filter = L"";
|
||||
_Weight = 0;
|
||||
_HighlightedName = _computeHighlightedName();
|
||||
|
||||
// Recompute the highlighted name if the item name changes
|
||||
|
||||
@ -19,7 +19,7 @@ namespace winrt::TerminalApp::implementation
|
||||
FilteredCommand() = default;
|
||||
FilteredCommand(const winrt::TerminalApp::PaletteItem& item);
|
||||
|
||||
void UpdateFilter(const winrt::hstring& filter);
|
||||
virtual void UpdateFilter(const winrt::hstring& filter);
|
||||
|
||||
static int Compare(const winrt::TerminalApp::FilteredCommand& first, const winrt::TerminalApp::FilteredCommand& second);
|
||||
|
||||
@ -29,6 +29,9 @@ 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();
|
||||
|
||||
@ -6,7 +6,7 @@ import "HighlightedTextControl.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass FilteredCommand : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
[default_interface] unsealed runtimeclass FilteredCommand : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
FilteredCommand();
|
||||
FilteredCommand(PaletteItem item);
|
||||
|
||||
@ -2944,7 +2944,8 @@ void Pane::FinalizeConfigurationGivenDefault()
|
||||
// - Returns true if the pane or one of its descendants is read-only
|
||||
bool Pane::ContainsReadOnly() const
|
||||
{
|
||||
return _IsLeaf() ? _content.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
|
||||
return _IsLeaf() ? (_content == nullptr ? false : _content.ReadOnly()) :
|
||||
(_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@ -907,6 +907,28 @@
|
||||
<data name="RestartConnectionToolTip" xml:space="preserve">
|
||||
<value>Restart the active pane connection</value>
|
||||
</data>
|
||||
<data name="SnippetPaneTitle.Text" xml:space="preserve">
|
||||
<value>Snippets</value>
|
||||
<comment>Header for a page that includes small "snippets" of text for the user to enter</comment>
|
||||
</data>
|
||||
<data name="SnippetsFilterBox.PlaceholderText" xml:space="preserve">
|
||||
<value>Filter snippets...</value>
|
||||
<comment>Placeholder text for a text box to filter snippets (on the same page as the 'SnippetPaneTitle')</comment>
|
||||
</data>
|
||||
<data name="SnippetPlayButton.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Input this command</value>
|
||||
</data>
|
||||
<data name="SnippetPlayButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Input this command</value>
|
||||
</data>
|
||||
<data name="SnippetsPaneNoneFoundHeader.Text" xml:space="preserve">
|
||||
<value>No snippets found in your settings.</value>
|
||||
<comment>Text shown to user when no snippets are found in their settings</comment>
|
||||
</data>
|
||||
<data name="SnippetsPaneNoneFoundDetails.Text" xml:space="preserve">
|
||||
<value>Add some "Send input" actions in your settings to have them show up here.</value>
|
||||
<comment>Additional information presented to the user to let them know they can add a "Send input" action in their setting to populate the snippets pane</comment>
|
||||
</data>
|
||||
<data name="ActionSavedToast.Title" xml:space="preserve">
|
||||
<value>Action saved</value>
|
||||
</data>
|
||||
|
||||
199
src/cascadia/TerminalApp/SnippetsPaneContent.cpp
Normal file
199
src/cascadia/TerminalApp/SnippetsPaneContent.cpp
Normal file
@ -0,0 +1,199 @@
|
||||
// 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()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
WUX::Automation::AutomationProperties::SetName(*this, RS_(L"SnippetPaneTitle/Text"));
|
||||
}
|
||||
|
||||
void SnippetsPaneContent::_updateFilteredCommands()
|
||||
{
|
||||
const auto& queryString = _filterBox().Text();
|
||||
|
||||
// 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(queryString);
|
||||
}
|
||||
}
|
||||
|
||||
void SnippetsPaneContent::UpdateSettings(const CascadiaSettings& settings)
|
||||
{
|
||||
_settings = settings;
|
||||
|
||||
// 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 = _settings.GlobalSettings().ActionMap().FilterToSendInput(winrt::hstring{}); // IVector<Model::Command>
|
||||
_allTasks = winrt::single_threaded_observable_vector<TerminalApp::FilteredTask>();
|
||||
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"UnfocusedBorderBrush");
|
||||
return ThemeLookup(WUX::Application::Current().Resources(),
|
||||
_settings.GlobalSettings().CurrentTheme().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());
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
154
src/cascadia/TerminalApp/SnippetsPaneContent.h
Normal file
154
src/cascadia/TerminalApp/SnippetsPaneContent.h
Normal file
@ -0,0 +1,154 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
#include "SnippetsPaneContent.g.h"
|
||||
#include "FilteredTask.g.h"
|
||||
#include "FilteredCommand.h"
|
||||
#include "ActionPaletteItem.h"
|
||||
#include <LibraryResources.h>
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct SnippetsPaneContent : SnippetsPaneContentT<SnippetsPaneContent>
|
||||
{
|
||||
SnippetsPaneContent();
|
||||
|
||||
winrt::Windows::UI::Xaml::FrameworkElement GetRoot();
|
||||
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
|
||||
|
||||
winrt::Windows::Foundation::Size MinimumSize();
|
||||
void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic);
|
||||
void Close();
|
||||
winrt::Microsoft::Terminal::Settings::Model::INewContentArgs GetNewTerminalArgs(BuildStartupKind kind) const;
|
||||
|
||||
winrt::hstring Title() { return RS_(L"SnippetPaneTitle/Text"); }
|
||||
uint64_t TaskbarState() { return 0; }
|
||||
uint64_t TaskbarProgress() { return 0; }
|
||||
bool ReadOnly() { return false; }
|
||||
winrt::hstring Icon() const;
|
||||
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() const noexcept { return nullptr; }
|
||||
winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush();
|
||||
|
||||
void SetLastActiveControl(const Microsoft::Terminal::Control::TermControl& control);
|
||||
bool HasSnippets() const;
|
||||
|
||||
til::typed_event<> ConnectionStateChanged;
|
||||
til::typed_event<IPaneContent> CloseRequested;
|
||||
til::typed_event<IPaneContent, winrt::TerminalApp::BellEventArgs> BellRequested;
|
||||
til::typed_event<IPaneContent> TitleChanged;
|
||||
til::typed_event<IPaneContent> TabColorChanged;
|
||||
til::typed_event<IPaneContent> TaskbarProgressChanged;
|
||||
til::typed_event<IPaneContent> ReadOnlyChanged;
|
||||
til::typed_event<IPaneContent> FocusRequested;
|
||||
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::Command> DispatchCommandRequested;
|
||||
|
||||
til::property_changed_event PropertyChanged;
|
||||
|
||||
private:
|
||||
friend struct SnippetsPaneContentT<SnippetsPaneContent>; // for Xaml to bind events
|
||||
|
||||
winrt::weak_ref<Microsoft::Terminal::Control::TermControl> _control{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<TerminalApp::FilteredTask> _allTasks{ nullptr };
|
||||
|
||||
void _runCommandButtonClicked(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs&);
|
||||
void _filterTextChanged(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
|
||||
void _updateFilteredCommands();
|
||||
void _treeItemInvokedHandler(const Windows::Foundation::IInspectable& sender, const Microsoft::UI::Xaml::Controls::TreeViewItemInvokedEventArgs& e);
|
||||
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(sendInput.Input().c_str()) };
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
BASIC_FACTORY(SnippetsPaneContent);
|
||||
}
|
||||
261
src/cascadia/TerminalApp/SnippetsPaneContent.xaml
Normal file
261
src/cascadia/TerminalApp/SnippetsPaneContent.xaml
Normal file
@ -0,0 +1,261 @@
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information.
|
||||
-->
|
||||
<UserControl x:Class="TerminalApp.SnippetsPaneContent"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:SettingsModel="using:Microsoft.Terminal.Settings.Model"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:Microsoft.Terminal.Settings.Model"
|
||||
xmlns:mtu="using:Microsoft.Terminal.UI"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
AutomationProperties.LocalizedControlType="pane"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
|
||||
<Style x:Key="PlayButtonTemplate"
|
||||
TargetType="Button">
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="Padding" Value="4" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="ButtonBaseElement"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Background="{TemplateBinding Background}"
|
||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<Viewbox Width="14"
|
||||
Height="14">
|
||||
<Grid>
|
||||
<FontIcon x:Name="ButtonBackgroundIcon"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
Foreground="{ThemeResource PlayButtonHoveredColor}"
|
||||
Glyph=""
|
||||
Visibility="Collapsed" />
|
||||
<FontIcon x:Name="ButtonOutlineIcon"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
Foreground="{ThemeResource PlayButtonNormalColor}"
|
||||
Glyph="" />
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
|
||||
<VisualState x:Name="Normal">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Disabled" />
|
||||
</VisualStateGroup>
|
||||
|
||||
<VisualStateGroup x:Name="PlayButtonStates">
|
||||
<VisualState x:Name="Ready">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Glyph" Value="" />
|
||||
<Setter Target="ButtonOutlineIcon.Glyph" Value="" />
|
||||
<Setter Target="StatusProgress.IsActive" Value="False" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
</Style>
|
||||
|
||||
<DataTemplate x:Key="TaskItemTemplate"
|
||||
x:DataType="local:FilteredTask">
|
||||
<mux:TreeViewItem x:Name="rootItem"
|
||||
AutomationProperties.HelpText="{x:Bind Input, Mode=OneWay}"
|
||||
AutomationProperties.Name="{x:Bind FilteredCommand.Item.Name, Mode=OneWay}"
|
||||
ItemsSource="{x:Bind Children, Mode=OneWay}"
|
||||
KeyUp="_treeItemKeyUpHandler"
|
||||
Visibility="{x:Bind Visibility, Mode=OneWay}">
|
||||
<Grid AutomationProperties.AccessibilityView="Raw">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<!-- Name -->
|
||||
<RowDefinition Height="*" />
|
||||
<!-- Input -->
|
||||
<RowDefinition Height="0" />
|
||||
<!-- Input gets put here when we're a nested command, to hide it -->
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
|
||||
<Button x:Uid="SnippetPlayButton"
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="1"
|
||||
Grid.Column="0"
|
||||
Margin="-28,0,0,0"
|
||||
Padding="3"
|
||||
VerticalAlignment="Bottom"
|
||||
Background="Transparent"
|
||||
BorderBrush="Transparent"
|
||||
Click="_runCommandButtonClicked"
|
||||
Style="{StaticResource PlayButtonTemplate}"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(HasChildren), Mode=OneWay}">
|
||||
|
||||
<Button.Content>
|
||||
<FontIcon FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="12"
|
||||
Glyph="" />
|
||||
<!--
|
||||
xE768 is Play, which is just an outline.
|
||||
xF5B0 is PlaySolid, also a good option. Seemed
|
||||
better to have a lightweight outline though
|
||||
-->
|
||||
</Button.Content>
|
||||
|
||||
<Button.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
|
||||
Color="{StaticResource SystemAccentColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed"
|
||||
Color="{StaticResource SystemAccentColor}" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
|
||||
Color="{StaticResource SystemAccentColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed"
|
||||
Color="{StaticResource SystemAccentColor}" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<SolidColorBrush x:Key="ButtonBackground"
|
||||
Color="{ThemeResource SystemColorButtonFaceColor}" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="ButtonBackgroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForeground"
|
||||
Color="{ThemeResource SystemColorButtonTextColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
</Button>
|
||||
|
||||
<local:HighlightedTextControl Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
IsTabStop="False"
|
||||
Text="{x:Bind FilteredCommand.HighlightedName, Mode=OneWay}" />
|
||||
|
||||
<!--
|
||||
BODGY: I can't choose different templates if this item is nested or not.
|
||||
(See https://github.com/microsoft/microsoft-ui-xaml/issues/2121)
|
||||
But what I can do, is toss the text into a 0-height row to hide it.
|
||||
-->
|
||||
<TextBlock Grid.Row="{x:Bind Row, Mode=OneWay}"
|
||||
Grid.Column="1"
|
||||
Margin="12,0,12,6"
|
||||
FontFamily="Cascadia Mono, Consolas"
|
||||
IsTextSelectionEnabled="False"
|
||||
Style="{ThemeResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind Input}"
|
||||
Visibility="{Binding ElementName=rootItem, Path=IsSelected}" />
|
||||
</Grid>
|
||||
</mux:TreeViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<!-- same as in MainPage, this is SolidBackgroundFillColorTertiary -->
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<Color x:Key="PageBackground">#282828</Color>
|
||||
<Color x:Key="PlayButtonHoveredColor">#90ef90</Color>
|
||||
<Color x:Key="PlayButtonNormalColor">#8888</Color>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<Color x:Key="PageBackground">#F9F9F9</Color>
|
||||
<Color x:Key="PlayButtonHoveredColor">#257f01</Color>
|
||||
<Color x:Key="PlayButtonNormalColor">#88222222</Color>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<!-- Define resources for HighContrast mode here -->
|
||||
<StaticResource x:Key="PageBackground"
|
||||
ResourceKey="SystemColorWindowColorBrush" />
|
||||
</ResourceDictionary>
|
||||
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<!-- Don't allow the user to focus the root pane, but do allow individual controls to be focused -->
|
||||
<!-- TabFocusNavigation="Cycle" is load-bearing: otherwise, tab focus disappears to nowhere off the play button -->
|
||||
<Grid AllowFocusOnInteraction="False"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Background="{ThemeResource PageBackground}"
|
||||
TabFocusNavigation="Cycle">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock x:Name="_title"
|
||||
x:Uid="SnippetPaneTitle"
|
||||
Grid.Row="0"
|
||||
Margin="4"
|
||||
FontSize="24" />
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Margin="8,16,8,8"
|
||||
TextWrapping="WrapWholeWords"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(HasSnippets), Mode=OneWay}">
|
||||
<Run x:Uid="SnippetsPaneNoneFoundHeader" />
|
||||
<LineBreak />
|
||||
<Run x:Uid="SnippetsPaneNoneFoundDetails" />
|
||||
</TextBlock>
|
||||
|
||||
<TextBox x:Name="_filterBox"
|
||||
x:Uid="SnippetsFilterBox"
|
||||
Grid.Row="1"
|
||||
Margin="8,0,8,8"
|
||||
AllowFocusOnInteraction="True"
|
||||
TextChanged="_filterTextChanged"
|
||||
Visibility="{x:Bind HasSnippets, Mode=OneWay}" />
|
||||
|
||||
<mux:TreeView x:Name="_treeView"
|
||||
Grid.Row="2"
|
||||
AllowFocusOnInteraction="True"
|
||||
CanDragItems="False"
|
||||
CanReorderItems="False"
|
||||
ItemInvoked="_treeItemInvokedHandler"
|
||||
ItemTemplate="{StaticResource TaskItemTemplate}"
|
||||
Visibility="{x:Bind HasSnippets, Mode=OneWay}" />
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@ -71,6 +71,9 @@
|
||||
<Page Include="SuggestionsControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="SnippetsPaneContent.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
@ -161,6 +164,9 @@
|
||||
<ClInclude Include="ScratchpadContent.h">
|
||||
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SnippetsPaneContent.h">
|
||||
<DependentUpon>SnippetsPaneContent.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingsPaneContent.h">
|
||||
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
@ -274,6 +280,9 @@
|
||||
<ClCompile Include="ScratchpadContent.cpp">
|
||||
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SnippetsPaneContent.cpp">
|
||||
<DependentUpon>SnippetsPaneContent.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SettingsPaneContent.cpp">
|
||||
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
@ -352,7 +361,10 @@
|
||||
</Midl>
|
||||
<Midl Include="FilteredCommand.idl" />
|
||||
<Midl Include="IPaneContent.idl" />
|
||||
<Midl Include="TerminalPaneContent.idl" />
|
||||
<Midl Include="TerminalPaneContent.idl" >
|
||||
<DependentUpon>TaskPaneContent.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="TerminalSettingsCache.idl" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Misc Files ======================== -->
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include "DebugTapConnection.h"
|
||||
#include "SettingsPaneContent.h"
|
||||
#include "ScratchpadContent.h"
|
||||
#include "SnippetsPaneContent.h"
|
||||
#include "TabRowControl.h"
|
||||
|
||||
#include "TerminalPage.g.cpp"
|
||||
@ -451,10 +452,10 @@ namespace winrt::TerminalApp::implementation
|
||||
// - command - command to dispatch
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_OnDispatchCommandRequested(const IInspectable& /*sender*/, const Microsoft::Terminal::Settings::Model::Command& command)
|
||||
void TerminalPage::_OnDispatchCommandRequested(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::Command& command)
|
||||
{
|
||||
const auto& actionAndArgs = command.ActionAndArgs();
|
||||
_actionDispatch->DoAction(actionAndArgs);
|
||||
_actionDispatch->DoAction(sender, actionAndArgs);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -620,9 +621,12 @@ namespace winrt::TerminalApp::implementation
|
||||
// GH#6586: now that we're done processing all startup commands,
|
||||
// focus the active control. This will work as expected for both
|
||||
// commandline invocations and for `wt` action invocations.
|
||||
if (const auto control = _GetActiveControl())
|
||||
if (const auto& terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
control.Focus(FocusState::Programmatic);
|
||||
if (const auto& content{ terminalTab->GetActiveContent() })
|
||||
{
|
||||
content.Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (initial)
|
||||
@ -2466,16 +2470,16 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
_UnZoomIfNeeded();
|
||||
auto [original, _] = activeTab->SplitPane(*realSplitType, splitSize, newPane);
|
||||
auto [original, newGuy] = activeTab->SplitPane(*realSplitType, splitSize, newPane);
|
||||
|
||||
// After GH#6586, the control will no longer focus itself
|
||||
// automatically when it's finished being laid out. Manually focus
|
||||
// the control here instead.
|
||||
if (_startupState == StartupState::Initialized)
|
||||
{
|
||||
if (const auto control = _GetActiveControl())
|
||||
if (const auto& content{ newGuy->GetContent() })
|
||||
{
|
||||
control.Focus(FocusState::Programmatic);
|
||||
content.Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3270,6 +3274,8 @@ namespace winrt::TerminalApp::implementation
|
||||
return resultPane;
|
||||
}
|
||||
|
||||
// NOTE: callers of _MakePane should be able to accept nullptr as a return
|
||||
// value gracefully.
|
||||
std::shared_ptr<Pane> TerminalPage::_MakePane(const INewContentArgs& contentArgs,
|
||||
const winrt::TerminalApp::TabBase& sourceTab,
|
||||
TerminalConnection::ITerminalConnection existingConnection)
|
||||
@ -3300,6 +3306,36 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
content = _makeSettingsContent();
|
||||
}
|
||||
else if (paneType == L"snippets")
|
||||
{
|
||||
// Prevent the user from opening a bunch of snippets panes.
|
||||
//
|
||||
// Look at the focused tab, and if it already has one, then just focus it.
|
||||
const bool found = _GetFocusedTab().try_as<TerminalTab>()->GetRootPane()->WalkTree([](const auto& p) -> bool {
|
||||
if (const auto& snippets{ p->GetContent().try_as<SnippetsPaneContent>() })
|
||||
{
|
||||
snippets->Focus(FocusState::Programmatic);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
// Bail out if we already found one.
|
||||
if (found)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto& tasksContent{ winrt::make_self<SnippetsPaneContent>() };
|
||||
tasksContent->UpdateSettings(_settings);
|
||||
tasksContent->GetRoot().KeyDown({ this, &TerminalPage::_KeyDownHandler });
|
||||
tasksContent->DispatchCommandRequested({ this, &TerminalPage::_OnDispatchCommandRequested });
|
||||
if (const auto& termControl{ _GetActiveControl() })
|
||||
{
|
||||
tasksContent->SetLastActiveControl(termControl);
|
||||
}
|
||||
|
||||
content = *tasksContent;
|
||||
}
|
||||
|
||||
assert(content);
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
import "IPaneContent.idl";
|
||||
import "TerminalSettingsCache.idl";
|
||||
import "FilteredCommand.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
@ -16,4 +17,22 @@ 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();
|
||||
void SetLastActiveControl(Microsoft.Terminal.Control.TermControl control);
|
||||
Boolean HasSnippets { get; };
|
||||
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Settings.Model.Command> DispatchCommandRequested;
|
||||
}
|
||||
}
|
||||
|
||||
@ -525,7 +525,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// - pane: The new pane to add to the tree of panes; note that this pane
|
||||
// could itself be a parent pane/the root node of a tree of panes
|
||||
// Return Value:
|
||||
// - <none>
|
||||
// - a pair of (the Pane that now holds the original content, the new Pane in the tree)
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> TerminalTab::SplitPane(SplitDirection splitType,
|
||||
const float splitSize,
|
||||
std::shared_ptr<Pane> pane)
|
||||
@ -1223,6 +1223,20 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// Raise our own ActivePaneChanged event.
|
||||
ActivePaneChanged.raise(*this, nullptr);
|
||||
|
||||
// If the new active pane is a terminal, tell other interested panes
|
||||
// what the new active pane is.
|
||||
const auto content{ pane->GetContent() };
|
||||
if (const auto termContent{ content.try_as<winrt::TerminalApp::TerminalPaneContent>() })
|
||||
{
|
||||
const auto& termControl{ termContent.GetTermControl() };
|
||||
_rootPane->WalkTree([termControl](const auto& p) {
|
||||
if (const auto& taskPane{ p->GetContent().try_as<SnippetsPaneContent>() })
|
||||
{
|
||||
taskPane.SetLastActiveControl(termControl);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@ -126,6 +126,10 @@
|
||||
<data name="SplitPaneParentCommandName" xml:space="preserve">
|
||||
<value>Split pane</value>
|
||||
</data>
|
||||
<data name="SnippetsPaneCommandName" xml:space="preserve">
|
||||
<value>Open snippets pane</value>
|
||||
<comment>This will open a pane with a list of the users's saved commands ("snippets") in it</comment>
|
||||
</data>
|
||||
<data name="ApplicationDisplayNamePortable" xml:space="preserve">
|
||||
<value>Terminal (Portable)</value>
|
||||
<comment>This display name is used when the Terminal application is running in a "portable" mode, where settings are not stored in a shared location.</comment>
|
||||
|
||||
@ -446,6 +446,7 @@
|
||||
{ "command": "quit", "id": "Terminal.Quit" },
|
||||
{ "command": "restoreLastClosed", "id": "Terminal.RestoreLastClosed" },
|
||||
{ "command": "openAbout", "id": "Terminal.OpenAboutDialog" },
|
||||
{ "command": "experimental.openTasks", "id": "Terminal.OpenTasks" },
|
||||
|
||||
// Tab Management
|
||||
// "command": "closeTab" is unbound by default.
|
||||
@ -528,6 +529,7 @@
|
||||
{ "command": { "action": "movePane", "index": 8 }, "id": "Terminal.MovePaneToTab8" },
|
||||
{ "command": { "action": "movePane", "window": "new" }, "id": "Terminal.MovePaneToNewWindow" },
|
||||
{ "command": "restartConnection", "id": "Terminal.RestartConnection" },
|
||||
{ "command": { "action": "splitPane", "type": "snippets" }, "id": "Terminal.OpenSnippetsPane", "name": { "key": "SnippetsPaneCommandName" } },
|
||||
|
||||
// Clipboard Integration
|
||||
{ "command": { "action": "copy", "singleLine": false }, "id": "Terminal.CopyToClipboard" },
|
||||
|
||||
@ -133,7 +133,7 @@ public: \
|
||||
_##name = value; \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
protected: \
|
||||
type _##name{ __VA_ARGS__ };
|
||||
|
||||
// Use this macro to quickly implement both the getter and setter for an
|
||||
@ -158,7 +158,7 @@ public:
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
private: \
|
||||
protected: \
|
||||
type _##name{ __VA_ARGS__ }; \
|
||||
void _set##name(const type& value) \
|
||||
{ \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user