Skip to content

Commit

Permalink
Introduce parsed command line text to command palette (microsoft#8515)
Browse files Browse the repository at this point in the history
This commit introduces another optional text block in palette that will
be shown in the command line mode (above the history). This text block
will either contain a list of parsed command lines or a description why
the parsing failed

Closes microsoft#8344
Closes microsoft#7284
  • Loading branch information
Don-Vito authored and mpela81 committed Jan 28, 2021
1 parent 8a9e81d commit 395d29c
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 32 deletions.
72 changes: 72 additions & 0 deletions src/cascadia/TerminalApp/AppCommandlineArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -720,3 +720,75 @@ int AppCommandlineArgs::ParseArgs(winrt::array_view<const winrt::hstring>& 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<LPWSTR*, decltype(&::LocalFree), ::LocalFree> argv{ CommandLineToArgvW(args.Commandline().c_str(), &argc) };
if (argv)
{
std::vector<winrt::hstring> 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<const winrt::hstring> argsView{ args };
return ParseArgs(argsView);
}
return 0;
}

// Method Description:
// - Allows disabling addition of help-related info in the exit message
// Arguments:
// - <none>
// Return Value:
// - <none>
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:
// - <none>
// Return Value:
// - <none>
void AppCommandlineArgs::FullResetState()
{
_resetStateToDefault();

_currentCommandline = nullptr;
_launchMode = std::nullopt;
_startupActions.clear();
_exitMessage = "";
_shouldExitEarly = false;
}
11 changes: 7 additions & 4 deletions src/cascadia/TerminalApp/AppCommandlineArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class TerminalApp::AppCommandlineArgs final

std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> GetLaunchMode() const noexcept;

int ParseArgs(const winrt::Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args);
void DisableHelpInExitMessage();
void FullResetState();

private:
static const std::wregex _commandDelimiterRegex;

Expand Down Expand Up @@ -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<std::string> _commandline;

const Commandline* _currentCommandline{ nullptr };

bool _splitVertical{ false };
bool _splitHorizontal{ false };

int _focusTabIndex{ -1 };
bool _focusNextTab{ false };
bool _focusPrevTab{ false };

std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> _launchMode{ std::nullopt };
// Are you adding more args here? Make sure to reset them in _resetStateToDefault

const Commandline* _currentCommandline{ nullptr };
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> _launchMode{ std::nullopt };
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _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);
Expand Down
33 changes: 32 additions & 1 deletion src/cascadia/TerminalApp/CommandPalette.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include "TabPaletteItem.h"
#include "CommandLinePaletteItem.h"
#include "CommandPalette.h"

#include <LibraryResources.h>

#include "CommandPalette.g.cpp"
Expand Down Expand Up @@ -99,6 +98,8 @@ namespace winrt::TerminalApp::implementation
});

_filteredActionsView().SelectionChanged({ this, &CommandPalette::_selectedCommandChanged });

_appArgs.DisableHelpInExitMessage();
}

// Method Description:
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/TerminalApp/CommandPalette.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "FilteredCommand.h"
#include "CommandPalette.g.h"
#include "AppCommandlineArgs.h"
#include "../../cascadia/inc/cppwinrt_utils.h"

// fwdecl unittest classes
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -128,6 +130,7 @@ namespace winrt::TerminalApp::implementation

static constexpr int CommandLineHistoryLength = 10;
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _commandLineHistory{ nullptr };
::TerminalApp::AppCommandlineArgs _appArgs;

friend class TerminalAppLocalTests::TabTests;
};
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/CommandPalette.idl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace TerminalApp
String PrefixCharacter { get; };
String ControlName { get; };
String ParentCommandName { get; };
String ParsedCommandLineText { get; };

Windows.Foundation.Collections.IObservableVector<FilteredCommand> FilteredActions { get; };

Expand Down
40 changes: 40 additions & 0 deletions src/cascadia/TerminalApp/CommandPalette.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ the MIT License. See LICENSE in the project root for license information. -->

<!-- This creates an instance of our CommandKeyChordVisibilityConverter we can reference below -->
<local:EmptyStringVisibilityConverter x:Key="CommandKeyChordVisibilityConverter"/>
<local:EmptyStringVisibilityConverter x:Key="ParsedCommandLineTextVisibilityConverter"/>
<local:EmptyStringVisibilityConverter x:Key="ParentCommandVisibilityConverter"/>
<local:HasNestedCommandsVisibilityConverter x:Key="HasNestedCommandsVisibilityConverter"/>
<model:IconPathConverter x:Key="IconSourceConverter"/>
Expand Down Expand Up @@ -69,6 +70,16 @@ the MIT License. See LICENSE in the project root for license information. -->
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>

