diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index c259385100c..63d1d458279 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -2171,11 +2171,6 @@ "description": "When set to true, the background image for the currently focused profile is expanded to encompass the entire window, beneath other panes.", "type": "boolean" }, - "compatibility.reloadEnvironmentVariables": { - "default": true, - "description": "When set to true, when opening a new tab or pane it will get reloaded environment variables.", - "type": "boolean" - }, "initialCols": { "default": 120, "description": "The number of columns displayed in the window upon first load. If \"launchMode\" is set to \"maximized\" (or \"maximizedFocus\"), this property is ignored.", @@ -2424,6 +2419,11 @@ "null" ] }, + "compatibility.reloadEnvironmentVariables": { + "default": true, + "description": "When set to true, when opening a new tab or pane it will get reloaded environment variables.", + "type": "boolean" + }, "unfocusedAppearance": { "$ref": "#/$defs/AppearanceConfig", "description": "Sets the appearance of the terminal when it is unfocused.", diff --git a/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp b/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp index 5f02757084a..b5139a5263f 100644 --- a/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp @@ -74,6 +74,8 @@ namespace SettingsModelLocalTests TEST_METHOD(TestInheritedCommand); TEST_METHOD(LoadFragmentsWithMultipleUpdates); + TEST_METHOD(MigrateReloadEnvVars); + private: static winrt::com_ptr createSettings(const std::string_view& userJSON) { @@ -2020,4 +2022,40 @@ namespace SettingsModelLocalTests // GH#12520: Fragments should be able to override the name of builtin profiles. VERIFY_ARE_EQUAL(L"NewName", loader.userSettings.profiles[0]->Name()); } + + void DeserializationTests::MigrateReloadEnvVars() + { + static constexpr std::string_view settings1Json{ R"( + { + "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "compatibility.reloadEnvironmentVariables": false, + "profiles": [ + { + "name": "profile0", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "historySize": 1, + "commandline": "cmd.exe" + } + ], + "actions": [ + { + "name": "foo", + "command": "closePane", + "keys": "ctrl+shift+w" + } + ] + })" }; + + implementation::SettingsLoader loader{ settings1Json, DefaultJson }; + loader.MergeInboxIntoUserSettings(); + loader.FinalizeLayering(); + + VERIFY_IS_TRUE(loader.FixupUserSettings(), L"Validate that this will indicate we need to write them back to disk"); + + const auto settings = winrt::make_self(std::move(loader)); + + Log::Comment(L"Ensure that the profile defaults have the new setting added"); + VERIFY_IS_TRUE(settings->ProfileDefaults().HasReloadEnvironmentVariables()); + VERIFY_IS_FALSE(settings->ProfileDefaults().ReloadEnvironmentVariables()); + } } diff --git a/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp b/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp index ffc7dea07bd..2488f3f812d 100644 --- a/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp @@ -42,6 +42,9 @@ namespace SettingsModelLocalTests TEST_METHOD(CascadiaSettings); TEST_METHOD(LegacyFontSettings); + TEST_METHOD(RoundtripReloadEnvVars); + TEST_METHOD(DontRoundtripNoReloadEnvVars); + private: // Method Description: // - deserializes and reserializes a json string representing a settings object model of type T @@ -513,4 +516,114 @@ namespace SettingsModelLocalTests VERIFY_ARE_EQUAL(toString(jsonOutput), toString(result)); } + + void SerializationTests::RoundtripReloadEnvVars() + { + static constexpr std::string_view oldSettingsJson{ R"( + { + "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "compatibility.reloadEnvironmentVariables": false, + "profiles": [ + { + "name": "profile0", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "historySize": 1, + "commandline": "cmd.exe" + } + ], + "actions": [ + { + "name": "foo", + "command": "closePane", + "keys": "ctrl+shift+w" + } + ] + })" }; + + static constexpr std::string_view newSettingsJson{ R"( + { + "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "profiles": + { + "defaults": + { + "compatibility.reloadEnvironmentVariables": false + }, + "list": + [ + { + "name": "profile0", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "historySize": 1, + "commandline": "cmd.exe" + } + ] + }, + "actions": [ + { + "name": "foo", + "command": "closePane", + "keys": "ctrl+shift+w" + } + ] + })" }; + + implementation::SettingsLoader oldLoader{ oldSettingsJson, DefaultJson }; + oldLoader.MergeInboxIntoUserSettings(); + oldLoader.FinalizeLayering(); + VERIFY_IS_TRUE(oldLoader.FixupUserSettings(), L"Validate that this will indicate we need to write them back to disk"); + const auto oldSettings = winrt::make_self(std::move(oldLoader)); + const auto oldResult{ oldSettings->ToJson() }; + + implementation::SettingsLoader newLoader{ newSettingsJson, DefaultJson }; + newLoader.MergeInboxIntoUserSettings(); + newLoader.FinalizeLayering(); + newLoader.FixupUserSettings(); + const auto newSettings = winrt::make_self(std::move(newLoader)); + const auto newResult{ newSettings->ToJson() }; + + VERIFY_ARE_EQUAL(toString(newResult), toString(oldResult)); + } + + void SerializationTests::DontRoundtripNoReloadEnvVars() + { + // Kinda like the above test, but confirming that _nothing_ happens if + // we don't have a setting to migrate. + + static constexpr std::string_view oldSettingsJson{ R"( + { + "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name": "profile0", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "historySize": 1, + "commandline": "cmd.exe" + } + ], + "actions": [ + { + "name": "foo", + "command": "closePane", + "keys": "ctrl+shift+w" + } + ] + })" }; + + implementation::SettingsLoader oldLoader{ oldSettingsJson, DefaultJson }; + oldLoader.MergeInboxIntoUserSettings(); + oldLoader.FinalizeLayering(); + oldLoader.FixupUserSettings(); + const auto oldSettings = winrt::make_self(std::move(oldLoader)); + const auto oldResult{ oldSettings->ToJson() }; + + Log::Comment(L"Now, create a _new_ settings object from the re-serialization of the first"); + implementation::SettingsLoader newLoader{ toString(oldResult), DefaultJson }; + newLoader.MergeInboxIntoUserSettings(); + newLoader.FinalizeLayering(); + newLoader.FixupUserSettings(); + const auto newSettings = winrt::make_self(std::move(newLoader)); + VERIFY_IS_FALSE(newSettings->ProfileDefaults().HasReloadEnvironmentVariables(), + L"Ensure that the new settings object didn't find a reloadEnvironmentVariables"); + } } diff --git a/src/cascadia/LocalTests_SettingsModel/pch.h b/src/cascadia/LocalTests_SettingsModel/pch.h index 96727252489..b077abab8be 100644 --- a/src/cascadia/LocalTests_SettingsModel/pch.h +++ b/src/cascadia/LocalTests_SettingsModel/pch.h @@ -64,6 +64,7 @@ Author(s): // Manually include til after we include Windows.Foundation to give it winrt superpowers #include "til.h" +#include // Common includes for most tests: #include "../../inc/conattrs.hpp" diff --git a/src/cascadia/Remoting/CommandlineArgs.h b/src/cascadia/Remoting/CommandlineArgs.h index 4d40c898a62..2f618e53efc 100644 --- a/src/cascadia/Remoting/CommandlineArgs.h +++ b/src/cascadia/Remoting/CommandlineArgs.h @@ -15,10 +15,12 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation CommandlineArgs(const winrt::array_view& args, winrt::hstring currentDirectory, - const uint32_t showWindowCommand) : + const uint32_t showWindowCommand, + winrt::hstring envString) : _args{ args.begin(), args.end() }, _cwd{ currentDirectory }, - _ShowWindowCommand{ showWindowCommand } + _ShowWindowCommand{ showWindowCommand }, + CurrentEnvironment{ envString } { } @@ -27,6 +29,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation void Commandline(const winrt::array_view& value); winrt::com_array Commandline(); + til::property CurrentEnvironment; + WINRT_PROPERTY(uint32_t, ShowWindowCommand, SW_NORMAL); // SW_NORMAL is 1, 0 is SW_HIDE private: diff --git a/src/cascadia/Remoting/Monarch.h b/src/cascadia/Remoting/Monarch.h index 3b5cc7d9abe..aeac9d817d3 100644 --- a/src/cascadia/Remoting/Monarch.h +++ b/src/cascadia/Remoting/Monarch.h @@ -47,7 +47,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation _WindowName{ windowInfo.WindowName() }, _args{ command.Commandline() }, _CurrentDirectory{ command.CurrentDirectory() }, - _ShowWindowCommand{ command.ShowWindowCommand() } {}; + _ShowWindowCommand{ command.ShowWindowCommand() }, + _CurrentEnvironment{ command.CurrentEnvironment() } {}; WindowRequestedArgs(const winrt::hstring& window, const winrt::hstring& content, const Windows::Foundation::IReference& bounds) : _Id{ 0u }, @@ -65,6 +66,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation WINRT_PROPERTY(winrt::hstring, CurrentDirectory); WINRT_PROPERTY(winrt::hstring, Content); WINRT_PROPERTY(uint32_t, ShowWindowCommand, SW_NORMAL); + WINRT_PROPERTY(winrt::hstring, CurrentEnvironment); WINRT_PROPERTY(Windows::Foundation::IReference, InitialBounds); private: diff --git a/src/cascadia/Remoting/Monarch.idl b/src/cascadia/Remoting/Monarch.idl index cc2c45f5426..f57bd6b59b2 100644 --- a/src/cascadia/Remoting/Monarch.idl +++ b/src/cascadia/Remoting/Monarch.idl @@ -27,6 +27,7 @@ namespace Microsoft.Terminal.Remoting String[] Commandline { get; }; String CurrentDirectory { get; }; UInt32 ShowWindowCommand { get; }; + String CurrentEnvironment { get; }; String Content { get; }; Windows.Foundation.IReference InitialBounds { get; }; diff --git a/src/cascadia/Remoting/Peasant.idl b/src/cascadia/Remoting/Peasant.idl index 64ff512a1b4..f02d22da9c4 100644 --- a/src/cascadia/Remoting/Peasant.idl +++ b/src/cascadia/Remoting/Peasant.idl @@ -7,11 +7,12 @@ namespace Microsoft.Terminal.Remoting runtimeclass CommandlineArgs { CommandlineArgs(); - CommandlineArgs(String[] args, String cwd, UInt32 showWindowCommand); + CommandlineArgs(String[] args, String cwd, UInt32 showWindowCommand, String env); String[] Commandline { get; set; }; String CurrentDirectory { get; }; UInt32 ShowWindowCommand { get; }; + String CurrentEnvironment { get; }; }; runtimeclass RenameRequestArgs diff --git a/src/cascadia/Remoting/WindowManager.cpp b/src/cascadia/Remoting/WindowManager.cpp index 5572c6eee95..aa9f67b0b3f 100644 --- a/src/cascadia/Remoting/WindowManager.cpp +++ b/src/cascadia/Remoting/WindowManager.cpp @@ -349,7 +349,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // If the name wasn't specified, this will be an empty string. p->WindowName(args.WindowName()); - p->ExecuteCommandline(*winrt::make_self(args.Commandline(), args.CurrentDirectory(), args.ShowWindowCommand())); + p->ExecuteCommandline(*winrt::make_self(args.Commandline(), + args.CurrentDirectory(), + args.ShowWindowCommand(), + args.CurrentEnvironment())); _monarch.AddPeasant(*p); diff --git a/src/cascadia/Remoting/pch.h b/src/cascadia/Remoting/pch.h index 3e65fdf1038..4c4bcb1ac96 100644 --- a/src/cascadia/Remoting/pch.h +++ b/src/cascadia/Remoting/pch.h @@ -52,3 +52,4 @@ TRACELOGGING_DECLARE_PROVIDER(g_hRemotingProvider); #include "til.h" #include +#include diff --git a/src/cascadia/TerminalApp/AppCommandlineArgs.cpp b/src/cascadia/TerminalApp/AppCommandlineArgs.cpp index e9b6368ff0b..f3822fe2256 100644 --- a/src/cascadia/TerminalApp/AppCommandlineArgs.cpp +++ b/src/cascadia/TerminalApp/AppCommandlineArgs.cpp @@ -568,6 +568,11 @@ void AppCommandlineArgs::_addNewTerminalArgs(AppCommandlineArgs::NewTerminalSubc subcommand.colorSchemeOption = subcommand.subcommand->add_option("--colorScheme", _startingColorScheme, RS_A(L"CmdColorSchemeArgDesc")); + subcommand.inheritEnvOption = subcommand.subcommand->add_flag( + "--inheritEnvironment,!--reloadEnvironment", + _inheritEnvironment, + RS_A(L"CmdInheritEnvDesc")); + // Using positionals_at_end allows us to support "wt new-tab -d wsl -d Ubuntu" // without CLI11 thinking that we've specified -d twice. // There's an alternate construction where we make all subcommands "prefix commands", @@ -589,7 +594,8 @@ NewTerminalArgs AppCommandlineArgs::_getNewTerminalArgs(AppCommandlineArgs::NewT { NewTerminalArgs args{}; - if (!_commandline.empty()) + const auto hasCommandline{ !_commandline.empty() }; + if (hasCommandline) { std::ostringstream cmdlineBuffer; @@ -655,6 +661,13 @@ NewTerminalArgs AppCommandlineArgs::_getNewTerminalArgs(AppCommandlineArgs::NewT args.ColorScheme(winrt::to_hstring(_startingColorScheme)); } + bool inheritEnv = hasCommandline; + if (*subcommand.inheritEnvOption) + { + inheritEnv = _inheritEnvironment; + } + args.ReloadEnvironmentVariables(!inheritEnv); + return args; } diff --git a/src/cascadia/TerminalApp/AppCommandlineArgs.h b/src/cascadia/TerminalApp/AppCommandlineArgs.h index 31eac78168b..a76d0ca5fac 100644 --- a/src/cascadia/TerminalApp/AppCommandlineArgs.h +++ b/src/cascadia/TerminalApp/AppCommandlineArgs.h @@ -67,6 +67,7 @@ class TerminalApp::AppCommandlineArgs final CLI::Option* tabColorOption; CLI::Option* suppressApplicationTitleOption; CLI::Option* colorSchemeOption; + CLI::Option* inheritEnvOption; }; struct NewPaneSubcommand : public NewTerminalSubcommand @@ -99,6 +100,7 @@ class TerminalApp::AppCommandlineArgs final std::string _startingTabColor; std::string _startingColorScheme; bool _suppressApplicationTitle{ false }; + bool _inheritEnvironment{ false }; winrt::Microsoft::Terminal::Settings::Model::FocusDirection _moveFocusDirection{ winrt::Microsoft::Terminal::Settings::Model::FocusDirection::None }; winrt::Microsoft::Terminal::Settings::Model::FocusDirection _swapPaneDirection{ winrt::Microsoft::Terminal::Settings::Model::FocusDirection::None }; diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index 7b7ee2dc3e0..c6ccf6856c1 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -368,6 +368,10 @@ Open the tab with tabTitle overriding default title and suppressing title change messages from the application {Locked="\"tabTitle\""} + + Inherit the terminal's own environment variables when creating the new tab or pane, rather than creating a fresh environment block. This defaults to set when a "command" is passed. + {Locked="\"command\""} + Open the tab with the specified color scheme, instead of the profile's set "colorScheme" {Locked="\"colorScheme\""} diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 66c129ea9fa..27c3710ad78 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -556,7 +556,8 @@ namespace winrt::TerminalApp::implementation // - winrt::fire_and_forget TerminalPage::ProcessStartupActions(Windows::Foundation::Collections::IVector actions, const bool initial, - const winrt::hstring cwd) + const winrt::hstring cwd, + const winrt::hstring env) { auto weakThis{ get_weak() }; @@ -576,6 +577,12 @@ namespace winrt::TerminalApp::implementation _WindowProperties.VirtualWorkingDirectory(originalVirtualCwd); }); + // Literally the same thing with env vars too + auto originalVirtualEnv{ _WindowProperties.VirtualEnvVars() }; + auto restoreEnv = wil::scope_exit([&originalVirtualEnv, this]() { + _WindowProperties.VirtualEnvVars(originalVirtualEnv); + }); + if (cwd.empty()) { // We didn't actually need to change the virtual CWD, so we don't @@ -587,6 +594,15 @@ namespace winrt::TerminalApp::implementation _WindowProperties.VirtualWorkingDirectory(cwd); } + if (env.empty()) + { + restoreEnv.release(); + } + else + { + _WindowProperties.VirtualEnvVars(env); + } + if (auto page{ weakThis.get() }) { for (const auto& action : actions) @@ -1223,6 +1239,8 @@ namespace winrt::TerminalApp::implementation auto valueSet = TerminalConnection::ConptyConnection::CreateSettings(azBridgePath.native(), L".", L"Azure", + false, + L"", nullptr, settings.InitialRows(), settings.InitialCols(), @@ -1263,6 +1281,8 @@ namespace winrt::TerminalApp::implementation auto valueSet = TerminalConnection::ConptyConnection::CreateSettings(settings.Commandline(), newWorkingDirectory, settings.StartingTitle(), + settings.ReloadEnvironmentVariables(), + _WindowProperties.VirtualEnvVars(), environment, settings.InitialRows(), settings.InitialCols(), @@ -1270,8 +1290,6 @@ namespace winrt::TerminalApp::implementation profile.Guid()); valueSet.Insert(L"passthroughMode", Windows::Foundation::PropertyValue::CreateBoolean(settings.VtPassthrough())); - valueSet.Insert(L"reloadEnvironmentVariables", - Windows::Foundation::PropertyValue::CreateBoolean(_settings.GlobalSettings().ReloadEnvironmentVariables())); if (inheritCursor) { diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 1beb3f00b7e..1e1a1bfd90f 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -151,7 +151,8 @@ namespace winrt::TerminalApp::implementation winrt::fire_and_forget ProcessStartupActions(Windows::Foundation::Collections::IVector actions, const bool initial, - const winrt::hstring cwd = L""); + const winrt::hstring cwd = L"", + const winrt::hstring env = L""); TerminalApp::WindowProperties WindowProperties() const noexcept { return _WindowProperties; }; diff --git a/src/cascadia/TerminalApp/TerminalPage.idl b/src/cascadia/TerminalApp/TerminalPage.idl index 4375c000738..76ee847fb80 100644 --- a/src/cascadia/TerminalApp/TerminalPage.idl +++ b/src/cascadia/TerminalApp/TerminalPage.idl @@ -52,6 +52,7 @@ namespace TerminalApp String WindowIdForDisplay { get; }; String VirtualWorkingDirectory { get; set; }; + String VirtualEnvVars { get; set; }; Boolean IsQuakeWindow(); }; diff --git a/src/cascadia/TerminalApp/TerminalWindow.cpp b/src/cascadia/TerminalApp/TerminalWindow.cpp index c95cf789315..c5c6090515f 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.cpp +++ b/src/cascadia/TerminalApp/TerminalWindow.cpp @@ -1023,9 +1023,12 @@ namespace winrt::TerminalApp::implementation // Return Value: // - the result of the first command who's parsing returned a non-zero code, // or 0. (see TerminalWindow::_ParseArgs) - int32_t TerminalWindow::SetStartupCommandline(array_view args, winrt::hstring cwd) + int32_t TerminalWindow::SetStartupCommandline(array_view args, + winrt::hstring cwd, + winrt::hstring env) { _WindowProperties->SetInitialCwd(std::move(cwd)); + _WindowProperties->VirtualEnvVars(std::move(env)); // This is called in AppHost::ctor(), before we've created the window // (or called TerminalWindow::Initialize) @@ -1080,7 +1083,8 @@ namespace winrt::TerminalApp::implementation // - the result of the first command who's parsing returned a non-zero code, // or 0. (see TerminalWindow::_ParseArgs) int32_t TerminalWindow::ExecuteCommandline(array_view args, - const winrt::hstring& cwd) + const winrt::hstring& cwd, + const winrt::hstring& env) { ::TerminalApp::AppCommandlineArgs appArgs; auto result = appArgs.ParseArgs(args); @@ -1088,7 +1092,7 @@ namespace winrt::TerminalApp::implementation { auto actions = winrt::single_threaded_vector(std::move(appArgs.GetStartupActions())); - _root->ProcessStartupActions(actions, false, cwd); + _root->ProcessStartupActions(actions, false, cwd, env); if (appArgs.IsHandoffListener()) { diff --git a/src/cascadia/TerminalApp/TerminalWindow.h b/src/cascadia/TerminalApp/TerminalWindow.h index a59c139a95c..574fcd98738 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.h +++ b/src/cascadia/TerminalApp/TerminalWindow.h @@ -56,6 +56,8 @@ namespace winrt::TerminalApp::implementation // Used for setting the initial CWD, before we have XAML set up for property change notifications. void SetInitialCwd(winrt::hstring cwd) { _VirtualWorkingDirectory = std::move(cwd); }; + til::property VirtualEnvVars; + private: winrt::hstring _WindowName{}; uint64_t _WindowId{ 0 }; @@ -77,9 +79,9 @@ namespace winrt::TerminalApp::implementation bool HasCommandlineArguments() const noexcept; - int32_t SetStartupCommandline(array_view actions, winrt::hstring cwd); + int32_t SetStartupCommandline(array_view actions, winrt::hstring cwd, winrt::hstring env); void SetStartupContent(const winrt::hstring& content, const Windows::Foundation::IReference& contentBounds); - int32_t ExecuteCommandline(array_view actions, const winrt::hstring& cwd); + int32_t ExecuteCommandline(array_view actions, const winrt::hstring& cwd, const winrt::hstring& env); void SetSettingsStartupArgs(const std::vector& actions); winrt::hstring ParseCommandlineMessage(); bool ShouldExitEarly(); diff --git a/src/cascadia/TerminalApp/TerminalWindow.idl b/src/cascadia/TerminalApp/TerminalWindow.idl index d91de2dce88..1b4d68c7527 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.idl +++ b/src/cascadia/TerminalApp/TerminalWindow.idl @@ -53,9 +53,9 @@ namespace TerminalApp Boolean HasCommandlineArguments(); - Int32 SetStartupCommandline(String[] commands, String cwd); + Int32 SetStartupCommandline(String[] commands, String cwd, String env); void SetStartupContent(String json, Windows.Foundation.IReference bounds); - Int32 ExecuteCommandline(String[] commands, String cwd); + Int32 ExecuteCommandline(String[] commands, String cwd, String env); String ParseCommandlineMessage { get; }; Boolean ShouldExitEarly { get; }; diff --git a/src/cascadia/TerminalConnection/ConptyConnection.cpp b/src/cascadia/TerminalConnection/ConptyConnection.cpp index cecb5c7d759..e086c9b2cfc 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.cpp +++ b/src/cascadia/TerminalConnection/ConptyConnection.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include "CTerminalHandoff.h" @@ -90,14 +89,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation }); // Populate the environment map with the current environment. - if (_reloadEnvironmentVariables) - { - environment.regenerate(); - } - else - { - environment = til::env::from_current_environment(); - } + environment = _initialEnv; { // Convert connection Guid to string and ignore the enclosing '{}'. @@ -235,7 +227,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation Windows::Foundation::Collections::ValueSet ConptyConnection::CreateSettings(const winrt::hstring& cmdline, const winrt::hstring& startingDirectory, const winrt::hstring& startingTitle, - const Windows::Foundation::Collections::IMapView& environment, + bool reloadEnvironmentVariables, + const winrt::hstring& initialEnvironment, + const Windows::Foundation::Collections::IMapView& environmentOverrides, uint32_t rows, uint32_t columns, const winrt::guid& guid, @@ -246,23 +240,35 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation vs.Insert(L"commandline", Windows::Foundation::PropertyValue::CreateString(cmdline)); vs.Insert(L"startingDirectory", Windows::Foundation::PropertyValue::CreateString(startingDirectory)); vs.Insert(L"startingTitle", Windows::Foundation::PropertyValue::CreateString(startingTitle)); + vs.Insert(L"reloadEnvironmentVariables", Windows::Foundation::PropertyValue::CreateBoolean(reloadEnvironmentVariables)); vs.Insert(L"initialRows", Windows::Foundation::PropertyValue::CreateUInt32(rows)); vs.Insert(L"initialCols", Windows::Foundation::PropertyValue::CreateUInt32(columns)); vs.Insert(L"guid", Windows::Foundation::PropertyValue::CreateGuid(guid)); vs.Insert(L"profileGuid", Windows::Foundation::PropertyValue::CreateGuid(profileGuid)); - if (environment) + if (environmentOverrides) { Windows::Foundation::Collections::ValueSet env{}; - for (const auto& [k, v] : environment) + for (const auto& [k, v] : environmentOverrides) { env.Insert(k, Windows::Foundation::PropertyValue::CreateString(v)); } vs.Insert(L"environment", env); } + + if (!initialEnvironment.empty()) + { + vs.Insert(L"initialEnvironment", Windows::Foundation::PropertyValue::CreateString(initialEnvironment)); + } return vs; } + template + T unbox_prop_or(const Windows::Foundation::Collections::ValueSet& blob, std::wstring_view key, T defaultValue) + { + return winrt::unbox_value_or(blob.TryLookup(key).try_as(), defaultValue); + } + void ConptyConnection::Initialize(const Windows::Foundation::Collections::ValueSet& settings) { if (settings) @@ -271,26 +277,47 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation // auto bad = unbox_value_or(settings.TryLookup(L"foo").try_as(), nullptr); // It'll just return null - _commandline = winrt::unbox_value_or(settings.TryLookup(L"commandline").try_as(), _commandline); - _startingDirectory = winrt::unbox_value_or(settings.TryLookup(L"startingDirectory").try_as(), _startingDirectory); - _startingTitle = winrt::unbox_value_or(settings.TryLookup(L"startingTitle").try_as(), _startingTitle); - _rows = winrt::unbox_value_or(settings.TryLookup(L"initialRows").try_as(), _rows); - _cols = winrt::unbox_value_or(settings.TryLookup(L"initialCols").try_as(), _cols); - _guid = winrt::unbox_value_or(settings.TryLookup(L"guid").try_as(), _guid); + _commandline = unbox_prop_or(settings, L"commandline", _commandline); + _startingDirectory = unbox_prop_or(settings, L"startingDirectory", _startingDirectory); + _startingTitle = unbox_prop_or(settings, L"startingTitle", _startingTitle); + _rows = unbox_prop_or(settings, L"initialRows", _rows); + _cols = unbox_prop_or(settings, L"initialCols", _cols); + _guid = unbox_prop_or(settings, L"guid", _guid); _environment = settings.TryLookup(L"environment").try_as(); if constexpr (Feature_VtPassthroughMode::IsEnabled()) { - _passthroughMode = winrt::unbox_value_or(settings.TryLookup(L"passthroughMode").try_as(), _passthroughMode); + _passthroughMode = unbox_prop_or(settings, L"passthroughMode", _passthroughMode); } - _inheritCursor = winrt::unbox_value_or(settings.TryLookup(L"inheritCursor").try_as(), _inheritCursor); - _reloadEnvironmentVariables = winrt::unbox_value_or(settings.TryLookup(L"reloadEnvironmentVariables").try_as(), - _reloadEnvironmentVariables); - _profileGuid = winrt::unbox_value_or(settings.TryLookup(L"profileGuid").try_as(), _profileGuid); - } + _inheritCursor = unbox_prop_or(settings, L"inheritCursor", _inheritCursor); + _profileGuid = unbox_prop_or(settings, L"profileGuid", _profileGuid); - if (_guid == guid{}) - { - _guid = Utils::CreateGuid(); + const auto& initialEnvironment{ unbox_prop_or(settings, L"initialEnvironment", L"") }; + + const bool reloadEnvironmentVariables = unbox_prop_or(settings, L"reloadEnvironmentVariables", false); + + if (reloadEnvironmentVariables) + { + _initialEnv.regenerate(); + } + else + { + if (!initialEnvironment.empty()) + { + _initialEnv = til::env{ initialEnvironment.c_str() }; + } + else + { + // If we were not explicitly provided an "initial" env block to + // treat as our original one, then just use our actual current + // env block. + _initialEnv = til::env::from_current_environment(); + } + } + + if (_guid == guid{}) + { + _guid = Utils::CreateGuid(); + } } } @@ -734,5 +761,4 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation co_await winrt::resume_background(); // move to background connection.reset(); // explicitly destruct } - } diff --git a/src/cascadia/TerminalConnection/ConptyConnection.h b/src/cascadia/TerminalConnection/ConptyConnection.h index 747434f6dba..0105104c130 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.h +++ b/src/cascadia/TerminalConnection/ConptyConnection.h @@ -7,6 +7,7 @@ #include "ConnectionStateHolder.h" #include "ITerminalHandoff.h" +#include namespace winrt::Microsoft::Terminal::TerminalConnection::implementation { @@ -49,7 +50,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation static Windows::Foundation::Collections::ValueSet CreateSettings(const winrt::hstring& cmdline, const winrt::hstring& startingDirectory, const winrt::hstring& startingTitle, - const Windows::Foundation::Collections::IMapView& environment, + bool reloadEnvironmentVariables, + const winrt::hstring& initialEnvironment, + const Windows::Foundation::Collections::IMapView& environmentOverrides, uint32_t rows, uint32_t columns, const winrt::guid& guid, @@ -91,7 +94,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation std::array _buffer{}; bool _passthroughMode{}; bool _inheritCursor{ false }; - bool _reloadEnvironmentVariables{}; + + til::env _initialEnv{}; guid _profileGuid{}; struct StartupInfoFromDefTerm diff --git a/src/cascadia/TerminalConnection/ConptyConnection.idl b/src/cascadia/TerminalConnection/ConptyConnection.idl index c9928d5c425..5cc0fb6f1d8 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.idl +++ b/src/cascadia/TerminalConnection/ConptyConnection.idl @@ -28,7 +28,9 @@ namespace Microsoft.Terminal.TerminalConnection static Windows.Foundation.Collections.ValueSet CreateSettings(String cmdline, String startingDirectory, String startingTitle, - IMapView environment, + Boolean reloadEnvironmentVariables, + String initialEnvironment, + IMapView environmentOverrides, UInt32 rows, UInt32 columns, Guid guid, diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h index 0946d9146ad..0117861d2de 100644 --- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h +++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h @@ -104,7 +104,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation OBSERVABLE_PROJECTED_SETTING(_profile, BellStyle); OBSERVABLE_PROJECTED_SETTING(_profile, UseAtlasEngine); OBSERVABLE_PROJECTED_SETTING(_profile, Elevate); - OBSERVABLE_PROJECTED_SETTING(_profile, VtPassthrough) + OBSERVABLE_PROJECTED_SETTING(_profile, VtPassthrough); + OBSERVABLE_PROJECTED_SETTING(_profile, ReloadEnvironmentVariables); WINRT_PROPERTY(bool, IsBaseLayer, false); WINRT_PROPERTY(bool, FocusDeleteButton, false); diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl index ab0bcbf2ffb..e8517be3995 100644 --- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl +++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl @@ -106,5 +106,6 @@ namespace Microsoft.Terminal.Settings.Editor OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAtlasEngine); OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, Elevate); OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, VtPassthrough); + OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, ReloadEnvironmentVariables); } } diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.xaml b/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.xaml index b17296fe0ae..31a93782546 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.xaml +++ b/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.xaml @@ -136,6 +136,15 @@ + + + + + diff --git a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw index 85a19334d4f..630bcd87dd0 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw @@ -1142,6 +1142,14 @@ Use the new text renderer ("AtlasEngine") {Locked="AtlasEngine"} + + Launch this application with a new environment block + "environment variables" are user-definable values that can affect the way running processes will behave on a computer + + + When enabled, the Terminal will generate a new environment block when creating new tabs or panes with this profile. When disabled, the tab/pane will instead inherit the variables the Terminal was started with. + A description for what the "Reload environment variables" setting does. Presented near "Profile_ReloadEnvVars". + Enable experimental virtual terminal passthrough An option to enable experimental virtual terminal passthrough connectivity option with the underlying ConPTY diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h index 30367fdae37..5f85e67f33e 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h @@ -300,6 +300,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation ACTION_ARG(Windows::Foundation::IReference, SuppressApplicationTitle, nullptr); ACTION_ARG(winrt::hstring, ColorScheme); ACTION_ARG(Windows::Foundation::IReference, Elevate, nullptr); + ACTION_ARG(Windows::Foundation::IReference, ReloadEnvironmentVariables, nullptr); ACTION_ARG(uint64_t, ContentId); static constexpr std::string_view CommandlineKey{ "commandline" }; @@ -311,6 +312,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation static constexpr std::string_view SuppressApplicationTitleKey{ "suppressApplicationTitle" }; static constexpr std::string_view ColorSchemeKey{ "colorScheme" }; static constexpr std::string_view ElevateKey{ "elevate" }; + static constexpr std::string_view ReloadEnvironmentVariablesKey{ "reloadEnvironmentVariables" }; static constexpr std::string_view ContentKey{ "__content" }; public: @@ -331,6 +333,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation otherAsUs->_SuppressApplicationTitle == _SuppressApplicationTitle && otherAsUs->_ColorScheme == _ColorScheme && otherAsUs->_Elevate == _Elevate && + otherAsUs->_ReloadEnvironmentVariables == _ReloadEnvironmentVariables && otherAsUs->_ContentId == _ContentId; } return false; @@ -348,6 +351,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation JsonUtils::GetValueForKey(json, SuppressApplicationTitleKey, args->_SuppressApplicationTitle); JsonUtils::GetValueForKey(json, ColorSchemeKey, args->_ColorScheme); JsonUtils::GetValueForKey(json, ElevateKey, args->_Elevate); + JsonUtils::GetValueForKey(json, ReloadEnvironmentVariablesKey, args->_ReloadEnvironmentVariables); JsonUtils::GetValueForKey(json, ContentKey, args->_ContentId); return *args; } @@ -368,6 +372,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation JsonUtils::SetValueForKey(json, SuppressApplicationTitleKey, args->_SuppressApplicationTitle); JsonUtils::SetValueForKey(json, ColorSchemeKey, args->_ColorScheme); JsonUtils::SetValueForKey(json, ElevateKey, args->_Elevate); + JsonUtils::SetValueForKey(json, ReloadEnvironmentVariablesKey, args->_ReloadEnvironmentVariables); JsonUtils::SetValueForKey(json, ContentKey, args->_ContentId); return json; } @@ -383,6 +388,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_SuppressApplicationTitle = _SuppressApplicationTitle; copy->_ColorScheme = _ColorScheme; copy->_Elevate = _Elevate; + copy->_ReloadEnvironmentVariables = _ReloadEnvironmentVariables; copy->_ContentId = _ContentId; return *copy; } @@ -403,6 +409,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation h.write(SuppressApplicationTitle()); h.write(ColorScheme()); h.write(Elevate()); + h.write(ReloadEnvironmentVariables()); h.write(ContentId()); } }; diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl index 06b81964481..86b9fe43ff6 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl @@ -137,6 +137,8 @@ namespace Microsoft.Terminal.Settings.Model // This needs to be an optional so that the default value (null) does // not modify whatever the profile's value is (either true or false) Windows.Foundation.IReference Elevate; + // Similarly with ReloadEnvironmentVariables + Windows.Foundation.IReference ReloadEnvironmentVariables; UInt64 ContentId{ get; set; }; diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp index 3063f549494..7f2f15d42e3 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp @@ -450,6 +450,17 @@ bool SettingsLoader::FixupUserSettings() } } + // Terminal 1.19: Migrate the global + // `compatibility.reloadEnvironmentVariables` to being a per-profile + // setting. If the user had it disabled in 1.18, then set the + // profiles.defaults value to false to match. + if (!userSettings.globals->LegacyReloadEnvironmentVariables()) + { + // migrate the user's opt-out to the profiles.defaults + userSettings.baseLayerProfile->ReloadEnvironmentVariables(false); + fixedUp = true; + } + return fixedUp; } diff --git a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp index dff11656140..1caef96b2cf 100644 --- a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp @@ -20,6 +20,7 @@ static constexpr std::string_view ActionsKey{ "actions" }; static constexpr std::string_view ThemeKey{ "theme" }; static constexpr std::string_view DefaultProfileKey{ "defaultProfile" }; static constexpr std::string_view LegacyUseTabSwitcherModeKey{ "useTabSwitcher" }; +static constexpr std::string_view LegacyReloadEnvironmentVariablesKey{ "compatibility.reloadEnvironmentVariables" }; // Method Description: // - Copies any extraneous data from the parent before completing a CreateChild call @@ -157,6 +158,8 @@ void GlobalAppSettings::LayerJson(const Json::Value& json) _keybindingsWarnings.insert(_keybindingsWarnings.end(), warnings.begin(), warnings.end()); } } + + JsonUtils::GetValueForKey(json, LegacyReloadEnvironmentVariablesKey, _legacyReloadEnvironmentVariables); } // Method Description: diff --git a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.h b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.h index 8ef1a8a2f72..3ccc0972bea 100644 --- a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.h +++ b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.h @@ -67,6 +67,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation void ExpandCommands(const Windows::Foundation::Collections::IVectorView& profiles, const Windows::Foundation::Collections::IMapView& schemes); + bool LegacyReloadEnvironmentVariables() const noexcept { return _legacyReloadEnvironmentVariables; } + INHERITABLE_SETTING(Model::GlobalAppSettings, hstring, UnparsedDefaultProfile, L""); #define GLOBAL_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \ @@ -82,6 +84,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation #endif winrt::guid _defaultProfile; + bool _legacyReloadEnvironmentVariables{ true }; winrt::com_ptr _actionMap{ winrt::make_self() }; std::vector _keybindingsWarnings; diff --git a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl index a9745cf7804..a02c3f06ffa 100644 --- a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl +++ b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl @@ -79,7 +79,6 @@ namespace Microsoft.Terminal.Settings.Model INHERITABLE_SETTING(Boolean, ForceFullRepaintRendering); INHERITABLE_SETTING(Boolean, SoftwareRendering); INHERITABLE_SETTING(Boolean, UseBackgroundImageForWindow); - INHERITABLE_SETTING(Boolean, ReloadEnvironmentVariables); INHERITABLE_SETTING(Boolean, ForceVTInput); INHERITABLE_SETTING(Boolean, DebugFeaturesEnabled); INHERITABLE_SETTING(Boolean, StartOnUserLogin); diff --git a/src/cascadia/TerminalSettingsModel/MTSMSettings.h b/src/cascadia/TerminalSettingsModel/MTSMSettings.h index 544366fcea1..d8caee04b91 100644 --- a/src/cascadia/TerminalSettingsModel/MTSMSettings.h +++ b/src/cascadia/TerminalSettingsModel/MTSMSettings.h @@ -27,7 +27,6 @@ Author(s): X(bool, ForceFullRepaintRendering, "experimental.rendering.forceFullRepaint", false) \ X(bool, SoftwareRendering, "experimental.rendering.software", false) \ X(bool, UseBackgroundImageForWindow, "experimental.useBackgroundImageForWindow", false) \ - X(bool, ReloadEnvironmentVariables, "compatibility.reloadEnvironmentVariables", true) \ X(bool, ForceVTInput, "experimental.input.forceVT", false) \ X(bool, TrimBlockSelection, "trimBlockSelection", true) \ X(bool, DetectURLs, "experimental.detectURLs", true) \ @@ -89,7 +88,8 @@ Author(s): X(bool, Elevate, "elevate", false) \ X(bool, VtPassthrough, "experimental.connection.passthroughMode", false) \ X(bool, AutoMarkPrompts, "experimental.autoMarkPrompts", false) \ - X(bool, ShowMarks, "experimental.showMarksOnScrollbar", false) + X(bool, ShowMarks, "experimental.showMarksOnScrollbar", false) \ + X(bool, ReloadEnvironmentVariables, "compatibility.reloadEnvironmentVariables", true) // Intentionally omitted Profile settings: // * Name diff --git a/src/cascadia/TerminalSettingsModel/Profile.idl b/src/cascadia/TerminalSettingsModel/Profile.idl index f6ab00a26c9..ddf5c78a6d6 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.idl +++ b/src/cascadia/TerminalSettingsModel/Profile.idl @@ -94,5 +94,8 @@ namespace Microsoft.Terminal.Settings.Model INHERITABLE_PROFILE_SETTING(Boolean, ShowMarks); INHERITABLE_PROFILE_SETTING(Boolean, RightClickContextMenu); + + INHERITABLE_PROFILE_SETTING(Boolean, ReloadEnvironmentVariables); + } } diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp index a69ba7086b4..a6de9a49203 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp @@ -178,6 +178,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { defaultSettings.Elevate(newTerminalArgs.Elevate().Value()); } + + if (newTerminalArgs.ReloadEnvironmentVariables()) + { + defaultSettings.ReloadEnvironmentVariables(newTerminalArgs.ReloadEnvironmentVariables().Value()); + } } return settingsPair; @@ -325,6 +330,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation _ShowMarks = Feature_ScrollbarMarks::IsEnabled() && profile.ShowMarks(); _RightClickContextMenu = profile.RightClickContextMenu(); + + _ReloadEnvironmentVariables = profile.ReloadEnvironmentVariables(); } // Method Description: diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.h b/src/cascadia/TerminalSettingsModel/TerminalSettings.h index 7df75e1ab5c..a13ea9e41df 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.h @@ -165,6 +165,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::TerminalSettings, bool, ShowMarks, false); INHERITABLE_SETTING(Model::TerminalSettings, bool, RightClickContextMenu, false); + INHERITABLE_SETTING(Model::TerminalSettings, bool, ReloadEnvironmentVariables, true); + private: std::optional> _ColorTable; std::span _getColorTableImpl(); diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.idl b/src/cascadia/TerminalSettingsModel/TerminalSettings.idl index 3bc2c72ed0e..23c305ee4e0 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.idl +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.idl @@ -45,5 +45,6 @@ namespace Microsoft.Terminal.Settings.Model String StartingDirectory { set; }; Boolean Elevate; + Boolean ReloadEnvironmentVariables; }; } diff --git a/src/cascadia/TerminalSettingsModel/pch.h b/src/cascadia/TerminalSettingsModel/pch.h index 75b789ed581..133786e5dae 100644 --- a/src/cascadia/TerminalSettingsModel/pch.h +++ b/src/cascadia/TerminalSettingsModel/pch.h @@ -58,6 +58,7 @@ TRACELOGGING_DECLARE_PROVIDER(g_hSettingsModelProvider); // Manually include til after we include Windows.Foundation to give it winrt superpowers #include "til.h" +#include #include #include diff --git a/src/cascadia/UnitTests_Remoting/RemotingTests.cpp b/src/cascadia/UnitTests_Remoting/RemotingTests.cpp index 0b8a07ddfe1..7dec3c052e6 100644 --- a/src/cascadia/UnitTests_Remoting/RemotingTests.cpp +++ b/src/cascadia/UnitTests_Remoting/RemotingTests.cpp @@ -431,7 +431,7 @@ namespace RemotingUnitTests m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper); std::vector args{}; - Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow()); @@ -468,7 +468,7 @@ namespace RemotingUnitTests }); std::vector args{ L"1", L"arg[1]" }; - Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow()); @@ -489,7 +489,7 @@ namespace RemotingUnitTests { std::vector args{ L"-1" }; - Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow()); @@ -497,7 +497,7 @@ namespace RemotingUnitTests } { std::vector args{ L"-2" }; - Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow()); @@ -534,7 +534,7 @@ namespace RemotingUnitTests winrt::clock().now() }; p1->ActivateWindow(activatedArgs); - Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow()); @@ -559,7 +559,7 @@ namespace RemotingUnitTests p2->ActivateWindow(activatedArgs); Log::Comment(L"Send a commandline to the current window, which should be p2"); - Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow()); VERIFY_ARE_EQUAL(false, (bool)result.Id()); @@ -572,7 +572,7 @@ namespace RemotingUnitTests p1->ActivateWindow(activatedArgs); Log::Comment(L"Send a commandline to the current window, which should be p1 again"); - Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow()); VERIFY_ARE_EQUAL(false, (bool)result.Id()); @@ -593,7 +593,7 @@ namespace RemotingUnitTests { std::vector args{ L"2" }; - Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow()); @@ -602,7 +602,7 @@ namespace RemotingUnitTests } { std::vector args{ L"10" }; - Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow()); @@ -648,7 +648,7 @@ namespace RemotingUnitTests { Log::Comment(L"Send a commandline to p2, who is still alive. We won't create a new window."); - Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow()); @@ -656,7 +656,7 @@ namespace RemotingUnitTests } { Log::Comment(L"Send a commandline to p1, who is dead. We will create a new window."); - Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow()); @@ -1359,7 +1359,7 @@ namespace RemotingUnitTests std::vector p2Args{ L"two", L"this is for p2" }; { - Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow()); VERIFY_ARE_EQUAL(false, (bool)result.Id()); // Casting to (bool) checks if the reference has a value @@ -1368,7 +1368,7 @@ namespace RemotingUnitTests { Log::Comment(L"Send a commandline to \"two\", which should be p2"); - Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow()); VERIFY_ARE_EQUAL(false, (bool)result.Id()); // Casting to (bool) checks if the reference has a value @@ -1380,7 +1380,7 @@ namespace RemotingUnitTests { Log::Comment(L"Send a commandline to \"two\", who is now dead."); - Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" }, SW_NORMAL, L"" }; auto result = m0->ProposeCommandline(eventArgs); VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow()); VERIFY_ARE_EQUAL(false, (bool)result.Id()); // Casting to (bool) checks if the reference has a value @@ -2392,7 +2392,7 @@ namespace RemotingUnitTests VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID()); std::vector commandlineArgs{ L"0", L"arg[1]" }; - Remoting::CommandlineArgs eventArgs{ { commandlineArgs }, { L"" }, SW_NORMAL }; + Remoting::CommandlineArgs eventArgs{ { commandlineArgs }, { L"" }, SW_NORMAL, L"" }; Log::Comment(L"When we attempt to send a commandline to the MRU window," L" we should find peasant 1 (who's name is \"one\"), not 2" @@ -2577,7 +2577,7 @@ namespace RemotingUnitTests auto m0 = make_private(monarch0PID); { - Remoting::CommandlineArgs args{ { L"wt.exe" }, { L"-Embedding" }, SW_NORMAL }; + Remoting::CommandlineArgs args{ { L"wt.exe" }, { L"-Embedding" }, SW_NORMAL, L"" }; const auto result = m0->ProposeCommandline(args); auto shouldCreateWindow = result.ShouldCreateWindow(); VERIFY_IS_TRUE(shouldCreateWindow); @@ -2585,7 +2585,7 @@ namespace RemotingUnitTests auto m1 = make_self(); { - Remoting::CommandlineArgs args{ { L"wt.exe" }, { L"-Embedding" }, SW_NORMAL }; + Remoting::CommandlineArgs args{ { L"wt.exe" }, { L"-Embedding" }, SW_NORMAL, L"" }; try { diff --git a/src/cascadia/UnitTests_Remoting/pch.h b/src/cascadia/UnitTests_Remoting/pch.h index 4ad6732bf6b..523f6305c3b 100644 --- a/src/cascadia/UnitTests_Remoting/pch.h +++ b/src/cascadia/UnitTests_Remoting/pch.h @@ -49,3 +49,4 @@ Licensed under the MIT license. #include "../../inc/DefaultSettings.h" #include +#include diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index f98e5cfaec1..87049b82da1 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -154,7 +154,7 @@ void AppHost::_HandleCommandlineArgs(const Remoting::WindowRequestedArgs& window } else if (args) { - const auto result = _windowLogic.SetStartupCommandline(args.Commandline(), args.CurrentDirectory()); + const auto result = _windowLogic.SetStartupCommandline(args.Commandline(), args.CurrentDirectory(), args.CurrentEnvironment()); const auto message = _windowLogic.ParseCommandlineMessage(); if (!message.empty()) { @@ -898,7 +898,7 @@ void AppHost::_DispatchCommandline(winrt::Windows::Foundation::IInspectable send // Summon the window whenever we dispatch a commandline to it. This will // make it obvious when a new tab/pane is created in a window. _HandleSummon(sender, summonArgs); - _windowLogic.ExecuteCommandline(args.Commandline(), args.CurrentDirectory()); + _windowLogic.ExecuteCommandline(args.Commandline(), args.CurrentDirectory(), args.CurrentEnvironment()); } void AppHost::_WindowActivated(bool activated) diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.cpp b/src/cascadia/WindowsTerminal/WindowEmperor.cpp index 23aba3d683e..47a11bba38e 100644 --- a/src/cascadia/WindowsTerminal/WindowEmperor.cpp +++ b/src/cascadia/WindowsTerminal/WindowEmperor.cpp @@ -12,6 +12,7 @@ #include "resource.h" #include "NotificationIcon.h" +#include using namespace winrt; using namespace winrt::Microsoft::Terminal; @@ -105,7 +106,9 @@ bool WindowEmperor::HandleCommandlineArgs() GetStartupInfoW(&si); const uint32_t showWindow = WI_IsFlagSet(si.dwFlags, STARTF_USESHOWWINDOW) ? si.wShowWindow : SW_SHOW; - Remoting::CommandlineArgs eventArgs{ { args }, { cwd }, showWindow }; + const auto currentEnv{ til::env::from_current_environment() }; + + Remoting::CommandlineArgs eventArgs{ { args }, { cwd }, showWindow, winrt::hstring{ currentEnv.to_string() } }; const auto isolatedMode{ _app.Logic().IsolatedMode() }; diff --git a/src/inc/til/env.h b/src/inc/til/env.h index 36b682cfbd3..4d95f9f2f98 100644 --- a/src/inc/til/env.h +++ b/src/inc/til/env.h @@ -559,7 +559,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" get_vars_from_registry(HKEY_CURRENT_USER, fmt::format(til::details::vars::reg::user_volatile_session_env_var_root_pattern, NtCurrentTeb()->ProcessEnvironmentBlock->SessionId)); } - std::wstring to_string() + std::wstring to_string() const { std::wstring result; for (const auto& [name, value] : _envMap)