mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-19 18:11:39 -05:00
Add ability to save input action from command line (#16513)
Hi wanted to make an attempt at
[12857](https://github.com/microsoft/terminal/issues/12857). This still
needs work but I think the initial version is ready to be reviewed.
## Summary of the Pull Request
Mostly copied from:
6f5b9fb...1cde67ac46
- Save to disk
- If command line is empty use selection
- Show toast
- No UI. Trying out the different options now.
## PR Checklist
- [ ] Closes #12857
- [ ] Tests added/passed
- [ ] Documentation updated
- If checked, please file a pull request on [our docs
repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
- [ ] Schema updated (if necessary)
---------
Co-authored-by: Mike Griese <migrie@microsoft.com>
This commit is contained in:
@@ -1264,6 +1264,113 @@ namespace winrt::TerminalApp::implementation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalPage::_HandleSaveSnippet(const IInspectable& /*sender*/,
|
||||||
|
const ActionEventArgs& args)
|
||||||
|
{
|
||||||
|
if constexpr (!Feature_SaveSnippet::IsEnabled())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args)
|
||||||
|
{
|
||||||
|
if (const auto& realArgs = args.ActionArgs().try_as<SaveSnippetArgs>())
|
||||||
|
{
|
||||||
|
auto commandLine = realArgs.Commandline();
|
||||||
|
if (commandLine.empty())
|
||||||
|
{
|
||||||
|
if (const auto termControl{ _GetActiveControl() })
|
||||||
|
{
|
||||||
|
if (termControl.HasSelection())
|
||||||
|
{
|
||||||
|
const auto selections{ termControl.SelectedText(true) };
|
||||||
|
const auto selection = std::accumulate(selections.begin(), selections.end(), std::wstring());
|
||||||
|
commandLine = selection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commandLine.empty())
|
||||||
|
{
|
||||||
|
ActionSaveFailed(L"CommandLine is Required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
KeyChord keyChord = nullptr;
|
||||||
|
if (!realArgs.KeyChord().empty())
|
||||||
|
{
|
||||||
|
keyChord = KeyChordSerialization::FromString(winrt::to_hstring(realArgs.KeyChord()));
|
||||||
|
}
|
||||||
|
_settings.GlobalSettings().ActionMap().AddSendInputAction(realArgs.Name(), commandLine, keyChord);
|
||||||
|
_settings.WriteSettingsToDisk();
|
||||||
|
ActionSaved(commandLine, realArgs.Name(), realArgs.KeyChord());
|
||||||
|
}
|
||||||
|
catch (const winrt::hresult_error& ex)
|
||||||
|
{
|
||||||
|
auto code = ex.code();
|
||||||
|
auto message = ex.message();
|
||||||
|
ActionSaveFailed(message);
|
||||||
|
args.Handled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.Handled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalPage::ActionSaved(winrt::hstring input, winrt::hstring name, winrt::hstring keyChord)
|
||||||
|
{
|
||||||
|
// If we haven't ever loaded the TeachingTip, then do so now and
|
||||||
|
// create the toast for it.
|
||||||
|
if (_actionSavedToast == nullptr)
|
||||||
|
{
|
||||||
|
if (auto tip{ FindName(L"ActionSavedToast").try_as<MUX::Controls::TeachingTip>() })
|
||||||
|
{
|
||||||
|
_actionSavedToast = std::make_shared<Toast>(tip);
|
||||||
|
// Make sure to use the weak ref when setting up this
|
||||||
|
// callback.
|
||||||
|
tip.Closed({ get_weak(), &TerminalPage::_FocusActiveControl });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_UpdateTeachingTipTheme(ActionSavedToast().try_as<winrt::Windows::UI::Xaml::FrameworkElement>());
|
||||||
|
|
||||||
|
SavedActionName(name);
|
||||||
|
SavedActionKeyChord(keyChord);
|
||||||
|
SavedActionCommandLine(input);
|
||||||
|
|
||||||
|
if (_actionSavedToast != nullptr)
|
||||||
|
{
|
||||||
|
_actionSavedToast->Open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalPage::ActionSaveFailed(winrt::hstring message)
|
||||||
|
{
|
||||||
|
// If we haven't ever loaded the TeachingTip, then do so now and
|
||||||
|
// create the toast for it.
|
||||||
|
if (_actionSaveFailedToast == nullptr)
|
||||||
|
{
|
||||||
|
if (auto tip{ FindName(L"ActionSaveFailedToast").try_as<MUX::Controls::TeachingTip>() })
|
||||||
|
{
|
||||||
|
_actionSaveFailedToast = std::make_shared<Toast>(tip);
|
||||||
|
// Make sure to use the weak ref when setting up this
|
||||||
|
// callback.
|
||||||
|
tip.Closed({ get_weak(), &TerminalPage::_FocusActiveControl });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_UpdateTeachingTipTheme(ActionSaveFailedToast().try_as<winrt::Windows::UI::Xaml::FrameworkElement>());
|
||||||
|
|
||||||
|
ActionSaveFailedMessage().Text(message);
|
||||||
|
|
||||||
|
if (_actionSaveFailedToast != nullptr)
|
||||||
|
{
|
||||||
|
_actionSaveFailedToast->Open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TerminalPage::_HandleSelectCommand(const IInspectable& /*sender*/,
|
void TerminalPage::_HandleSelectCommand(const IInspectable& /*sender*/,
|
||||||
const ActionEventArgs& args)
|
const ActionEventArgs& args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ void AppCommandlineArgs::_buildParser()
|
|||||||
_buildMovePaneParser();
|
_buildMovePaneParser();
|
||||||
_buildSwapPaneParser();
|
_buildSwapPaneParser();
|
||||||
_buildFocusPaneParser();
|
_buildFocusPaneParser();
|
||||||
|
_buildSaveSnippetParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
@@ -537,6 +538,72 @@ void AppCommandlineArgs::_buildFocusPaneParser()
|
|||||||
setupSubcommand(_focusPaneShort);
|
setupSubcommand(_focusPaneShort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppCommandlineArgs::_buildSaveSnippetParser()
|
||||||
|
{
|
||||||
|
_saveCommand = _app.add_subcommand("x-save-snippet", RS_A(L"SaveSnippetDesc"));
|
||||||
|
|
||||||
|
auto setupSubcommand = [this](auto* subcommand) {
|
||||||
|
subcommand->add_option("--name,-n", _saveInputName, RS_A(L"SaveSnippetArgDesc"));
|
||||||
|
subcommand->add_option("--keychord,-k", _keyChordOption, RS_A(L"KeyChordArgDesc"));
|
||||||
|
subcommand->add_option("command,", _commandline, RS_A(L"CmdCommandArgDesc"));
|
||||||
|
subcommand->positionals_at_end(true);
|
||||||
|
|
||||||
|
// When ParseCommand is called, if this subcommand was provided, this
|
||||||
|
// callback function will be triggered on the same thread. We can be sure
|
||||||
|
// that `this` will still be safe - this function just lets us know this
|
||||||
|
// command was parsed.
|
||||||
|
subcommand->callback([&, this]() {
|
||||||
|
// Build the action from the values we've parsed on the commandline.
|
||||||
|
ActionAndArgs saveSnippet{};
|
||||||
|
saveSnippet.Action(ShortcutAction::SaveSnippet);
|
||||||
|
// First, parse out the commandline in the same way that
|
||||||
|
// _getNewTerminalArgs does it
|
||||||
|
SaveSnippetArgs args{};
|
||||||
|
|
||||||
|
if (!_commandline.empty())
|
||||||
|
{
|
||||||
|
std::ostringstream cmdlineBuffer;
|
||||||
|
|
||||||
|
for (const auto& arg : _commandline)
|
||||||
|
{
|
||||||
|
if (cmdlineBuffer.tellp() != 0)
|
||||||
|
{
|
||||||
|
// If there's already something in here, prepend a space
|
||||||
|
cmdlineBuffer << ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg.find(" ") != std::string::npos)
|
||||||
|
{
|
||||||
|
cmdlineBuffer << '"' << arg << '"';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmdlineBuffer << arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args.Commandline(winrt::to_hstring(cmdlineBuffer.str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_keyChordOption.empty())
|
||||||
|
{
|
||||||
|
args.KeyChord(winrt::to_hstring(_keyChordOption));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_saveInputName.empty())
|
||||||
|
{
|
||||||
|
winrt::hstring hString = winrt::to_hstring(_saveInputName);
|
||||||
|
args.Name(hString);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveSnippet.Args(args);
|
||||||
|
_startupActions.push_back(saveSnippet);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
setupSubcommand(_saveCommand);
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Add the `NewTerminalArgs` parameters to the given subcommand. This enables
|
// - Add the `NewTerminalArgs` parameters to the given subcommand. This enables
|
||||||
// that subcommand to support all the properties in a NewTerminalArgs.
|
// that subcommand to support all the properties in a NewTerminalArgs.
|
||||||
@@ -710,7 +777,8 @@ bool AppCommandlineArgs::_noCommandsProvided()
|
|||||||
*_focusPaneCommand ||
|
*_focusPaneCommand ||
|
||||||
*_focusPaneShort ||
|
*_focusPaneShort ||
|
||||||
*_newPaneShort.subcommand ||
|
*_newPaneShort.subcommand ||
|
||||||
*_newPaneCommand.subcommand);
|
*_newPaneCommand.subcommand ||
|
||||||
|
*_saveCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ private:
|
|||||||
CLI::App* _swapPaneCommand;
|
CLI::App* _swapPaneCommand;
|
||||||
CLI::App* _focusPaneCommand;
|
CLI::App* _focusPaneCommand;
|
||||||
CLI::App* _focusPaneShort;
|
CLI::App* _focusPaneShort;
|
||||||
|
CLI::App* _saveCommand;
|
||||||
|
|
||||||
// Are you adding a new sub-command? Make sure to update _noCommandsProvided!
|
// Are you adding a new sub-command? Make sure to update _noCommandsProvided!
|
||||||
|
|
||||||
@@ -123,6 +124,8 @@ private:
|
|||||||
bool _focusPrevTab{ false };
|
bool _focusPrevTab{ false };
|
||||||
|
|
||||||
int _focusPaneTarget{ -1 };
|
int _focusPaneTarget{ -1 };
|
||||||
|
std::string _saveInputName;
|
||||||
|
std::string _keyChordOption;
|
||||||
// Are you adding more args here? Make sure to reset them in _resetStateToDefault
|
// Are you adding more args here? Make sure to reset them in _resetStateToDefault
|
||||||
|
|
||||||
const Commandline* _currentCommandline{ nullptr };
|
const Commandline* _currentCommandline{ nullptr };
|
||||||
@@ -141,6 +144,7 @@ private:
|
|||||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs _getNewTerminalArgs(NewTerminalSubcommand& subcommand);
|
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs _getNewTerminalArgs(NewTerminalSubcommand& subcommand);
|
||||||
void _addNewTerminalArgs(NewTerminalSubcommand& subcommand);
|
void _addNewTerminalArgs(NewTerminalSubcommand& subcommand);
|
||||||
void _buildParser();
|
void _buildParser();
|
||||||
|
void _buildSaveSnippetParser();
|
||||||
void _buildNewTabParser();
|
void _buildNewTabParser();
|
||||||
void _buildSplitPaneParser();
|
void _buildSplitPaneParser();
|
||||||
void _buildFocusTabParser();
|
void _buildFocusTabParser();
|
||||||
|
|||||||
@@ -288,6 +288,15 @@
|
|||||||
<data name="CmdCommandArgDesc" xml:space="preserve">
|
<data name="CmdCommandArgDesc" xml:space="preserve">
|
||||||
<value>An optional command, with arguments, to be spawned in the new tab or pane</value>
|
<value>An optional command, with arguments, to be spawned in the new tab or pane</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="SaveSnippetDesc" xml:space="preserve">
|
||||||
|
<value>Save command line as input action</value>
|
||||||
|
</data>
|
||||||
|
<data name="SaveSnippetArgDesc" xml:space="preserve">
|
||||||
|
<value>An optional argument</value>
|
||||||
|
</data>
|
||||||
|
<data name="KeyChordArgDesc" xml:space="preserve">
|
||||||
|
<value>An optional argument</value>
|
||||||
|
</data>
|
||||||
<data name="CmdFocusTabDesc" xml:space="preserve">
|
<data name="CmdFocusTabDesc" xml:space="preserve">
|
||||||
<value>Move focus to another tab</value>
|
<value>Move focus to another tab</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -898,4 +907,10 @@
|
|||||||
<data name="RestartConnectionToolTip" xml:space="preserve">
|
<data name="RestartConnectionToolTip" xml:space="preserve">
|
||||||
<value>Restart the active pane connection</value>
|
<value>Restart the active pane connection</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ActionSavedToast.Title" xml:space="preserve">
|
||||||
|
<value>Action saved</value>
|
||||||
|
</data>
|
||||||
|
<data name="ActionSaveFailedToast.Title" xml:space="preserve">
|
||||||
|
<value>Action save failed</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -357,7 +357,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- ========================= Misc Files ======================== -->
|
<!-- ========================= Misc Files ======================== -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PRIResource Include="Resources\en-US\Resources.resw" />
|
<PRIResource Include="Resources\en-US\Resources.resw">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</PRIResource>
|
||||||
<PRIResource Include="Resources\en-US\ContextMenu.resw" />
|
<PRIResource Include="Resources\en-US\ContextMenu.resw" />
|
||||||
<OCResourceDirectory Include="Resources" />
|
<OCResourceDirectory Include="Resources" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -466,10 +468,8 @@
|
|||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<!-- ========================= Globals ======================== -->
|
<!-- ========================= Globals ======================== -->
|
||||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||||
|
|
||||||
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
|
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
|
||||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
By default, the PRI file will contain resource paths beginning with the
|
By default, the PRI file will contain resource paths beginning with the
|
||||||
project name. Since we enabled XBF embedding, this *also* includes App.xbf.
|
project name. Since we enabled XBF embedding, this *also* includes App.xbf.
|
||||||
@@ -490,4 +490,4 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
@@ -146,6 +146,8 @@ namespace winrt::TerminalApp::implementation
|
|||||||
winrt::hstring KeyboardServiceDisabledText();
|
winrt::hstring KeyboardServiceDisabledText();
|
||||||
|
|
||||||
winrt::fire_and_forget IdentifyWindow();
|
winrt::fire_and_forget IdentifyWindow();
|
||||||
|
void ActionSaved(winrt::hstring input, winrt::hstring name, winrt::hstring keyChord);
|
||||||
|
void ActionSaveFailed(winrt::hstring message);
|
||||||
winrt::fire_and_forget RenameFailed();
|
winrt::fire_and_forget RenameFailed();
|
||||||
winrt::fire_and_forget ShowTerminalWorkingDirectory();
|
winrt::fire_and_forget ShowTerminalWorkingDirectory();
|
||||||
|
|
||||||
@@ -199,6 +201,10 @@ namespace winrt::TerminalApp::implementation
|
|||||||
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, TitlebarBrush, PropertyChanged.raise, nullptr);
|
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, TitlebarBrush, PropertyChanged.raise, nullptr);
|
||||||
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, FrameBrush, PropertyChanged.raise, nullptr);
|
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, FrameBrush, PropertyChanged.raise, nullptr);
|
||||||
|
|
||||||
|
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SavedActionName, PropertyChanged.raise, L"");
|
||||||
|
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SavedActionKeyChord, PropertyChanged.raise, L"");
|
||||||
|
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SavedActionCommandLine, PropertyChanged.raise, L"");
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct TerminalPageT<TerminalPage>; // for Xaml to bind events
|
friend struct TerminalPageT<TerminalPage>; // for Xaml to bind events
|
||||||
std::optional<HWND> _hostingHwnd;
|
std::optional<HWND> _hostingHwnd;
|
||||||
@@ -258,6 +264,8 @@ namespace winrt::TerminalApp::implementation
|
|||||||
bool _isEmbeddingInboundListener{ false };
|
bool _isEmbeddingInboundListener{ false };
|
||||||
|
|
||||||
std::shared_ptr<Toast> _windowIdToast{ nullptr };
|
std::shared_ptr<Toast> _windowIdToast{ nullptr };
|
||||||
|
std::shared_ptr<Toast> _actionSavedToast{ nullptr };
|
||||||
|
std::shared_ptr<Toast> _actionSaveFailedToast{ nullptr };
|
||||||
std::shared_ptr<Toast> _windowRenameFailedToast{ nullptr };
|
std::shared_ptr<Toast> _windowRenameFailedToast{ nullptr };
|
||||||
std::shared_ptr<Toast> _windowCwdToast{ nullptr };
|
std::shared_ptr<Toast> _windowCwdToast{ nullptr };
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ namespace TerminalApp
|
|||||||
void IdentifyWindow();
|
void IdentifyWindow();
|
||||||
void RenameFailed();
|
void RenameFailed();
|
||||||
|
|
||||||
|
String SavedActionName { get; };
|
||||||
|
String SavedActionKeyChord { get; };
|
||||||
|
String SavedActionCommandLine { get; };
|
||||||
|
|
||||||
// We cannot use the default XAML APIs because we want to make sure
|
// We cannot use the default XAML APIs because we want to make sure
|
||||||
// that there's only one application-global dialog visible at a time,
|
// that there's only one application-global dialog visible at a time,
|
||||||
// and because of GH#5224.
|
// and because of GH#5224.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="using:TerminalApp"
|
xmlns:local="using:TerminalApp"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:mtu="using:Microsoft.Terminal.UI"
|
||||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
@@ -204,5 +205,43 @@
|
|||||||
Title="{x:Bind WindowProperties.VirtualWorkingDirectory, Mode=OneWay}"
|
Title="{x:Bind WindowProperties.VirtualWorkingDirectory, Mode=OneWay}"
|
||||||
x:Load="False"
|
x:Load="False"
|
||||||
IsLightDismissEnabled="True" />
|
IsLightDismissEnabled="True" />
|
||||||
|
|
||||||
|
<mux:TeachingTip x:Name="ActionSavedToast"
|
||||||
|
x:Uid="ActionSavedToast"
|
||||||
|
Title="Action Saved"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
x:Load="False"
|
||||||
|
IsLightDismissEnabled="True">
|
||||||
|
<mux:TeachingTip.Content>
|
||||||
|
<StackPanel HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Vertical">
|
||||||
|
<TextBlock x:Name="ActionSavedNameText"
|
||||||
|
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(SavedActionName), Mode=OneWay}">
|
||||||
|
<Run Text="Name: " />
|
||||||
|
<Run Text="{x:Bind SavedActionName, Mode=OneWay}" />
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock x:Name="ActionSavedKeyChordText"
|
||||||
|
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(SavedActionKeyChord), Mode=OneWay}">
|
||||||
|
<Run Text="Key Chord: " />
|
||||||
|
<Run Text="{x:Bind SavedActionKeyChord, Mode=OneWay}" />
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock x:Name="ActionSavedCommandLineText"
|
||||||
|
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(SavedActionCommandLine), Mode=OneWay}">
|
||||||
|
<Run Text="Input: " />
|
||||||
|
<Run Text="{x:Bind SavedActionCommandLine, Mode=OneWay}" />
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</mux:TeachingTip.Content>
|
||||||
|
</mux:TeachingTip>
|
||||||
|
<mux:TeachingTip x:Name="ActionSaveFailedToast"
|
||||||
|
x:Uid="ActionSaveFailedToast"
|
||||||
|
Title="Action Save Failed"
|
||||||
|
x:Load="False"
|
||||||
|
IsLightDismissEnabled="True">
|
||||||
|
<mux:TeachingTip.Content>
|
||||||
|
<TextBlock x:Name="ActionSaveFailedMessage"
|
||||||
|
Text="" />
|
||||||
|
</mux:TeachingTip.Content>
|
||||||
|
</mux:TeachingTip>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ static constexpr std::string_view SwitchToTabKey{ "switchToTab" };
|
|||||||
static constexpr std::string_view TabSearchKey{ "tabSearch" };
|
static constexpr std::string_view TabSearchKey{ "tabSearch" };
|
||||||
static constexpr std::string_view ToggleAlwaysOnTopKey{ "toggleAlwaysOnTop" };
|
static constexpr std::string_view ToggleAlwaysOnTopKey{ "toggleAlwaysOnTop" };
|
||||||
static constexpr std::string_view ToggleCommandPaletteKey{ "commandPalette" };
|
static constexpr std::string_view ToggleCommandPaletteKey{ "commandPalette" };
|
||||||
|
static constexpr std::string_view SaveSnippetKey{ "experimental.saveSnippet" };
|
||||||
static constexpr std::string_view SuggestionsKey{ "showSuggestions" };
|
static constexpr std::string_view SuggestionsKey{ "showSuggestions" };
|
||||||
static constexpr std::string_view ToggleFocusModeKey{ "toggleFocusMode" };
|
static constexpr std::string_view ToggleFocusModeKey{ "toggleFocusMode" };
|
||||||
static constexpr std::string_view SetFocusModeKey{ "setFocusMode" };
|
static constexpr std::string_view SetFocusModeKey{ "setFocusMode" };
|
||||||
@@ -389,6 +390,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
{ ShortcutAction::TabSearch, RS_(L"TabSearchCommandKey") },
|
{ ShortcutAction::TabSearch, RS_(L"TabSearchCommandKey") },
|
||||||
{ ShortcutAction::ToggleAlwaysOnTop, RS_(L"ToggleAlwaysOnTopCommandKey") },
|
{ ShortcutAction::ToggleAlwaysOnTop, RS_(L"ToggleAlwaysOnTopCommandKey") },
|
||||||
{ ShortcutAction::ToggleCommandPalette, MustGenerate },
|
{ ShortcutAction::ToggleCommandPalette, MustGenerate },
|
||||||
|
{ ShortcutAction::SaveSnippet, MustGenerate },
|
||||||
{ ShortcutAction::Suggestions, MustGenerate },
|
{ ShortcutAction::Suggestions, MustGenerate },
|
||||||
{ ShortcutAction::ToggleFocusMode, RS_(L"ToggleFocusModeCommandKey") },
|
{ ShortcutAction::ToggleFocusMode, RS_(L"ToggleFocusModeCommandKey") },
|
||||||
{ ShortcutAction::SetFocusMode, MustGenerate },
|
{ ShortcutAction::SetFocusMode, MustGenerate },
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "ScrollToMarkArgs.g.cpp"
|
#include "ScrollToMarkArgs.g.cpp"
|
||||||
#include "AddMarkArgs.g.cpp"
|
#include "AddMarkArgs.g.cpp"
|
||||||
#include "FindMatchArgs.g.cpp"
|
#include "FindMatchArgs.g.cpp"
|
||||||
|
#include "SaveSnippetArgs.g.cpp"
|
||||||
#include "ToggleCommandPaletteArgs.g.cpp"
|
#include "ToggleCommandPaletteArgs.g.cpp"
|
||||||
#include "SuggestionsArgs.g.cpp"
|
#include "SuggestionsArgs.g.cpp"
|
||||||
#include "NewWindowArgs.g.cpp"
|
#include "NewWindowArgs.g.cpp"
|
||||||
@@ -947,6 +948,29 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
winrt::hstring SaveSnippetArgs::GenerateName() const
|
||||||
|
{
|
||||||
|
if (Feature_SaveSnippet::IsEnabled())
|
||||||
|
{
|
||||||
|
std::wstringstream ss;
|
||||||
|
|
||||||
|
ss << RS_(L"SaveSnippetNamePrefix").c_str() << L" commandline: " << Commandline().c_str();
|
||||||
|
|
||||||
|
if (!Name().empty())
|
||||||
|
{
|
||||||
|
ss << L", name: " << Name().c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!KeyChord().empty())
|
||||||
|
{
|
||||||
|
ss << L", keyChord " << KeyChord().c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
return winrt::hstring{ ss.str() };
|
||||||
|
}
|
||||||
|
return L"";
|
||||||
|
}
|
||||||
|
|
||||||
static winrt::hstring _FormatColorString(const Control::SelectionColor& selectionColor)
|
static winrt::hstring _FormatColorString(const Control::SelectionColor& selectionColor)
|
||||||
{
|
{
|
||||||
if (!selectionColor)
|
if (!selectionColor)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "ScrollToMarkArgs.g.h"
|
#include "ScrollToMarkArgs.g.h"
|
||||||
#include "AddMarkArgs.g.h"
|
#include "AddMarkArgs.g.h"
|
||||||
#include "MoveTabArgs.g.h"
|
#include "MoveTabArgs.g.h"
|
||||||
|
#include "SaveSnippetArgs.g.h"
|
||||||
#include "ToggleCommandPaletteArgs.g.h"
|
#include "ToggleCommandPaletteArgs.g.h"
|
||||||
#include "SuggestionsArgs.g.h"
|
#include "SuggestionsArgs.g.h"
|
||||||
#include "FindMatchArgs.g.h"
|
#include "FindMatchArgs.g.h"
|
||||||
@@ -215,6 +216,12 @@ protected: \
|
|||||||
#define TOGGLE_COMMAND_PALETTE_ARGS(X) \
|
#define TOGGLE_COMMAND_PALETTE_ARGS(X) \
|
||||||
X(CommandPaletteLaunchMode, LaunchMode, "launchMode", false, CommandPaletteLaunchMode::Action)
|
X(CommandPaletteLaunchMode, LaunchMode, "launchMode", false, CommandPaletteLaunchMode::Action)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define SAVE_TASK_ARGS(X) \
|
||||||
|
X(winrt::hstring, Name, "name", false, L"") \
|
||||||
|
X(winrt::hstring, Commandline, "commandline", args->Commandline().empty(), L"") \
|
||||||
|
X(winrt::hstring, KeyChord, "keyChord", false, L"")
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
#define SUGGESTIONS_ARGS(X) \
|
#define SUGGESTIONS_ARGS(X) \
|
||||||
X(SuggestionsSource, Source, "source", false, SuggestionsSource::Tasks) \
|
X(SuggestionsSource, Source, "source", false, SuggestionsSource::Tasks) \
|
||||||
@@ -819,6 +826,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
|
|
||||||
ACTION_ARGS_STRUCT(ToggleCommandPaletteArgs, TOGGLE_COMMAND_PALETTE_ARGS);
|
ACTION_ARGS_STRUCT(ToggleCommandPaletteArgs, TOGGLE_COMMAND_PALETTE_ARGS);
|
||||||
|
|
||||||
|
ACTION_ARGS_STRUCT(SaveSnippetArgs, SAVE_TASK_ARGS);
|
||||||
|
|
||||||
ACTION_ARGS_STRUCT(SuggestionsArgs, SUGGESTIONS_ARGS);
|
ACTION_ARGS_STRUCT(SuggestionsArgs, SUGGESTIONS_ARGS);
|
||||||
|
|
||||||
ACTION_ARGS_STRUCT(FindMatchArgs, FIND_MATCH_ARGS);
|
ACTION_ARGS_STRUCT(FindMatchArgs, FIND_MATCH_ARGS);
|
||||||
@@ -941,6 +950,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
|
|||||||
BASIC_FACTORY(CloseTabArgs);
|
BASIC_FACTORY(CloseTabArgs);
|
||||||
BASIC_FACTORY(MoveTabArgs);
|
BASIC_FACTORY(MoveTabArgs);
|
||||||
BASIC_FACTORY(OpenSettingsArgs);
|
BASIC_FACTORY(OpenSettingsArgs);
|
||||||
|
BASIC_FACTORY(SaveSnippetArgs);
|
||||||
BASIC_FACTORY(FindMatchArgs);
|
BASIC_FACTORY(FindMatchArgs);
|
||||||
BASIC_FACTORY(NewWindowArgs);
|
BASIC_FACTORY(NewWindowArgs);
|
||||||
BASIC_FACTORY(FocusPaneArgs);
|
BASIC_FACTORY(FocusPaneArgs);
|
||||||
|
|||||||
@@ -357,6 +357,15 @@ namespace Microsoft.Terminal.Settings.Model
|
|||||||
FindMatchDirection Direction { get; };
|
FindMatchDirection Direction { get; };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[default_interface] runtimeclass SaveSnippetArgs : IActionArgs
|
||||||
|
{
|
||||||
|
SaveSnippetArgs();
|
||||||
|
SaveSnippetArgs(String Name, String Commandline, String KeyChord);
|
||||||
|
String Name;
|
||||||
|
String Commandline;
|
||||||
|
String KeyChord;
|
||||||
|
};
|
||||||
|
|
||||||
[default_interface] runtimeclass NewWindowArgs : IActionArgs
|
[default_interface] runtimeclass NewWindowArgs : IActionArgs
|
||||||
{
|
{
|
||||||
NewWindowArgs(INewContentArgs contentArgs);
|
NewWindowArgs(INewContentArgs contentArgs);
|
||||||
|
|||||||
@@ -882,6 +882,22 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ActionMap::AddSendInputAction(winrt::hstring name, winrt::hstring input, const Control::KeyChord keys)
|
||||||
|
{
|
||||||
|
auto newAction = winrt::make<ActionAndArgs>();
|
||||||
|
newAction.Action(ShortcutAction::SendInput);
|
||||||
|
auto sendInputArgs = winrt::make<SendInputArgs>(input);
|
||||||
|
newAction.Args(sendInputArgs);
|
||||||
|
auto cmd{ make_self<Command>() };
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
cmd->Name(name);
|
||||||
|
}
|
||||||
|
cmd->ActionAndArgs(newAction);
|
||||||
|
cmd->GenerateID();
|
||||||
|
AddAction(*cmd, keys);
|
||||||
|
}
|
||||||
|
|
||||||
IVector<Model::Command> ActionMap::FilterToSendInput(
|
IVector<Model::Command> ActionMap::FilterToSendInput(
|
||||||
winrt::hstring currentCommandline)
|
winrt::hstring currentCommandline)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
bool RebindKeys(const Control::KeyChord& oldKeys, const Control::KeyChord& newKeys);
|
bool RebindKeys(const Control::KeyChord& oldKeys, const Control::KeyChord& newKeys);
|
||||||
void DeleteKeyBinding(const Control::KeyChord& keys);
|
void DeleteKeyBinding(const Control::KeyChord& keys);
|
||||||
void RegisterKeyBinding(Control::KeyChord keys, Model::ActionAndArgs action);
|
void RegisterKeyBinding(Control::KeyChord keys, Model::ActionAndArgs action);
|
||||||
|
void AddSendInputAction(winrt::hstring name, winrt::hstring input, const Control::KeyChord keys);
|
||||||
|
|
||||||
Windows::Foundation::Collections::IVector<Model::Command> ExpandedCommands();
|
Windows::Foundation::Collections::IVector<Model::Command> ExpandedCommands();
|
||||||
void ExpandCommands(const Windows::Foundation::Collections::IVectorView<Model::Profile>& profiles,
|
void ExpandCommands(const Windows::Foundation::Collections::IVectorView<Model::Profile>& profiles,
|
||||||
|
|||||||
@@ -31,5 +31,6 @@ namespace Microsoft.Terminal.Settings.Model
|
|||||||
void DeleteKeyBinding(Microsoft.Terminal.Control.KeyChord keys);
|
void DeleteKeyBinding(Microsoft.Terminal.Control.KeyChord keys);
|
||||||
|
|
||||||
void RegisterKeyBinding(Microsoft.Terminal.Control.KeyChord keys, ActionAndArgs action);
|
void RegisterKeyBinding(Microsoft.Terminal.Control.KeyChord keys, ActionAndArgs action);
|
||||||
|
void AddSendInputAction(String name, String input, Microsoft.Terminal.Control.KeyChord keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,7 @@
|
|||||||
ON_ALL_ACTIONS(CloseTabsAfter) \
|
ON_ALL_ACTIONS(CloseTabsAfter) \
|
||||||
ON_ALL_ACTIONS(TabSearch) \
|
ON_ALL_ACTIONS(TabSearch) \
|
||||||
ON_ALL_ACTIONS(MoveTab) \
|
ON_ALL_ACTIONS(MoveTab) \
|
||||||
|
ON_ALL_ACTIONS(SaveSnippet) \
|
||||||
ON_ALL_ACTIONS(BreakIntoDebugger) \
|
ON_ALL_ACTIONS(BreakIntoDebugger) \
|
||||||
ON_ALL_ACTIONS(TogglePaneReadOnly) \
|
ON_ALL_ACTIONS(TogglePaneReadOnly) \
|
||||||
ON_ALL_ACTIONS(EnablePaneReadOnly) \
|
ON_ALL_ACTIONS(EnablePaneReadOnly) \
|
||||||
@@ -148,6 +149,7 @@
|
|||||||
ON_ALL_ACTIONS_WITH_ARGS(SplitPane) \
|
ON_ALL_ACTIONS_WITH_ARGS(SplitPane) \
|
||||||
ON_ALL_ACTIONS_WITH_ARGS(SwitchToTab) \
|
ON_ALL_ACTIONS_WITH_ARGS(SwitchToTab) \
|
||||||
ON_ALL_ACTIONS_WITH_ARGS(ToggleCommandPalette) \
|
ON_ALL_ACTIONS_WITH_ARGS(ToggleCommandPalette) \
|
||||||
|
ON_ALL_ACTIONS_WITH_ARGS(SaveSnippet) \
|
||||||
ON_ALL_ACTIONS_WITH_ARGS(FocusPane) \
|
ON_ALL_ACTIONS_WITH_ARGS(FocusPane) \
|
||||||
ON_ALL_ACTIONS_WITH_ARGS(ExportBuffer) \
|
ON_ALL_ACTIONS_WITH_ARGS(ExportBuffer) \
|
||||||
ON_ALL_ACTIONS_WITH_ARGS(ClearBuffer) \
|
ON_ALL_ACTIONS_WITH_ARGS(ClearBuffer) \
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
|
|
||||||
Version 2.0
|
Version 2.0
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
The primary goals of this format is to allow a simple XML format
|
||||||
that is mostly human readable. The generation and parsing of the
|
that is mostly human readable. The generation and parsing of the
|
||||||
various data types are done through the TypeConverter classes
|
various data types are done through the TypeConverter classes
|
||||||
associated with the data types.
|
associated with the data types.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
... ado.net/XML headers & schema ...
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
<resheader name="version">2.0</resheader>
|
<resheader name="version">2.0</resheader>
|
||||||
@@ -26,36 +26,36 @@
|
|||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
<comment>This is a comment</comment>
|
<comment>This is a comment</comment>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
There are any number of "resheader" rows that contain simple
|
||||||
name/value pairs.
|
name/value pairs.
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
Each data row contains a name, and value. The row also contains a
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
text/value conversion through the TypeConverter architecture.
|
text/value conversion through the TypeConverter architecture.
|
||||||
Classes that don't support this are serialized and stored with the
|
Classes that don't support this are serialized and stored with the
|
||||||
mimetype set.
|
mimetype set.
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
The mimetype is used for serialized objects, and tells the
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
read any of the formats listed below.
|
read any of the formats listed below.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
value : The object must be serialized with
|
value : The object must be serialized with
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
value : The object must be serialized with
|
value : The object must be serialized with
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
value : The object must be serialized into a byte array
|
value : The object must be serialized into a byte array
|
||||||
: using a System.ComponentModel.TypeConverter
|
: using a System.ComponentModel.TypeConverter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
-->
|
-->
|
||||||
@@ -727,4 +727,7 @@
|
|||||||
<value>Open about dialog</value>
|
<value>Open about dialog</value>
|
||||||
<comment>This will open the "about" dialog, to display version info and other documentation</comment>
|
<comment>This will open the "about" dialog, to display version info and other documentation</comment>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
<data name="SaveSnippetNamePrefix" xml:space="preserve">
|
||||||
|
<value>Save Snippet</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
|
|||||||
@@ -155,6 +155,17 @@
|
|||||||
</alwaysEnabledBrandingTokens>
|
</alwaysEnabledBrandingTokens>
|
||||||
</feature>
|
</feature>
|
||||||
|
|
||||||
|
<feature>
|
||||||
|
<name>Feature_SaveSnippet</name>
|
||||||
|
<description>Save Snippet</description>
|
||||||
|
<id>9971</id>
|
||||||
|
<stage>AlwaysDisabled</stage>
|
||||||
|
<alwaysEnabledBrandingTokens>
|
||||||
|
<brandingToken>Dev</brandingToken>
|
||||||
|
<brandingToken>Canary</brandingToken>
|
||||||
|
</alwaysEnabledBrandingTokens>
|
||||||
|
</feature>
|
||||||
|
|
||||||
<feature>
|
<feature>
|
||||||
<name>Feature_QuickFix</name>
|
<name>Feature_QuickFix</name>
|
||||||
<description>Enables the Quick Fix menu</description>
|
<description>Enables the Quick Fix menu</description>
|
||||||
|
|||||||
Reference in New Issue
Block a user