Repository: microsoft/terminal (language: cpp)

Issue:
Feature Request - Scripts Panel
Type the same commands multiple times or using external files from the terminal application to launch scripts. This feature would solve the problem of users alt tabbing allot of the time to run scripts where it could be in built in the terminal as an added option to make a side panel appear or something similar to that to show scripts and run them.

I want a panel to have toggle or an additional option so you can have a panel or something similar to be attached to the terminal so that you can run scripts from terminal and do not have to go into windows and search for scripts. This would kind of be like the the powershell ISE commands panel that you can toggle on but it would be for multiple terminals and you can set what you want to run their and the commands or scripts that you run all the time. 


![PowerShell ISE](https://user-images.githubusercontent.com/43774713/60091968-25ae3b80-9789-11e9-8f18-3cae8e1f3486.PNG)




Discussion / hints:
panes are comimg into the terminal soon, well its already within the code, its just unfinished
#1000
Actually, I'm gonna re-open this. This is a not terrible idea for an extension, similar to #644
Adding some other comments from other duped threads:


_@ThatWionGuy in #5273_:

> There are many commands that I either use frequently and some I use only once and a while but not frequently enough to memorize them. It would be nice if there was a way to store these and then access them from the terminal app to be executed when needed. A perfect example of this is the command to see all globally installed npm packages:
> 
> ```shell
> npm list -g --depth 0
> ```
> 
> I do this at least once a month which is just long enough to forget the exact line, so then I have to open Google and search for the command again, copy it and paste it into the terminal, which takes up time I should be using for other things.
> 
> The best way to keep a user engaged is to keep them from having to leave your app. By providing a way to quickly execute commands inside the terminal app, you allow users to be more productive and spend less time changing apps.
> 
> ## General Idea
> What I am thinking would be an aside on the left or right of the window. Would be hidden by default but able to be shown through the main menu or keyboard shortcut. Could be called Favorites, Shortcuts or Quick List the naming is completely up to you, but for consistency and ease of explanation I will refer to it as "favorites" through the rest of this proposal.
> 
> It would display these favorite commands where the user could just click on one of them and the app would input the command into the active terminal. The panel would be scoped to the current active terminal i.e. a cmd terminal would show the favorites for cmd, and if the user switched to a powershell terminal then the favorites would switch to powershell favorites.
> 
> ![windows-terminal-favorites](https://user-images.githubusercontent.com/3865442/78712096-b0f25b00-78dd-11ea-81f0-dae798174f32.png)
> _Image is a wireframe not a polished UI_
> 
> # Proposed technical implementation details (optional)
> Management of these favorites could be accomplished in the profiles section of the settings file, so no need to make a fancy GUI to manage the favorites. It could be structured something like this:
> 
> ```json
> ...
> "profiles" : 
>     [
>         {
>             ...,
>             "favorites" : [
>                  {
>                      "name" : "List global npm packages",
>                      "command" : "npm list -g --depth 0",
>                      "auto-run" : false
>                  }
>             ],
>         },
>         ...
>     ]
>     ...
> }
> ```
> 
> Property	Type	Usage
> name	string	What shows up in the aside panel
> command	string	What to inject into the terminal when clicked
> auto-run (optional)	boolean	Whether to run the command or just input into the terminal. Default to false.
> Since the user enters them in the profile settings there is no need to manage whether the command is actually a windows cmd, valid powershell or valid bash command... it is up to the user to put the favorites into the correct profile, correct order and to put valid commands. Terminal app would just display the list of favorites sorted by array order, based on the currently active profile and inject/execute the commands when they were clicked. Also since they are defined in the profiles the look and feel of the aside could match the profiles theme.
> 
> There would also need to be some kind of message to display if there are no current favorites for a profile. Something like "You currently have no favorites for this profile." and maybe a link to add a favorite which would open the settings file with a new favorite stubbed out.
> 
> The injection/execution could easily be accomplished in a variety of ways depending on the level of access to the underlying terminal that the app has (I will be honest, I have not looked into the code a lot) But even if you had to do it via sending the keystrokes to the underlying terminal and if `auto-run` is true sending a Enter Key at the end would be basically no different than the app typing the command for the user.
> 
> I am really not trying to completely design it out for you... just trying to give a general feature proposal so if you think of a better design and do it completely different I would not be offended, just wish that a feature like this existed.
> 
> # Possible future enhancements
> Initially just displaying the list, allowing injection/execution of the commands on click and management through the settings would allow this feature to be functional and useful to users. But if desired, future enhancements could be added that would only provide better usability such as:
> 
> * Change sort order by drag and drop in aside.
> * Add new favorite via GUI (Dialog, or integrated UI)
> * Add new favorite from last executed command.
> * Group Commands into collapsible sections for better organization.
> * Support executing multiple commands on a single click.
> 
> Again these would be nice to haves later, but in no way necessary to provide a usable feature that provides value to the user.

<hr>
_ @zadjii-msft in #5273 _:

> I think this is an _excellent_ extension idea. It's actually something I've been toying around with for a long time, but you've actually written up lots of the ideas I've had 😅.
> 
> I'm going to mark this up as an extension, and toss it onto the backlog.
> 
> <shameless self-plug>
> I've personally been working on a tool that does a lot of similar things to what you're requesting, just straight from the commandline as opposed to as a part of the UI. 
![image](https://user-images.githubusercontent.com/18356694/78796811-75f33480-797c-11ea-8811-aad5c7671206.png)
> 
> You can check it out over at [zadjii/keep](https://github.com/zadjii/keep). Admittedly, I only update it when I feel the itch, and it only works for CMD, but it works for me ¯\\\_(ツ)_/¯
> 
> </shameless self-plug>
> 
> My own personal goal is to get the Terminal to a place where I can integrate a bunch of the features from that helper tool more directly into the UI. I've been thinking of doing it with a combination of:
> 
> * [Scenario: Add support for 3rd-party extensions #4000](https://github.com/microsoft/terminal/issues/4000) - to support extensions at all
> * [Feature Request: Command Palette #2046](https://github.com/microsoft/terminal/issues/2046) - to provide a UI for running these commands easily
> * #I-cant-remember-which - to use a `ShortcutAction` to send input to the attached commandline app
> 
> One way or not, this is an excellent addition to my collection of extension ideas. Thanks!


<hr>
_ @MrGolden1 in #11270 _:

> I think this is very useful that there would be an option for saved commands/scripts in windows terminal.
> 
> for instance I need to ssh to a server several times a day or set a vpn at beginning of my work. or there is maybe many commands that we use hardly and we don't memorize them, such as resting database, special git command, changing an option in OS and many other things ....
> It would be great if we could pick the command we want from an easy accessible place inside of windows terminal. Add, remove, titling, editing before run, pin, most recent and most used commands can be good options for it too.
> 
> # Proposed technical implementation details (optional)
> This picture is just for visualize my idea. (I found nothing better than windows clipboard :))
> ![image](https://user-images.githubusercontent.com/41590281/133887525-6bfb8bce-d8f4-4093-9e72-1aa8c09fa3d5.png)
> 
> There is a panel such this that commands are listed in.
> 
> Thanks in advanced.


The 'scripts panel' that starts this thread is great for indexing/retaining/invoking a massive library of scripts. Later suggestions are closer to my needs: frequently accessing a (more limited, but commonly used) set of commands or executables (batch files/shell scripts/python/etc.).

I'd like to see one step further in terms of simplification (since UI elements is on the roadmap for extensions): a generic toolbar which contains 'buttons' that are linked to specific commands or executables. The profile structure suggested in #5273 could be extended to support the configuration of the toolbar (also add an 'icon' for quick & easy locating of specific buttons). I'm thinking the end result would be something akin to Chrome's 'Bookmarks' toolbar. Once defined, your favorite commands are one click away! 

As a next-level of difficulty, other elements could be added to add variability to toolbar items, such as a listbox to select one of several 'user profiles' when logging into ssh, or a textbox to enter a variable to pass on the command line to the script invoked by the associated button, etc.
>  I'm thinking the end result would be something akin to Chrome's 'Bookmarks' toolbar

I think we've actually got a good mental model on the team (if albeit not formally communicated) of how this is going to end up working. We've got our plan for action ID's, and customizing the dropdown with those action IDs (#1571). The "bookmarks bar" would just be the same kind of thing, with different UI. It's just another place that users can bind actions to a button. So opening specific profiles, running commands, all those could be bound to those buttons. (see also #2934, #4531)

<hr>

Moving some relevant discussion from #6412:

> I think there is important point that everyone is missing when telling us to rely on the shell completion functions. I want to be able to use snippets that are independent of the shell configuration. As an example, I often run awk '{ print $1 }' | while read... on server where I cannot create aliases or change any config, I would like to be able to type in 'a$1' for example and expand it to the predefined snippet. I'm often connecting to the systems where the completion is fully disabled and I run a lot of repetitive task that can't be scripted (terminal hijacking is always disabled). I'm really convinced this is a needed feature.


> You could also theoretically create a command like:
> 
> ```js
> { "command": { "action": "sendInput", "input": "awk '{ print $1 }' | while read...\r" }, "keys":"ctrl+a", "name": "a$1" },
> ```
> 
> and then you could use the command palette to send that snippet really simply. So you'd just press <kbd>Ctrl+Shift+P</kbd> (to open the command palette),<kbd>a</kbd>,<kbd>$</kbd>,<kbd>1</kbd>,<kbd>enter</kbd> and it'd send that snippet to the terminal. Or leave out the `\r` to just input it on the prompt, but not submit. Kinda similar, and shell/backend agnostic. 



Fix patch:
diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json
index c681ef29267..50a8a6a854f 100644
--- a/doc/cascadia/profiles.schema.json
+++ b/doc/cascadia/profiles.schema.json
@@ -85,6 +85,32 @@
         }
       ]
     },
+    "BuiltinSuggestionSource": {
+      "enum": [
+        "commandHistory",
+        "tasks",
+        "all"
+      ],
+      "type": "string"
+    },
+    "SuggestionSource": {
+      "default": "all",
+      "description": "Either a single suggestion source, or an array of sources to concatenate. Built-in sources include `commandHistory`, `directoryHistory`, and `tasks`. The special value `all` indicates all suggestion sources should be included",
+      "$comment": "`tasks` and `local` are sources that would be added by the Tasks feature, as a follow-up",
+      "oneOf": [
+        {
+          "type": [ "string", "null", "BuiltinSuggestionSource" ]
+        },
+        {
+          "type": "array",
+          "items": { "type": "BuiltinSuggestionSource" }
+        },
+        {
+          "type": "array",
+          "items": { "type": "string" }
+        }
+      ]
+    },
     "AppearanceConfig": {
       "properties": {
         "colorScheme": {
@@ -398,6 +424,7 @@
         "sendInput",
         "setColorScheme",
         "setTabColor",
+        "showSuggestions",
         "splitPane",
         "switchToTab",
         "tabSearch",
@@ -1767,6 +1794,30 @@
         }
       ]
     },
+    "ShowSuggestionsAction": {
+      "description": "Arguments corresponding to a Open Suggestions Action",
+      "allOf": [
+        {
+          "$ref": "#/$defs/ShortcutAction"
+        },
+        {
+          "properties": {
+            "action": {
+              "type": "string",
+              "const": "showSuggestions"
+            },
+            "source": {
+              "$ref": "#/$defs/SuggestionSource",
+              "description": "Which suggestion sources to filter."
+            },
+            "useCommandline": {
+              "default": false,
+              "description": "When set to `true`, the current commandline the user has typed will pre-populate the filter of the Suggestions UI. This requires that the user has enabled shell integration in their shell's config. When set to false, the filter will start empty."
+            }
+          }
+        }
+      ]
+    },
     "ShowCloseButton": {
       "enum": [
         "always",
@@ -2037,6 +2088,9 @@
             {
               "$ref": "#/$defs/SearchWebAction"
             },
+            {
+              "$ref": "#/$defs/ShowSuggestionsAction"
+            },
             {
               "type": "null"
             }
diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp
index a65c3ddbab0..2fefc40aae4 100644
--- a/src/cascadia/TerminalApp/AppActionHandlers.cpp
+++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp
@@ -1264,25 +1264,62 @@ namespace winrt::TerminalApp::implementation
         {
             if (const auto& realArgs = args.ActionArgs().try_as<SuggestionsArgs>())
             {
-                auto source = realArgs.Source();
-
-                switch (source)
-                {
-                case SuggestionsSource::CommandHistory:
+                const auto source = realArgs.Source();
+                std::vector<Command> commandsCollection;
+                Control::CommandHistoryContext context{ nullptr };
+                winrt::hstring currentCommandline = L"";
+
+                // If the user wanted to use the current commandline to filter results,
+                //    OR they wanted command history (or some other source that
+                //       requires context from the control)
+                // then get that here.
+                const bool shouldGetContext = realArgs.UseCommandline() ||
+                                              WI_IsFlagSet(source, SuggestionsSource::CommandHistory);
+                if (shouldGetContext)
                 {
                     if (const auto& control{ _GetActiveControl() })
                     {
-                        const auto context = control.CommandHistory();
-                        const auto& currentCmd{ realArgs.UseCommandline() ? context.CurrentCommandline() : L"" };
-                        _OpenSuggestions(control,
-                                         Command::HistoryToCommands(context.History(), currentCmd, false),
-                                         SuggestionsMode::Palette,
-                                         currentCmd);
+                        context = control.CommandHistory();
+                        if (context)
+                        {
+                            currentCommandline = context.CurrentCommandline();
+                        }
                     }
-                    args.Handled(true);
                 }
-                break;
+
+                // Aggregate all the commands from the different sources that
+                // the user selected.
+
+                // Tasks are all the sendInput commands the user has saved in
+                // their settings file. Ask the ActionMap for those.
+                if (WI_IsFlagSet(source, SuggestionsSource::Tasks))
+                {
+                    const auto tasks = _settings.GlobalSettings().ActionMap().FilterToSendInput(currentCommandline);
+                    for (const auto& t : tasks)
+                    {
+                        commandsCollection.push_back(t);
+                    }
                 }
+
+                // Command History comes from the commands in the buffer,
+                // assuming the user has enabled shell integration. Get those
+                // from the active control.
+                if (WI_IsFlagSet(source, SuggestionsSource::CommandHistory) &&
+                    context != nullptr)
+                {
+                    const auto recentCommands = Command::HistoryToCommands(context.History(), currentCommandline, false);
+                    for (const auto& t : recentCommands)
+                    {
+                        commandsCollection.push_back(t);
+                    }
+                }
+
+                // Open the palette with all these commands in it.
+                _OpenSuggestions(_GetActiveControl(),
+                                 winrt::single_threaded_vector<Command>(std::move(commandsCollection)),
+                                 SuggestionsMode::Palette,
+                                 currentCommandline);
+                args.Handled(true);
             }
         }
     }
diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp
index 1088ee27852..b2247321d5f 100644
--- a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp
+++ b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp
@@ -709,23 +709,42 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
 
     winrt::hstring SuggestionsArgs::GenerateName() const
     {
-        auto base{ RS_(L"SuggestionsCommandKey") };
-        switch (Source())
+        std::wstringstream ss;
+        ss << RS_(L"SuggestionsCommandKey").c_str();
+
+        if (UseCommandline())
         {
-        case SuggestionsSource::CommandHistory:
-            base = RS_(L"SuggestionsCommandHistoryCommandKey");
+            ss << L", useCommandline:true";
         }
 
-        if (UseCommandline())
+        // All of the source values will leave a trailing ", " that we need to chop later:
+        ss << L", source: ";
+        const auto source = Source();
+        if (source == SuggestionsSource::All)
         {
-            return winrt::hstring{
-                fmt::format(L"{}, useCommandline:true", std::wstring_view(base))
-            };
+            ss << L"all, ";
+        }
+        else if (source == static_cast<SuggestionsSource>(0))
+        {
+            ss << L"none, ";
         }
         else
         {
-            return base;
+            if (WI_IsFlagSet(source, SuggestionsSource::Tasks))
+            {
+                ss << L"tasks, ";
+            }
+
+            if (WI_IsFlagSet(source, SuggestionsSource::CommandHistory))
+            {
+                ss << L"commandHistory, ";
+            }
         }
+        // Chop off the last ","
+        auto result = ss.str();
+        // use `resize`, to avoid duplicating the entire string. (substr doesn't create a view.)
+        result.resize(result.size() - 2);
+        return winrt::hstring{ result };
     }
 
     winrt::hstring FindMatchArgs::GenerateName() const
diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl
index 936165b8b28..d38e3011281 100644
--- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl
+++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl
@@ -112,11 +112,14 @@ namespace Microsoft.Terminal.Settings.Model
         ToCurrent,
         ToMouse,
     };
+
+    [flags]
     enum SuggestionsSource
     {
-        Tasks,
-        CommandHistory,
-        DirectoryHistory,
+        Tasks = 0x1,
+        CommandHistory = 0x2,
+        DirectoryHistory = 0x4,
+        All = 0xffffffff,
     };
 
     [default_interface] runtimeclass NewTerminalArgs {
diff --git a/src/cascadia/TerminalSettingsModel/ActionMap.cpp b/src/cascadia/TerminalSettingsModel/ActionMap.cpp
index b2c78970d45..76565dff444 100644
--- a/src/cascadia/TerminalSettingsModel/ActionMap.cpp
+++ b/src/cascadia/TerminalSettingsModel/ActionMap.cpp
@@ -931,4 +931,72 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
     {
         return _ExpandedCommandsCache;
     }
+
+    IVector<Model::Command> _filterToSendInput(IMapView<hstring, Model::Command> nameMap,
+                                               winrt::hstring currentCommandline)
+    {
+        auto results = winrt::single_threaded_vector<Model::Command>();
+
+        const auto numBackspaces = currentCommandline.size();
+        // Helper to clone a sendInput command into a new Command, with the
+        // input trimmed to account for the currentCommandline
+        auto createInputAction = [&](const Model::Command& command) -> Model::Command {
+            winrt::com_ptr<implementation::Command> cmdImpl;
+            cmdImpl.copy_from(winrt::get_self<implementation::Command>(command));
+
+            const auto inArgs{ command.ActionAndArgs().Args().try_as<Model::SendInputArgs>() };
+
+            auto args = winrt::make_self<SendInputArgs>(
+                winrt::hstring{ fmt::format(FMT_COMPILE(L"{:\x7f^{}}{}"),
+                                            L"",
+                                            numBackspaces,
+                                            (std::wstring_view)(inArgs ? inArgs.Input() : L"")) });
+            Model::ActionAndArgs actionAndArgs{ ShortcutAction::SendInput, *args };
+
+            auto copy = cmdImpl->Copy();
+            copy->ActionAndArgs(actionAndArgs);
+
+            return *copy;
+        };
+
+        // iterate over all the commands in all our actions...
+        for (auto&& [name, command] : nameMap)
+        {
+            // If this is not a nested command, and it's a sendInput command...
+            if (!command.HasNestedCommands() &&
+                command.ActionAndArgs().Action() == ShortcutAction::SendInput)
+            {
+                // copy it into the results.
+                results.Append(createInputAction(command));
+            }
+            // If this is nested...
+            else if (command.HasNestedCommands())
+            {
+                // Look for any sendInput commands nested underneath us
+                auto innerResults = _filterToSendInput(command.NestedCommands(), currentCommandline);
+
+                if (innerResults.Size() > 0)
+                {
+                    // This command did have at least one sendInput under it
+
+                    // Create a new Command, which is a copy of this Command,
+                    // which only has SendInputs in it
+                    winrt::com_ptr<implementation::Command> cmdImpl;
+                    cmdImpl.copy_from(winrt::get_self<implementation::Command>(command));
+                    auto copy = cmdImpl->Copy();
+                    copy->NestedCommands(innerResults.GetView());
+
+                    results.Append(*copy);
+                }
+            }
+        }
+
+        return results;
+    }
+
+    IVector<Model::Command> ActionMap::FilterToSendInput(
+        winrt::hstring currentCommandline)
+    {
+        return _filterToSendInput(NameMap(), currentCommandline);
+    }
 }
diff --git a/src/cascadia/TerminalSettingsModel/ActionMap.h b/src/cascadia/TerminalSettingsModel/ActionMap.h
index 95ab9e9ab7f..4270a081118 100644
--- a/src/cascadia/TerminalSettingsModel/ActionMap.h
+++ b/src/cascadia/TerminalSettingsModel/ActionMap.h
@@ -79,6 +79,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
         void ExpandCommands(const Windows::Foundation::Collections::IVectorView<Model::Profile>& profiles,
                             const Windows::Foundation::Collections::IMapView<winrt::hstring, Model::ColorScheme>& schemes);
 
+        winrt::Windows::Foundation::Collections::IVector<Model::Command> FilterToSendInput(winrt::hstring currentCommandline);
+
     private:
         std::optional<Model::Command> _GetActionByID(const InternalActionID actionID) const;
         std::optional<Model::Command> _GetActionByKeyChordInternal(const Control::KeyChord& keys) const;
diff --git a/src/cascadia/TerminalSettingsModel/ActionMap.idl b/src/cascadia/TerminalSettingsModel/ActionMap.idl
index 99df487263b..b84305b9d0e 100644
--- a/src/cascadia/TerminalSettingsModel/ActionMap.idl
+++ b/src/cascadia/TerminalSettingsModel/ActionMap.idl
@@ -22,6 +22,8 @@ namespace Microsoft.Terminal.Settings.Model
         Windows.Foundation.Collections.IMapView<Microsoft.Terminal.Control.KeyChord, Command> GlobalHotkeys { get; };
 
         IVector<Command> ExpandedCommands { get; };
+
+        IVector<Command> FilterToSendInput(String CurrentCommandline);
     };
 
     [default_interface] runtimeclass ActionMap : IActionMapView
diff --git a/src/cascadia/TerminalSettingsModel/Command.cpp b/src/cascadia/TerminalSettingsModel/Command.cpp
index 63d4e2dea6e..b211987b677 100644
--- a/src/cascadia/TerminalSettingsModel/Command.cpp
+++ b/src/cascadia/TerminalSettingsModel/Command.cpp
@@ -64,6 +64,16 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
         return _subcommands ? _subcommands.GetView() : nullptr;
     }
 
+    void Command::NestedCommands(const Windows::Foundation::Collections::IVectorView<Model::Command>& nested)
+    {
+        _subcommands = winrt::single_threaded_map<winrt::hstring, Model::Command>();
+
+        for (const auto& n : nested)
+        {
+            _subcommands.Insert(n.Name(), n);
+        }
+    }
+
     // Function Description:
     // - reports if the current command has nested commands
     // - This CANNOT detect { "name": "foo", "commands": null }
@@ -752,7 +762,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
         // Iterate in reverse over the history, so that most recent commands are first
         for (auto i = history.Size(); i > 0; i--)
         {
-            std::wstring_view line{ history.GetAt(i - 1) };
+            const auto& element{ history.GetAt(i - 1) };
+            std::wstring_view line{ element };
 
             if (line.empty())
             {
diff --git a/src/cascadia/TerminalSettingsModel/Command.h b/src/cascadia/TerminalSettingsModel/Command.h
index 59a080c4c0a..41037bf1a29 100644
--- a/src/cascadia/TerminalSettingsModel/Command.h
+++ b/src/cascadia/TerminalSettingsModel/Command.h
@@ -52,6 +52,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
         bool HasNestedCommands() const;
         bool IsNestedCommand() const noexcept;
         Windows::Foundation::Collections::IMapView<winrt::hstring, Model::Command> NestedCommands() const;
+        void NestedCommands(const Windows::Foundation::Collections::IVectorView<Model::Command>& nested);
 
         bool HasName() const noexcept;
         hstring Name() const noexcept;
diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw
index 887d523fb0e..74035df755d 100644
--- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw
+++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
 <root>
-  <!--
-    Microsoft ResX Schema
-
+  <!-- 
+    Microsoft ResX Schema 
+    
     Version 2.0
-
-    The primary goals of this format is to allow a simple XML format
-    that is mostly human readable. The generation and parsing of the
-    various data types are done through the TypeConverter classes
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
     associated with the data types.
-
+    
     Example:
-
+    
     ... ado.net/XML headers & schema ...
     <resheader name="resmimetype">text/microsoft-resx</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>
         <comment>This is a comment</comment>
     </data>
-
-    There are any number of "resheader" rows that contain simple
+                
+    There are any number of "resheader" rows that contain simple 
     name/value pairs.
-
-    Each data row contains a name, and value. The row also contains a
-    type or mimetype. Type corresponds to a .NET class that support
-    text/value conversion through the TypeConverter architecture.
-    Classes that don't support this are serialized and stored with the
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
     mimetype set.
-
-    The mimetype is used for serialized objects, and tells the
-    ResXResourceReader how to depersist the object. This is currently not
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
     extensible. For a given mimetype the value must be set accordingly:
-
-    Note - application/x-microsoft.net.object.binary.base64 is the format
-    that the ResXResourceWriter will generate, however the reader can
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
     read any of the formats listed below.
-
+    
     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
             : and then encoded with base64 encoding.
-
+    
     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
             : and then encoded with base64 encoding.
 
     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
             : and then encoded with base64 encoding.
     -->
diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h
index 73af3411e2d..0dc91e30b11 100644
--- a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h
+++ b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h
@@ -499,12 +499,14 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::FindMatchDirecti
     };
 };
 
-JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::SuggestionsSource)
+JSON_FLAG_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::SuggestionsSource)
 {
-    JSON_MAPPINGS(3) = {
+    static constexpr std::array<pair_type, 5> mappings = {
+        pair_type{ "none", AllClear },
         pair_type{ "tasks", ValueType::Tasks },
         pair_type{ "commandHistory", ValueType::CommandHistory },
-        pair_type{ "directoryHistory", ValueType::DirectoryHistory }
+        pair_type{ "directoryHistory", ValueType::DirectoryHistory },
+        pair_type{ "all", AllSet },
     };
 };
 


Test patch: