1919#if TIL_FEATURE_DYNAMICSSHPROFILES_ENABLED
2020#include " SshHostGenerator.h"
2121#endif
22+ #include " PowershellInstallationProfileGenerator.h"
2223
2324#include " ApplicationState.h"
2425#include " DefaultTerminal.h"
@@ -209,26 +210,58 @@ Json::StreamWriterBuilder SettingsLoader::_getJsonStyledWriter()
209210// (meaning profiles specified by the application rather by the user).
210211void SettingsLoader::GenerateProfiles ()
211212{
212- auto generateProfiles = [&](const IDynamicProfileGenerator& generator) {
213+ auto generateProfiles = [&](IDynamicProfileGenerator& generator) {
213214 if (!_ignoredNamespaces.contains (generator.GetNamespace ()))
214215 {
215216 _executeGenerator (generator, inboxSettings.profiles );
216217 }
217218 };
218219
219- generateProfiles (PowershellCoreProfileGenerator{});
220- generateProfiles (WslDistroGenerator{});
221- generateProfiles (AzureCloudShellGenerator{});
222- generateProfiles (VisualStudioGenerator{});
220+ {
221+ PowershellCoreProfileGenerator powerShellGenerator{};
222+ generateProfiles (powerShellGenerator);
223+
224+ if (Feature_PowerShellInstallerProfileGenerator::IsEnabled ())
225+ {
226+ if (!powerShellGenerator.GetPowerShellInstances ().empty ())
227+ {
228+ // If PowerShell is installed, mark the installer profile for deletion
229+ const winrt::guid profileGuid{ L" {965a10f2-b0f2-55dc-a3c2-2ddbf639bf89}" };
230+ for (const auto & profile : userSettings.profiles )
231+ {
232+ if (profile->Guid () == profileGuid)
233+ {
234+ profile->Deleted (true );
235+ break ;
236+ }
237+ }
238+ }
239+ else
240+ {
241+ // Only generate the installer stub profile if PowerShell isn't installed.
242+ PowershellInstallationProfileGenerator pwshInstallationGenerator{};
243+ generateProfiles (pwshInstallationGenerator);
244+ }
245+ }
246+ }
247+ WslDistroGenerator wslGenerator{};
248+ generateProfiles (wslGenerator);
249+
250+ AzureCloudShellGenerator acsGenerator{};
251+ generateProfiles (acsGenerator);
252+
253+ VisualStudioGenerator vsGenerator{};
254+ generateProfiles (vsGenerator);
223255#if TIL_FEATURE_DYNAMICSSHPROFILES_ENABLED
224- generateProfiles (SshHostGenerator{});
256+ SshHostGenerator sshGenerator{};
257+ generateProfiles (sshGenerator);
225258#endif
226259}
227260
228261// Generate ExtensionPackage objects from the profile generators.
229262void SettingsLoader::GenerateExtensionPackagesFromProfileGenerators ()
230263{
231- auto generateExtensionPackages = [&](const IDynamicProfileGenerator& generator) {
264+ auto generateExtensionPackages = [&](IDynamicProfileGenerator& generator) {
232265 std::vector<winrt::com_ptr<implementation::Profile>> profilesList;
233266 _executeGenerator (generator, profilesList);
234267
@@ -255,17 +288,60 @@ void SettingsLoader::GenerateExtensionPackagesFromProfileGenerators()
255288 extPkg->Icon (hstring{ generator.GetIcon () });
256289 };
257290
258- // TODO CARLOS: is there a way to deduplicate this list?
259- // Is it even worth it if we're adding special logic for the PwshInstallerGenerator PR?
260- generateExtensionPackages (PowershellCoreProfileGenerator{});
261- generateExtensionPackages (WslDistroGenerator{});
262- generateExtensionPackages (AzureCloudShellGenerator{});
263- generateExtensionPackages (VisualStudioGenerator{});
291+ PowershellCoreProfileGenerator powerShellGenerator{};
292+ generateExtensionPackages (powerShellGenerator);
293+
294+ if (Feature_PowerShellInstallerProfileGenerator::IsEnabled ())
295+ {
296+ PowershellInstallationProfileGenerator pwshInstallationGenerator{};
297+ generateExtensionPackages (pwshInstallationGenerator);
298+ _patchInstallPowerShellProfile ();
299+ }
300+
301+ WslDistroGenerator wslGenerator{};
302+ generateExtensionPackages (wslGenerator);
303+
304+ AzureCloudShellGenerator acsGenerator{};
305+ generateExtensionPackages (acsGenerator);
306+
307+ VisualStudioGenerator vsGenerator{};
308+ generateExtensionPackages (vsGenerator);
264309#if TIL_FEATURE_DYNAMICSSHPROFILES_ENABLED
265- generateExtensionPackages (SshHostGenerator{});
310+ SshHostGenerator sshGenerator{};
311+ generateExtensionPackages (sshGenerator);
266312#endif
267313}
268314
315+ // Retrieve the "Install Latest PowerShell" profile and add a comment to the JSON to indicate it's conditionally applied
316+ void SettingsLoader::_patchInstallPowerShellProfile ()
317+ {
318+ const hstring pwshInstallerNamespace{ PowershellInstallationProfileGenerator::Namespace };
319+ if (extensionPackageMap.contains (pwshInstallerNamespace))
320+ {
321+ if (const auto & fragExtList = extensionPackageMap[pwshInstallerNamespace]->Fragments (); fragExtList.Size () > 0 )
322+ {
323+ auto fragExt = get_self<FragmentSettings>(fragExtList.GetAt (0 ));
324+
325+ // We want the comment to be the first thing in the object,
326+ // "closeOnExit" is the first property, so target that.
327+ auto fragExtJson = _parseJSON (til::u16u8 (fragExt->Json ()));
328+ fragExtJson[JsonKey (ProfilesKey)][0 ][" closeOnExit" ].setComment (til::u16u8 (fmt::format (FMT_COMPILE (L" // {}" ), RS_ (L" PowerShellInstallationProfileJsonComment" ))), Json::CommentPlacement::commentBefore);
329+ fragExt->Json (hstring{ til::u8u16 (Json::writeString (_getJsonStyledWriter (), fragExtJson)) });
330+
331+ if (const auto & profileEntryList = fragExt->NewProfilesView (); profileEntryList.Size () > 0 )
332+ {
333+ auto profileEntry = get_self<FragmentProfileEntry>(profileEntryList.GetAt (0 ));
334+
335+ // We want the comment to be the first thing in the object,
336+ // "closeOnExit" is the first property, so target that.
337+ auto profileJson = _parseJSON (til::u16u8 (profileEntry->Json ()));
338+ profileJson[" closeOnExit" ].setComment (til::u16u8 (fmt::format (FMT_COMPILE (L" // {}" ), RS_ (L" PowerShellInstallationProfileJsonComment" ))), Json::CommentPlacement::commentBefore);
339+ profileEntry->Json (hstring{ til::u8u16 (Json::writeString (_getJsonStyledWriter (), profileJson)) });
340+ }
341+ }
342+ }
343+ }
344+
269345// A new settings.json gets a special treatment:
270346// 1. The default profile is a PowerShell 7+ one, if one was generated,
271347// and falls back to the standard PowerShell 5 profile otherwise.
@@ -1084,7 +1160,7 @@ bool SettingsLoader::_addOrMergeUserColorScheme(const winrt::com_ptr<implementat
10841160
10851161// As the name implies it executes a generator.
10861162// Generated profiles are added to .inboxSettings. Used by GenerateProfiles().
1087- void SettingsLoader::_executeGenerator (const IDynamicProfileGenerator& generator, std::vector<winrt::com_ptr<implementation::Profile>>& profilesList)
1163+ void SettingsLoader::_executeGenerator (IDynamicProfileGenerator& generator, std::vector<winrt::com_ptr<implementation::Profile>>& profilesList)
10881164{
10891165 const auto generatorNamespace = generator.GetNamespace ();
10901166 const auto previousSize = profilesList.size ();
@@ -1648,7 +1724,11 @@ void CascadiaSettings::_resolveNewTabMenuProfiles() const
16481724 auto activeProfileCount = gsl::narrow_cast<int >(_activeProfiles.Size ());
16491725 for (auto profileIndex = 0 ; profileIndex < activeProfileCount; profileIndex++)
16501726 {
1651- remainingProfilesMap.emplace (profileIndex, _activeProfiles.GetAt (profileIndex));
1727+ const auto & profile = _activeProfiles.GetAt (profileIndex);
1728+ if (!profile.Deleted ())
1729+ {
1730+ remainingProfilesMap.emplace (profileIndex, _activeProfiles.GetAt (profileIndex));
1731+ }
16521732 }
16531733
16541734 // We keep track of the "remaining profiles" - those that have not yet been resolved
0 commit comments