<!-- ParsedCommandLineText styles -->
<Style x:Key="ParsedCommandLineBorderStyle" TargetType="Border">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="1" />
<Setter Property="Background" Value="{ThemeResource SystemAltMediumLowColor}" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>
<Style x:Key="ParsedCommandLineTextBlockStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<Style x:Key="CommandPaletteBackground" TargetType="Grid">
Expand Down Expand Up @@ -100,6 +111,16 @@ the MIT License. See LICENSE in the project root for license information. -->
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>

<!-- ParsedCommandLineText styles -->
<Style x:Key="ParsedCommandLineBorderStyle" TargetType="Border">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="1" />
<Setter Property="Background" Value="{ThemeResource SystemAltMediumLowColor}" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>
<Style x:Key="ParsedCommandLineTextBlockStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
</Style>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<Style x:Key="CommandPaletteBackground" TargetType="Grid">
Expand All @@ -110,6 +131,9 @@ the MIT License. See LICENSE in the project root for license information. -->
<Style x:Key="KeyChordBorderStyle" TargetType="Border"/>
<Style x:Key="KeyChordTextBlockStyle" TargetType="TextBlock"/>

<!-- ParsedCommandLineText styles (use XAML defaults for High Contrast theme) -->
<Style x:Key="ParsedCommandLineBoderStyle" TargetType="Border"/>
<Style x:Key="ParsedCommandLineTextBlockStyle" TargetType="TextBlock"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
Expand Down Expand Up @@ -228,6 +252,22 @@ the MIT License. See LICENSE in the project root for license information. -->
Text="{x:Bind NoMatchesText, Mode=OneWay}">
</TextBlock>

<Border
Grid.Row="1"
Visibility="{x:Bind ParsedCommandLineText, Mode=OneWay, Converter={StaticResource ParsedCommandLineTextVisibilityConverter}}"
Style="{ThemeResource ParsedCommandLineBorderStyle}"
Padding="16"
HorizontalAlignment="Stretch"
VerticalAlignment="Center">

<ScrollViewer MaxHeight="200" VerticalScrollBarVisibility="Auto">
<TextBlock
FontStyle="Italic"
TextWrapping="Wrap"
Text="{x:Bind ParsedCommandLineText, Mode=OneWay}"/>
</ScrollViewer>
</Border>

<ListView
Grid.Row="2"
x:Name="_filteredActionsView"
Expand Down
9 changes: 8 additions & 1 deletion src/cascadia/TerminalApp/Resources/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,13 @@
<data name="CommandPalette_NoMatchesText.Text" xml:space="preserve">
<value>No matching commands</value>
</data>
<data name="CommandPalette_ParsedCommandLine" xml:space="preserve">
<value>Executing command line will invoke the following commands:</value>
<comment>Will be followed by a list of strings describing parsed commands</comment>
</data>
<data name="CommandPalette_FailedParsingCommandLine" xml:space="preserve">
<value>Failed parsing command line:</value>
</data>
<data name="CommandPaletteControlName" xml:space="preserve">
<value>Command Palette</value>
</data>
Expand Down Expand Up @@ -513,4 +520,4 @@
<data name="NoticeWarning" xml:space="preserve">
<value>Warning</value>
</data>
</root>
</root>
29 changes: 3 additions & 26 deletions src/cascadia/TerminalApp/TerminalPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2698,35 +2698,12 @@ namespace winrt::TerminalApp::implementation
// - an empty list if we failed to parse, otherwise a list of actions to execute.
std::vector<ActionAndArgs> TerminalPage::ConvertExecuteCommandlineToActions(const ExecuteCommandlineArgs& args)
{
if (!args || args.Commandline().empty())
::TerminalApp::AppCommandlineArgs appArgs;
if (appArgs.ParseArgs(args) == 0)
{
return {};
return appArgs.GetStartupActions();
}
// 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<LPWSTR*, decltype(&::LocalFree), ::LocalFree> argv{ CommandLineToArgvW(args.Commandline().c_str(), &argc) };
if (argv)
{
std::vector<winrt::hstring> 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<const winrt::hstring> argsView{ args };

::TerminalApp::AppCommandlineArgs appArgs;
if (appArgs.ParseArgs(argsView) == 0)
{
return appArgs.GetStartupActions();
}
}
return {};
}

Expand Down

0 comments on commit 395d29c

Please sign in to comment.