diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index fbbc8a4076..47dee8aae7 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -1069,7 +1069,7 @@ namespace winrt::TerminalApp::implementation auto folderEntryItems = _CreateNewTabFlyoutItems(folderEntries); // If the folder should auto-inline and there is only one item, do so. - if (folderEntry.Inlining() == FolderEntryInlining::Auto && folderEntries.Size() == 1) + if (folderEntry.Inlining() == FolderEntryInlining::Auto && folderEntryItems.size() == 1) { for (auto const& folderEntryItem : folderEntryItems) { diff --git a/src/cascadia/TerminalSettingsModel/ApplicationState.h b/src/cascadia/TerminalSettingsModel/ApplicationState.h index 999ab0c0fc..f998fc5ead 100644 --- a/src/cascadia/TerminalSettingsModel/ApplicationState.h +++ b/src/cascadia/TerminalSettingsModel/ApplicationState.h @@ -41,7 +41,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation X(FileSource::Shared, Windows::Foundation::Collections::IVector, RecentCommands, "recentCommands") \ X(FileSource::Shared, Windows::Foundation::Collections::IVector, DismissedMessages, "dismissedMessages") \ X(FileSource::Local, Windows::Foundation::Collections::IVector, AllowedCommandlines, "allowedCommandlines") \ - X(FileSource::Local, std::unordered_set, DismissedBadges, "dismissedBadges") + X(FileSource::Local, std::unordered_set, DismissedBadges, "dismissedBadges") \ + X(FileSource::Shared, bool, SSHFolderGenerated, "sshFolderGenerated", false) struct WindowLayout : WindowLayoutT { diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.h b/src/cascadia/TerminalSettingsModel/CascadiaSettings.h index 5e235d62af..8336db13f0 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.h +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.h @@ -93,6 +93,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation void MergeFragmentIntoUserSettings(const winrt::hstring& source, const winrt::hstring& basePath, const std::string_view& content); void FinalizeLayering(); bool DisableDeletedProfiles(); + bool AddDynamicProfileFolders(); bool RemapColorSchemeForProfile(const winrt::com_ptr& profile); bool FixupUserSettings(); @@ -100,6 +101,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation ParsedSettings userSettings; std::unordered_map> extensionPackageMap; bool duplicateProfile = false; + bool sshProfilesGenerated = false; private: struct JsonSettings diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp index bb00ac550e..f251d3e027 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp @@ -213,8 +213,11 @@ void SettingsLoader::GenerateProfiles() auto generateProfiles = [&](const IDynamicProfileGenerator& generator) { if (!_ignoredNamespaces.contains(generator.GetNamespace())) { + const auto oldProfileCount = inboxSettings.profiles.size(); _executeGenerator(generator, inboxSettings.profiles); + return oldProfileCount != inboxSettings.profiles.size(); } + return false; }; // Generate profiles for each generator and add them to the inbox settings. @@ -224,7 +227,7 @@ void SettingsLoader::GenerateProfiles() generateProfiles(AzureCloudShellGenerator{}); generateProfiles(VisualStudioGenerator{}); #if TIL_FEATURE_DYNAMICSSHPROFILES_ENABLED - generateProfiles(SshHostGenerator{}); + sshProfilesGenerated = generateProfiles(SshHostGenerator{}); #endif } @@ -536,6 +539,33 @@ bool SettingsLoader::DisableDeletedProfiles() return newGeneratedProfiles; } +// Returns true if something got changed and +// the settings need to be saved to disk. +bool SettingsLoader::AddDynamicProfileFolders() +{ + // Keep track of generated folders to avoid regenerating them + const auto state = get_self(ApplicationState::SharedInstance()); + + // If the SSH generator is enabled, try to create an "SSH" folder with all the generated profiles + if (sshProfilesGenerated && !state->SSHFolderGenerated()) + { + SshHostGenerator sshGenerator; + auto matchProfilesEntry = make_self(); + matchProfilesEntry->Source(hstring{ sshGenerator.GetNamespace() }); + + auto folderEntry = make_self(); + folderEntry->Name(L"SSH"); + folderEntry->Icon(MediaResource::FromString(hstring{ sshGenerator.GetIcon() })); + folderEntry->Inlining(FolderEntryInlining::Auto); + folderEntry->RawEntries(winrt::single_threaded_vector({ *matchProfilesEntry })); + + userSettings.globals->NewTabMenu().Append(folderEntry.as()); + state->SSHFolderGenerated(true); + return true; + } + return false; +} + bool winrt::Microsoft::Terminal::Settings::Model::implementation::SettingsLoader::RemapColorSchemeForProfile(const winrt::com_ptr& profile) { bool modified{ false }; @@ -1229,6 +1259,7 @@ try // DisableDeletedProfiles returns true whenever we encountered any new generated/dynamic profiles. // Similarly FixupUserSettings returns true, when it encountered settings that were patched up. mustWriteToDisk |= loader.DisableDeletedProfiles(); + mustWriteToDisk |= loader.AddDynamicProfileFolders(); mustWriteToDisk |= loader.FixupUserSettings(); // If this throws, the app will catch it and use the default settings.