diff --git a/.github/actions/spell-check/dictionary/apis.txt b/.github/actions/spell-check/dictionary/apis.txt new file mode 100644 index 00000000000..637e714b960 --- /dev/null +++ b/.github/actions/spell-check/dictionary/apis.txt @@ -0,0 +1 @@ +rfind diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp index 2b4d2e18474..51d2287e41f 100644 --- a/src/cascadia/TerminalApp/AppLogic.cpp +++ b/src/cascadia/TerminalApp/AppLogic.cpp @@ -138,6 +138,29 @@ catch (...) namespace winrt::TerminalApp::implementation { + // Function Description: + // - Get the AppLogic for the current active Xaml application, or null if there isn't one. + // Return value: + // - A pointer (bare) to the applogic, or nullptr. The app logic outlives all other objects, + // unless the application is in a terrible way, so this is "safe." + AppLogic* AppLogic::Current() noexcept + try + { + if (auto currentXamlApp{ winrt::Windows::UI::Xaml::Application::Current().try_as() }) + { + if (auto appLogicPointer{ winrt::get_self(currentXamlApp.Logic()) }) + { + return appLogicPointer; + } + } + return nullptr; + } + catch (...) + { + LOG_CAUGHT_EXCEPTION(); + return nullptr; + } + AppLogic::AppLogic() : _dialogLock{}, _loadedInitialSettings{ false }, @@ -862,6 +885,32 @@ namespace winrt::TerminalApp::implementation return { L"" }; } + winrt::hstring AppLogic::ApplicationDisplayName() const + { + try + { + const auto package{ winrt::Windows::ApplicationModel::Package::Current() }; + return package.DisplayName(); + } + CATCH_LOG(); + + return RS_(L"ApplicationDisplayNameUnpackaged"); + } + + winrt::hstring AppLogic::ApplicationVersion() const + { + try + { + const auto package{ winrt::Windows::ApplicationModel::Package::Current() }; + const auto version{ package.Id().Version() }; + winrt::hstring formatted{ wil::str_printf(L"%u.%u.%u.%u", version.Major, version.Minor, version.Build, version.Revision) }; + return formatted; + } + CATCH_LOG(); + + return RS_(L"ApplicationVersionUnknown"); + } + // -------------------------------- WinRT Events --------------------------------- // Winrt events need a method for adding a callback to the event and removing the callback. // These macros will define them both for you. diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h index 99a8b93915b..dfff44f18fe 100644 --- a/src/cascadia/TerminalApp/AppLogic.h +++ b/src/cascadia/TerminalApp/AppLogic.h @@ -15,6 +15,8 @@ namespace winrt::TerminalApp::implementation struct AppLogic : AppLogicT { public: + static AppLogic* Current() noexcept; + AppLogic(); ~AppLogic() = default; @@ -28,6 +30,9 @@ namespace winrt::TerminalApp::implementation int32_t SetStartupCommandline(array_view actions); winrt::hstring EarlyExitMessage(); + winrt::hstring ApplicationDisplayName() const; + winrt::hstring ApplicationVersion() const; + Windows::Foundation::Point GetLaunchDimensions(uint32_t dpi); winrt::Windows::Foundation::Point GetLaunchInitialPositions(int32_t defaultInitialX, int32_t defaultInitialY); winrt::Windows::UI::Xaml::ElementTheme GetRequestedTheme(); diff --git a/src/cascadia/TerminalApp/AppLogic.idl b/src/cascadia/TerminalApp/AppLogic.idl index 1fecbfb34bd..bd01b43e49a 100644 --- a/src/cascadia/TerminalApp/AppLogic.idl +++ b/src/cascadia/TerminalApp/AppLogic.idl @@ -35,6 +35,9 @@ namespace TerminalApp String Title { get; }; + String ApplicationDisplayName { get; }; + String ApplicationVersion { get; }; + Windows.Foundation.Point GetLaunchDimensions(UInt32 dpi); Windows.Foundation.Point GetLaunchInitialPositions(Int32 defaultInitialX, Int32 defaultInitialY); Windows.UI.Xaml.ElementTheme GetRequestedTheme(); diff --git a/src/cascadia/TerminalApp/CascadiaSettings.cpp b/src/cascadia/TerminalApp/CascadiaSettings.cpp index 04418485228..6c0937780a0 100644 --- a/src/cascadia/TerminalApp/CascadiaSettings.cpp +++ b/src/cascadia/TerminalApp/CascadiaSettings.cpp @@ -27,18 +27,17 @@ static constexpr std::wstring_view PACKAGED_PROFILE_ICON_PATH{ L"ms-appx:///Prof static constexpr std::wstring_view PACKAGED_PROFILE_ICON_EXTENSION{ L".png" }; static constexpr std::wstring_view DEFAULT_LINUX_ICON_GUID{ L"{9acb9455-ca41-5af7-950f-6bca1bc9722f}" }; +// make sure this matches defaults.json. +static constexpr std::wstring_view DEFAULT_WINDOWS_POWERSHELL_GUID{ L"{61c54bbd-c2c6-5271-96e7-009a87ff44bf}" }; + // Method Description: // - Returns the settings currently in use by the entire Terminal application. // Throws: // - HR E_INVALIDARG if the app isn't up and running. const CascadiaSettings& CascadiaSettings::GetCurrentAppSettings() { - auto currentXamlApp{ winrt::Windows::UI::Xaml::Application::Current().as() }; - THROW_HR_IF_NULL(E_INVALIDARG, currentXamlApp); - - auto appLogic = winrt::get_self(currentXamlApp.Logic()); + auto appLogic{ ::winrt::TerminalApp::implementation::AppLogic::Current() }; THROW_HR_IF_NULL(E_INVALIDARG, appLogic); - return *(appLogic->GetSettings()); } @@ -70,7 +69,7 @@ CascadiaSettings::CascadiaSettings(const bool addDynamicProfiles) // - profileName: the name of the profile's GUID to return. // Return Value: // - the GUID associated with the profile name. -std::optional CascadiaSettings::FindGuid(const std::wstring& profileName) const noexcept +std::optional CascadiaSettings::FindGuid(const std::wstring_view profileName) const noexcept { std::optional profileGuid{}; @@ -673,3 +672,38 @@ void CascadiaSettings::_ValidateKeybindings() _warnings.insert(_warnings.end(), keybindingWarnings.begin(), keybindingWarnings.end()); } } + +// Method Description +// - Replaces known tokens DEFAULT_PROFILE, PRODUCT and VERSION in the settings template +// with their expected values. DEFAULT_PROFILE is updated to match PowerShell Core's GUID +// if such a profile is detected. If it isn't, it'll be set to Windows PowerShell's GUID. +// Arguments: +// - settingsTemplate: a settings template +// Return value: +// - The new settings string. +std::string CascadiaSettings::_ApplyFirstRunChangesToSettingsTemplate(std::string_view settingsTemplate) const +{ + std::string finalSettings{ settingsTemplate }; + auto replace{ [](std::string& haystack, std::string_view needle, std::string_view replacement) { + auto pos{ std::string::npos }; + while ((pos = haystack.rfind(needle, pos)) != std::string::npos) + { + haystack.replace(pos, needle.size(), replacement); + } + } }; + + std::wstring defaultProfileGuid{ DEFAULT_WINDOWS_POWERSHELL_GUID }; + if (const auto psCoreProfileGuid{ FindGuid(PowershellCoreProfileGenerator::GetPreferredPowershellProfileName()) }) + { + defaultProfileGuid = Utils::GuidToString(*psCoreProfileGuid); + } + + replace(finalSettings, "%DEFAULT_PROFILE%", til::u16u8(defaultProfileGuid)); + if (const auto appLogic{ winrt::TerminalApp::implementation::AppLogic::Current() }) + { + replace(finalSettings, "%VERSION%", til::u16u8(appLogic->ApplicationVersion())); + replace(finalSettings, "%PRODUCT%", til::u16u8(appLogic->ApplicationDisplayName())); + } + + return finalSettings; +} diff --git a/src/cascadia/TerminalApp/CascadiaSettings.h b/src/cascadia/TerminalApp/CascadiaSettings.h index 50a89b25340..7d84176f718 100644 --- a/src/cascadia/TerminalApp/CascadiaSettings.h +++ b/src/cascadia/TerminalApp/CascadiaSettings.h @@ -69,7 +69,7 @@ class TerminalApp::CascadiaSettings final static std::filesystem::path GetSettingsPath(); static std::filesystem::path GetDefaultSettingsPath(); - std::optional FindGuid(const std::wstring& profileName) const noexcept; + std::optional FindGuid(const std::wstring_view profileName) const noexcept; const Profile* FindProfile(GUID profileGuid) const noexcept; std::vector& GetWarnings(); @@ -95,6 +95,7 @@ class TerminalApp::CascadiaSettings final static const Json::Value& _GetDisabledProfileSourcesJsonObject(const Json::Value& json); bool _PrependSchemaDirective(); bool _AppendDynamicProfilesToUserSettings(); + std::string _ApplyFirstRunChangesToSettingsTemplate(std::string_view settingsTemplate) const; void _ApplyDefaultsFromUserSettings(); diff --git a/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp b/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp index bf3939ec586..f11c6080eff 100644 --- a/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp +++ b/src/cascadia/TerminalApp/CascadiaSettingsSerialization.cpp @@ -74,20 +74,22 @@ std::unique_ptr CascadiaSettings::LoadAll() { resultPtr->_ParseJsonString(fileData.value(), false); } - else + + // Load profiles from dynamic profile generators. _userSettings should be + // created by now, because we're going to check in there for any generators + // that should be disabled (if the user had any settings.) + resultPtr->_LoadDynamicProfiles(); + + if (!fileHasData) { // We didn't find the user settings. We'll need to create a file // to use as the user defaults. // For now, just parse our user settings template as their user settings. - resultPtr->_ParseJsonString(UserSettingsJson, false); + auto userSettings{ resultPtr->_ApplyFirstRunChangesToSettingsTemplate(UserSettingsJson) }; + resultPtr->_ParseJsonString(userSettings, false); needToWriteFile = true; } - // Load profiles from dynamic profile generators. _userSettings should be - // created by now, because we're going to check in there for any generators - // that should be disabled. - resultPtr->_LoadDynamicProfiles(); - // See microsoft/terminal#2325: find the defaultSettings from the user's // settings. Layer those settings upon all the existing profiles we have // (defaults and dynamic profiles). We'll also set @@ -902,5 +904,9 @@ const Json::Value& CascadiaSettings::_GetProfilesJsonObject(const Json::Value& j // given object const Json::Value& CascadiaSettings::_GetDisabledProfileSourcesJsonObject(const Json::Value& json) { + if (!json) + { + return Json::Value::nullSingleton(); + } return json[JsonKey(DisabledProfileSourcesKey)]; } diff --git a/src/cascadia/TerminalApp/DefaultProfileUtils.cpp b/src/cascadia/TerminalApp/DefaultProfileUtils.cpp index c6eca459cb1..02222fdcb61 100644 --- a/src/cascadia/TerminalApp/DefaultProfileUtils.cpp +++ b/src/cascadia/TerminalApp/DefaultProfileUtils.cpp @@ -21,7 +21,7 @@ TerminalApp::Profile CreateDefaultProfile(const std::wstring_view name) gsl::as_bytes(gsl::make_span(name))) }; TerminalApp::Profile newProfile{ profileGuid }; - newProfile.SetName(static_cast(name)); + newProfile.SetName(name); std::wstring iconPath{ PACKAGED_PROFILE_ICON_PATH }; iconPath.append(Microsoft::Console::Utils::GuidToString(profileGuid)); diff --git a/src/cascadia/TerminalApp/PowershellCoreProfileGenerator.cpp b/src/cascadia/TerminalApp/PowershellCoreProfileGenerator.cpp index d3285d34bd6..2c2ba87d48a 100644 --- a/src/cascadia/TerminalApp/PowershellCoreProfileGenerator.cpp +++ b/src/cascadia/TerminalApp/PowershellCoreProfileGenerator.cpp @@ -21,6 +21,7 @@ static constexpr std::wstring_view POWERSHELL_PREVIEW_PFN{ L"Microsoft.PowerShel static constexpr std::wstring_view PWSH_EXE{ L"pwsh.exe" }; static constexpr std::wstring_view POWERSHELL_ICON{ L"ms-appx:///ProfileIcons/pwsh.png" }; static constexpr std::wstring_view POWERSHELL_PREVIEW_ICON{ L"ms-appx:///ProfileIcons/pwsh-preview.png" }; +static constexpr std::wstring_view POWERSHELL_PREFERRED_PROFILE_NAME{ L"PowerShell" }; namespace { @@ -322,8 +323,17 @@ std::vector PowershellCoreProfileGenerator::GenerateProfil // (or the closest approximation thereof). It may choose a preview instance as the "best" if it is a higher version. auto firstProfile = profiles.begin(); firstProfile->SetGuid(PowershellCoreGuid); - firstProfile->SetName(L"PowerShell"); + firstProfile->SetName(POWERSHELL_PREFERRED_PROFILE_NAME); } return profiles; } + +// Function Description: +// - Returns the thing it's named for. +// Return value: +// - the thing it says in the name +const std::wstring_view PowershellCoreProfileGenerator::GetPreferredPowershellProfileName() +{ + return POWERSHELL_PREFERRED_PROFILE_NAME; +} diff --git a/src/cascadia/TerminalApp/PowershellCoreProfileGenerator.h b/src/cascadia/TerminalApp/PowershellCoreProfileGenerator.h index 7514fd781aa..eb529358843 100644 --- a/src/cascadia/TerminalApp/PowershellCoreProfileGenerator.h +++ b/src/cascadia/TerminalApp/PowershellCoreProfileGenerator.h @@ -23,6 +23,8 @@ namespace TerminalApp class PowershellCoreProfileGenerator : public TerminalApp::IDynamicProfileGenerator { public: + static const std::wstring_view GetPreferredPowershellProfileName(); + PowershellCoreProfileGenerator() = default; ~PowershellCoreProfileGenerator() = default; std::wstring_view GetNamespace() override; diff --git a/src/cascadia/TerminalApp/Profile.cpp b/src/cascadia/TerminalApp/Profile.cpp index 7380e10c5d1..f9e30cbf387 100644 --- a/src/cascadia/TerminalApp/Profile.cpp +++ b/src/cascadia/TerminalApp/Profile.cpp @@ -718,9 +718,9 @@ void Profile::SetStartingDirectory(std::wstring startingDirectory) noexcept _startingDirectory = std::move(startingDirectory); } -void Profile::SetName(std::wstring name) noexcept +void Profile::SetName(const std::wstring_view name) noexcept { - _name = std::move(name); + _name = static_cast(name); } void Profile::SetUseAcrylic(bool useAcrylic) noexcept diff --git a/src/cascadia/TerminalApp/Profile.h b/src/cascadia/TerminalApp/Profile.h index ba28b9beedb..f14e762d7ba 100644 --- a/src/cascadia/TerminalApp/Profile.h +++ b/src/cascadia/TerminalApp/Profile.h @@ -79,7 +79,7 @@ class TerminalApp::Profile final void SetAcrylicOpacity(double opacity) noexcept; void SetCommandline(std::wstring cmdline) noexcept; void SetStartingDirectory(std::wstring startingDirectory) noexcept; - void SetName(std::wstring name) noexcept; + void SetName(const std::wstring_view name) noexcept; void SetUseAcrylic(bool useAcrylic) noexcept; void SetDefaultForeground(COLORREF defaultForeground) noexcept; void SetDefaultBackground(COLORREF defaultBackground) noexcept; diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index 465fa3727e8..ca7c73488eb 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -266,11 +266,11 @@ Temporarily using the Windows Terminal default settings. Privacy Policy A hyperlink name for the Terminal's privacy policy - + Windows Terminal (Unpackaged) This display name is used when the application's name cannot be determined - + Unknown This is displayed when the version of the application cannot be determined @@ -283,4 +283,4 @@ Temporarily using the Windows Terminal default settings. Do you want to close all tabs? - + \ No newline at end of file diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 7ca074a3166..5df4710db4d 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -5,6 +5,7 @@ #include "TerminalPage.h" #include "ActionAndArgs.h" #include "Utils.h" +#include "AppLogic.h" #include "../../types/inc/utils.hpp" #include @@ -234,28 +235,22 @@ namespace winrt::TerminalApp::implementation winrt::hstring TerminalPage::ApplicationDisplayName() { - try + if (const auto appLogic{ implementation::AppLogic::Current() }) { - const auto package{ winrt::Windows::ApplicationModel::Package::Current() }; - return package.DisplayName(); + return appLogic->ApplicationDisplayName(); } - CATCH_LOG(); - return RS_(L"AboutDialog_DisplayNameUnpackaged"); + return RS_(L"ApplicationDisplayNameUnpackaged"); } winrt::hstring TerminalPage::ApplicationVersion() { - try + if (const auto appLogic{ implementation::AppLogic::Current() }) { - const auto package{ winrt::Windows::ApplicationModel::Package::Current() }; - const auto version{ package.Id().Version() }; - winrt::hstring formatted{ wil::str_printf(L"%u.%u.%u.%u", version.Major, version.Minor, version.Build, version.Revision) }; - return formatted; + return appLogic->ApplicationVersion(); } - CATCH_LOG(); - return RS_(L"AboutDialog_VersionUnknown"); + return RS_(L"ApplicationVersionUnknown"); } // Method Description: diff --git a/src/cascadia/TerminalApp/userDefaults.json b/src/cascadia/TerminalApp/userDefaults.json index e5b325a1d86..1e2dedbe857 100644 --- a/src/cascadia/TerminalApp/userDefaults.json +++ b/src/cascadia/TerminalApp/userDefaults.json @@ -1,10 +1,12 @@ +// This file was generated by %PRODUCT% %VERSION% + // To view the default settings, hold "alt" while clicking on the "Settings" button. // For documentation on these settings, see: https://aka.ms/terminal-documentation { "$schema": "https://aka.ms/terminal-profiles-schema", - "defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", + "defaultProfile": "%DEFAULT_PROFILE%", "profiles": {