diff --git a/src/cascadia/TerminalApp/AppCommandlineArgs.cpp b/src/cascadia/TerminalApp/AppCommandlineArgs.cpp index 7b7e21382655..4fcf9026c7b1 100644 --- a/src/cascadia/TerminalApp/AppCommandlineArgs.cpp +++ b/src/cascadia/TerminalApp/AppCommandlineArgs.cpp @@ -720,3 +720,75 @@ int AppCommandlineArgs::ParseArgs(winrt::array_view& args) // built in _appArgs, which we'll use when the application starts up. return 0; } + +// Method Description: +// - Attempts to parse an array of commandline args into a list of +// commands to execute, and then parses these commands. As commands are +// successfully parsed, they will generate ShortcutActions for us to be +// able to execute. If we fail to parse any commands, we'll return the +// error code from the failure to parse that command, and stop processing +// additional commands. +// - The first arg in args should be the program name "wt" (or some variant). It +// will be ignored during parsing. +// Arguments: +// - args: ExecuteCommandlineArgs describing the command line to parse +// Return Value: +// - 0 if the commandline was successfully parsed +int AppCommandlineArgs::ParseArgs(const winrt::Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args) +{ + if (!args || args.Commandline().empty()) + { + return 0; + } + + // 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 }; + return ParseArgs(argsView); + } + return 0; +} + +// Method Description: +// - Allows disabling addition of help-related info in the exit message +// Arguments: +// - +// Return Value: +// - +void AppCommandlineArgs::DisableHelpInExitMessage() +{ + _app.set_help_flag(); + _app.set_help_all_flag(); +} + +// Method Description: +// - Resets the state to allow external consumers to reuse this instance +// Arguments: +// - +// Return Value: +// - +void AppCommandlineArgs::FullResetState() +{ + _resetStateToDefault(); + + _currentCommandline = nullptr; + _launchMode = std::nullopt; + _startupActions.clear(); + _exitMessage = ""; + _shouldExitEarly = false; +} diff --git a/src/cascadia/TerminalApp/AppCommandlineArgs.h b/src/cascadia/TerminalApp/AppCommandlineArgs.h index 6a7d08b0e7de..984a2b123d69 100644 --- a/src/cascadia/TerminalApp/AppCommandlineArgs.h +++ b/src/cascadia/TerminalApp/AppCommandlineArgs.h @@ -40,6 +40,10 @@ class TerminalApp::AppCommandlineArgs final std::optional GetLaunchMode() const noexcept; + int ParseArgs(const winrt::Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args); + void DisableHelpInExitMessage(); + void FullResetState(); + private: static const std::wregex _commandDelimiterRegex; @@ -80,21 +84,20 @@ class TerminalApp::AppCommandlineArgs final // _commandline will contain the command line with which we'll be spawning a new terminal std::vector _commandline; - const Commandline* _currentCommandline{ nullptr }; - bool _splitVertical{ false }; bool _splitHorizontal{ false }; int _focusTabIndex{ -1 }; bool _focusNextTab{ false }; bool _focusPrevTab{ false }; - - std::optional _launchMode{ std::nullopt }; // Are you adding more args here? Make sure to reset them in _resetStateToDefault + const Commandline* _currentCommandline{ nullptr }; + std::optional _launchMode{ std::nullopt }; std::vector _startupActions; std::string _exitMessage; bool _shouldExitEarly{ false }; + // Are you adding more args or attributes here? If they are not reset in _resetStateToDefault, make sure to reset them in FullResetState winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs _getNewTerminalArgs(NewTerminalSubcommand& subcommand); void _addNewTerminalArgs(NewTerminalSubcommand& subcommand); diff --git a/src/cascadia/TerminalApp/CommandPalette.cpp b/src/cascadia/TerminalApp/CommandPalette.cpp index d1886a40a022..9543b0a1bec0 100644 --- a/src/cascadia/TerminalApp/CommandPalette.cpp +++ b/src/cascadia/TerminalApp/CommandPalette.cpp @@ -6,7 +6,6 @@ #include "TabPaletteItem.h" #include "CommandLinePaletteItem.h" #include "CommandPalette.h" - #include #include "CommandPalette.g.cpp" @@ -99,6 +98,8 @@ namespace winrt::TerminalApp::implementation }); _filteredActionsView().SelectionChanged({ this, &CommandPalette::_selectedCommandChanged }); + + _appArgs.DisableHelpInExitMessage(); } // Method Description: @@ -793,6 +794,35 @@ namespace winrt::TerminalApp::implementation { _noMatchesText().Visibility(Visibility::Collapsed); } + + if (_currentMode == CommandPaletteMode::CommandlineMode) + { + ParsedCommandLineText(L""); + + const auto commandLine = _getTrimmedInput(); + if (!commandLine.empty()) + { + ExecuteCommandlineArgs args{ commandLine }; + _appArgs.FullResetState(); + if (_appArgs.ParseArgs(args) == 0) + { + const auto& commands = _appArgs.GetStartupActions(); + if (commands.size() > 0) + { + std::wstring commandDescription{ RS_(L"CommandPalette_ParsedCommandLine") }; + for (const auto& command : commands) + { + commandDescription += L"\n\t" + command.Args().GenerateName(); + } + ParsedCommandLineText(commandDescription.data()); + } + } + else + { + ParsedCommandLineText(RS_(L"CommandPalette_FailedParsingCommandLine") + L"\n\t" + til::u8u16(_appArgs.GetExitMessage())); + } + } + } } void CommandPalette::_evaluatePrefix() @@ -893,6 +923,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 69b5eb1fba08..07a20f56bb41 100644 --- a/src/cascadia/TerminalApp/CommandPalette.h +++ b/src/cascadia/TerminalApp/CommandPalette.h @@ -5,6 +5,7 @@ #include "FilteredCommand.h" #include "CommandPalette.g.h" +#include "AppCommandlineArgs.h" #include "../../cascadia/inc/cppwinrt_utils.h" // fwdecl unittest classes @@ -54,6 +55,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); TYPED_EVENT(SwitchToTabRequested, winrt::TerminalApp::CommandPalette, winrt::TerminalApp::TabBase); TYPED_EVENT(CommandLineExecutionRequested, winrt::TerminalApp::CommandPalette, winrt::hstring); @@ -128,6 +130,7 @@ namespace winrt::TerminalApp::implementation static constexpr int CommandLineHistoryLength = 10; Windows::Foundation::Collections::IVector _commandLineHistory{ nullptr }; + ::TerminalApp::AppCommandlineArgs _appArgs; friend class TerminalAppLocalTests::TabTests; }; diff --git a/src/cascadia/TerminalApp/CommandPalette.idl b/src/cascadia/TerminalApp/CommandPalette.idl index ac4eebb7b46e..57347ecc6b5c 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 ac41b070c5d3..1926b1b0c607 100644 --- a/src/cascadia/TerminalApp/CommandPalette.xaml +++ b/src/cascadia/TerminalApp/CommandPalette.xaml @@ -31,6 +31,7 @@ the MIT License. See LICENSE in the project root for license information. --> + @@ -69,6 +70,16 @@ the MIT License. See LICENSE in the project root for license information. --> + + + + + +