From 7d6c61a1cb07c129d23afced38526680a29abbf2 Mon Sep 17 00:00:00 2001 From: khvitaly Date: Mon, 7 Dec 2020 15:13:01 +0200 Subject: [PATCH 1/7] Introduce parsed command line text to command palette --- .../CommandlineTest.cpp | 6 +-- .../TerminalApp/AppActionHandlers.cpp | 2 +- .../TerminalApp/AppCommandlineArgs.cpp | 43 +++++++++++++++++++ src/cascadia/TerminalApp/AppCommandlineArgs.h | 2 + src/cascadia/TerminalApp/CommandPalette.cpp | 32 +++++++++++++- src/cascadia/TerminalApp/CommandPalette.h | 1 + src/cascadia/TerminalApp/CommandPalette.idl | 1 + src/cascadia/TerminalApp/CommandPalette.xaml | 38 ++++++++++++++++ .../Resources/en-US/Resources.resw | 7 +++ src/cascadia/TerminalApp/TerminalPage.cpp | 43 ------------------- src/cascadia/TerminalApp/TerminalPage.h | 1 - 11 files changed, 127 insertions(+), 49 deletions(-) diff --git a/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp b/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp index b9261c1c683..5afeee18f81 100644 --- a/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp +++ b/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp @@ -1124,7 +1124,7 @@ namespace TerminalAppLocalTests void CommandlineTest::TestSimpleExecuteCommandlineAction() { ExecuteCommandlineArgs args{ L"new-tab" }; - auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(args); + auto actions = AppCommandlineArgs::ConvertExecuteCommandlineToActions(args); VERIFY_ARE_EQUAL(1u, actions.size()); auto actionAndArgs = actions.at(0); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); @@ -1143,7 +1143,7 @@ namespace TerminalAppLocalTests void CommandlineTest::TestMultipleCommandExecuteCommandlineAction() { ExecuteCommandlineArgs args{ L"new-tab ; split-pane" }; - auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(args); + auto actions = AppCommandlineArgs::ConvertExecuteCommandlineToActions(args); VERIFY_ARE_EQUAL(2u, actions.size()); { auto actionAndArgs = actions.at(0); @@ -1179,7 +1179,7 @@ namespace TerminalAppLocalTests { // -H and -V cannot be combined. ExecuteCommandlineArgs args{ L"split-pane -H -V" }; - auto actions = implementation::TerminalPage::ConvertExecuteCommandlineToActions(args); + auto actions = AppCommandlineArgs::ConvertExecuteCommandlineToActions(args); VERIFY_ARE_EQUAL(0u, actions.size()); } diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 7da1daa6f8e..4cd0de4934a 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -434,7 +434,7 @@ namespace winrt::TerminalApp::implementation if (const auto& realArgs = actionArgs.ActionArgs().try_as()) { auto actions = winrt::single_threaded_vector(std::move( - TerminalPage::ConvertExecuteCommandlineToActions(realArgs))); + AppCommandlineArgs::ConvertExecuteCommandlineToActions(realArgs))); if (_startupActions.Size() != 0) { diff --git a/src/cascadia/TerminalApp/AppCommandlineArgs.cpp b/src/cascadia/TerminalApp/AppCommandlineArgs.cpp index 7b7e2138265..08b4922cd25 100644 --- a/src/cascadia/TerminalApp/AppCommandlineArgs.cpp +++ b/src/cascadia/TerminalApp/AppCommandlineArgs.cpp @@ -720,3 +720,46 @@ int AppCommandlineArgs::ParseArgs(winrt::array_view& args) // built in _appArgs, which we'll use when the application starts up. return 0; } + +// Function Description: +// - This is a helper method to get the commandline out of a +// ExecuteCommandline action, break it into subcommands, and attempt to +// parse it into actions. This is used by _HandleExecuteCommandline for +// processing commandlines in the current WT window. +// Arguments: +// - args: the ExecuteCommandlineArgs to synthesize a list of startup actions for. +// Return Value: +// - an empty list if we failed to parse, otherwise a list of actions to execute. +std::vector AppCommandlineArgs::ConvertExecuteCommandlineToActions(const winrt::Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args) +{ + if (!args || args.Commandline().empty()) + { + return {}; + } + // Convert the commandline into an array of args with + // CommandLineToArgvW, similar to how the app typically does when + // called from the commandline. + int argc = 0; + wil::unique_any argv{ CommandLineToArgvW(args.Commandline().c_str(), &argc) }; + if (argv) + { + std::vector args; + + // Make sure the first argument is wt.exe, because ParseArgs will + // always skip the program name. The particular value of this first + // string doesn't terribly matter. + args.emplace_back(L"wt.exe"); + for (auto& elem : wil::make_range(argv.get(), argc)) + { + args.emplace_back(elem); + } + winrt::array_view argsView{ args }; + + ::TerminalApp::AppCommandlineArgs appArgs; + if (appArgs.ParseArgs(argsView) == 0) + { + return appArgs.GetStartupActions(); + } + } + return {}; +} diff --git a/src/cascadia/TerminalApp/AppCommandlineArgs.h b/src/cascadia/TerminalApp/AppCommandlineArgs.h index 6a7d08b0e7d..40ef499a042 100644 --- a/src/cascadia/TerminalApp/AppCommandlineArgs.h +++ b/src/cascadia/TerminalApp/AppCommandlineArgs.h @@ -40,6 +40,8 @@ class TerminalApp::AppCommandlineArgs final std::optional GetLaunchMode() const noexcept; + static std::vector ConvertExecuteCommandlineToActions(const winrt::Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args); + private: static const std::wregex _commandDelimiterRegex; diff --git a/src/cascadia/TerminalApp/CommandPalette.cpp b/src/cascadia/TerminalApp/CommandPalette.cpp index 90c1f7f95c1..8a3b928bbd5 100644 --- a/src/cascadia/TerminalApp/CommandPalette.cpp +++ b/src/cascadia/TerminalApp/CommandPalette.cpp @@ -3,7 +3,7 @@ #include "pch.h" #include "CommandPalette.h" - +#include "AppCommandlineArgs.h" #include #include "CommandPalette.g.cpp" @@ -733,6 +733,35 @@ namespace winrt::TerminalApp::implementation { _noMatchesText().Visibility(Visibility::Collapsed); } + + if (_currentMode == CommandPaletteMode::CommandlineMode) + { + const auto commandLine = _getTrimmedInput(); + if (commandLine.empty()) + { + ParsedCommandLineText(L""); + } + else + { + ExecuteCommandlineArgs args{ commandLine }; + const auto commands = ::TerminalApp::AppCommandlineArgs::ConvertExecuteCommandlineToActions(args); + if (commands.size() == 0) + { + ParsedCommandLineText(RS_(L"CommandPalette_FailedParsingCommandLine")); + } + else + { + std::wstring commandDescription{ RS_(L"CommandPalette_ParsedCommandLine") }; + for (const auto& command : commands) + { + commandDescription += L"\n\t" + command.Args().GenerateName(); + } + ParsedCommandLineText(commandDescription.data()); + } + + _noMatchesText().Visibility(Visibility::Visible); + } + } } void CommandPalette::_evaluatePrefix() @@ -837,6 +866,7 @@ namespace winrt::TerminalApp::implementation } } + ParsedCommandLineText(L""); _searchBox().Text(L""); _searchBox().Select(_searchBox().Text().size(), 0); // Leaving this block of code outside the above if-statement diff --git a/src/cascadia/TerminalApp/CommandPalette.h b/src/cascadia/TerminalApp/CommandPalette.h index 21c00129307..06c783fcc66 100644 --- a/src/cascadia/TerminalApp/CommandPalette.h +++ b/src/cascadia/TerminalApp/CommandPalette.h @@ -56,6 +56,7 @@ namespace winrt::TerminalApp::implementation OBSERVABLE_GETSET_PROPERTY(winrt::hstring, PrefixCharacter, _PropertyChangedHandlers); OBSERVABLE_GETSET_PROPERTY(winrt::hstring, ControlName, _PropertyChangedHandlers); OBSERVABLE_GETSET_PROPERTY(winrt::hstring, ParentCommandName, _PropertyChangedHandlers); + OBSERVABLE_GETSET_PROPERTY(winrt::hstring, ParsedCommandLineText, _PropertyChangedHandlers); private: friend struct CommandPaletteT; // for Xaml to bind events diff --git a/src/cascadia/TerminalApp/CommandPalette.idl b/src/cascadia/TerminalApp/CommandPalette.idl index e75209e7699..aa3e27f4b7b 100644 --- a/src/cascadia/TerminalApp/CommandPalette.idl +++ b/src/cascadia/TerminalApp/CommandPalette.idl @@ -17,6 +17,7 @@ namespace TerminalApp String PrefixCharacter { get; }; String ControlName { get; }; String ParentCommandName { get; }; + String ParsedCommandLineText { get; }; Windows.Foundation.Collections.IObservableVector FilteredActions { get; }; diff --git a/src/cascadia/TerminalApp/CommandPalette.xaml b/src/cascadia/TerminalApp/CommandPalette.xaml index 680a6be37f4..6f70ad53fab 100644 --- a/src/cascadia/TerminalApp/CommandPalette.xaml +++ b/src/cascadia/TerminalApp/CommandPalette.xaml @@ -29,6 +29,7 @@ the MIT License. See LICENSE in the project root for license information. --> + @@ -67,6 +68,16 @@ the MIT License. See LICENSE in the project root for license information. --> + + + + + + - @@ -118,7 +118,7 @@ the MIT License. See LICENSE in the project root for license information. --> - From 75fffb344a8cf4722b6c6ca0d79805d58b015079 Mon Sep 17 00:00:00 2001 From: khvitaly Date: Wed, 16 Dec 2020 03:24:43 +0200 Subject: [PATCH 6/7] Cleanup leftover setting noMatchText visible in command line mode --- src/cascadia/TerminalApp/CommandPalette.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cascadia/TerminalApp/CommandPalette.cpp b/src/cascadia/TerminalApp/CommandPalette.cpp index 37bb79bbda9..9543b0a1bec 100644 --- a/src/cascadia/TerminalApp/CommandPalette.cpp +++ b/src/cascadia/TerminalApp/CommandPalette.cpp @@ -821,7 +821,6 @@ namespace winrt::TerminalApp::implementation { ParsedCommandLineText(RS_(L"CommandPalette_FailedParsingCommandLine") + L"\n\t" + til::u8u16(_appArgs.GetExitMessage())); } - _noMatchesText().Visibility(Visibility::Visible); } } } From dc2459247f85287e8a73a31603187c9b7e95e6ab Mon Sep 17 00:00:00 2001 From: khvitaly Date: Wed, 16 Dec 2020 03:40:36 +0200 Subject: [PATCH 7/7] Introduce vertical scroll for parsed command text --- src/cascadia/TerminalApp/CommandPalette.xaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cascadia/TerminalApp/CommandPalette.xaml b/src/cascadia/TerminalApp/CommandPalette.xaml index e7277cb0ccb..1926b1b0c60 100644 --- a/src/cascadia/TerminalApp/CommandPalette.xaml +++ b/src/cascadia/TerminalApp/CommandPalette.xaml @@ -260,10 +260,12 @@ the MIT License. See LICENSE in the project root for license information. --> HorizontalAlignment="Stretch" VerticalAlignment="Center"> - + + +