From 816f8b2026368a4af12476d4c7de946acb238a7e Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 1 May 2023 14:19:22 -0500 Subject: [PATCH 01/11] dirty: stash a string as a "virtual" CWD, ala #5506 In the dirtiest way possible, this seems to work for most "start with this CWD" scenarios. --- src/cascadia/Remoting/Peasant.idl | 2 +- src/cascadia/TerminalApp/TerminalPage.cpp | 34 ++++++++++++++++----- src/cascadia/TerminalApp/TerminalPage.idl | 2 ++ src/cascadia/TerminalApp/TerminalWindow.cpp | 5 ++- src/cascadia/TerminalApp/TerminalWindow.h | 7 ++++- src/cascadia/TerminalApp/TerminalWindow.idl | 2 +- src/cascadia/WindowsTerminal/AppHost.cpp | 2 +- 7 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/cascadia/Remoting/Peasant.idl b/src/cascadia/Remoting/Peasant.idl index 89e2b52db2c..64ff512a1b4 100644 --- a/src/cascadia/Remoting/Peasant.idl +++ b/src/cascadia/Remoting/Peasant.idl @@ -10,7 +10,7 @@ namespace Microsoft.Terminal.Remoting CommandlineArgs(String[] args, String cwd, UInt32 showWindowCommand); String[] Commandline { get; set; }; - String CurrentDirectory(); + String CurrentDirectory { get; }; UInt32 ShowWindowCommand { get; }; }; diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 99a1fdafde9..3b4becfcfe7 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -554,13 +554,24 @@ namespace winrt::TerminalApp::implementation // back once we're done. This looks weird though, because we have to set // up the scope_exit _first_. We'll release the scope_exit if we don't // actually need it. - auto originalCwd{ wil::GetCurrentDirectoryW() }; - auto restoreCwd = wil::scope_exit([&originalCwd]() { + // auto originalRealCwd{ wil::GetCurrentDirectoryW() }; + + if (initial) + { + // _WindowProperties.VirtualWorkingDirectory(cwd.empty() ? originalRealCwd.c_str() : cwd.c_str()); + LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(L"%SystemRoot%\\System32")); + } + + auto originalVirtualCwd{ _WindowProperties.VirtualWorkingDirectory() }; + auto restoreCwd = wil::scope_exit([&originalVirtualCwd, this /*&originalCwd, &initial*/]() { // ignore errors, we'll just power on through. We'd rather do // something rather than fail silently if the directory doesn't // actually exist. - LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(originalCwd.c_str())); + // LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(L"%SystemRoot%\\System32")); + + _WindowProperties.VirtualWorkingDirectory(originalVirtualCwd); }); + if (cwd.empty()) { restoreCwd.release(); @@ -570,9 +581,15 @@ namespace winrt::TerminalApp::implementation // ignore errors, we'll just power on through. We'd rather do // something rather than fail silently if the directory doesn't // actually exist. - LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(cwd.c_str())); + // LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(cwd.c_str())); + _WindowProperties.VirtualWorkingDirectory(cwd); } + // if (initial) + // { + // _WindowProperties.VirtualWorkingDirectory(cwd.empty() ? originalCwd : cwd); + // } + if (auto page{ weakThis.get() }) { for (const auto& action : actions) @@ -1226,10 +1243,13 @@ namespace winrt::TerminalApp::implementation // process until later, on another thread, after we've already // restored the CWD to its original value. auto newWorkingDirectory{ settings.StartingDirectory() }; - if (newWorkingDirectory.size() == 0 || newWorkingDirectory.size() == 1 && - !(newWorkingDirectory[0] == L'~' || newWorkingDirectory[0] == L'/')) + const bool looksLikeLinux = newWorkingDirectory.size() == 1 && + (newWorkingDirectory[0] == L'~' || newWorkingDirectory[0] == L'/'); + // if (newWorkingDirectory.size() == 0 || looksLikeLinux) + if (!looksLikeLinux) { // We only want to resolve the new WD against the CWD if it doesn't look like a Linux path (see GH#592) - auto cwdString{ wil::GetCurrentDirectoryW() }; + // auto cwdString{ wil::GetCurrentDirectoryW() }; + auto cwdString{ _WindowProperties.VirtualWorkingDirectory().c_str() }; std::filesystem::path cwd{ cwdString }; cwd /= settings.StartingDirectory().c_str(); newWorkingDirectory = winrt::hstring{ cwd.wstring() }; diff --git a/src/cascadia/TerminalApp/TerminalPage.idl b/src/cascadia/TerminalApp/TerminalPage.idl index 92052ed1677..4375c000738 100644 --- a/src/cascadia/TerminalApp/TerminalPage.idl +++ b/src/cascadia/TerminalApp/TerminalPage.idl @@ -51,6 +51,8 @@ namespace TerminalApp String WindowNameForDisplay { get; }; String WindowIdForDisplay { get; }; + String VirtualWorkingDirectory { get; set; }; + Boolean IsQuakeWindow(); }; diff --git a/src/cascadia/TerminalApp/TerminalWindow.cpp b/src/cascadia/TerminalApp/TerminalWindow.cpp index e62d25c4e99..ebbb04b8428 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.cpp +++ b/src/cascadia/TerminalApp/TerminalWindow.cpp @@ -1013,8 +1013,10 @@ 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) + int32_t TerminalWindow::SetStartupCommandline(array_view args, winrt::hstring cwd) { + _WindowProperties->SetInitialCwd(cwd); + // This is called in AppHost::ctor(), before we've created the window // (or called TerminalWindow::Initialize) const auto result = _appArgs.ParseArgs(args); @@ -1336,6 +1338,7 @@ namespace winrt::TerminalApp::implementation CATCH_LOG(); } } + uint64_t WindowProperties::WindowId() const noexcept { return _WindowId; diff --git a/src/cascadia/TerminalApp/TerminalWindow.h b/src/cascadia/TerminalApp/TerminalWindow.h index 2d288ccfddf..fa5e0cd3884 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.h +++ b/src/cascadia/TerminalApp/TerminalWindow.h @@ -48,8 +48,13 @@ namespace winrt::TerminalApp::implementation winrt::hstring WindowNameForDisplay() const noexcept; bool IsQuakeWindow() const noexcept; + WINRT_OBSERVABLE_PROPERTY(winrt::hstring, VirtualWorkingDirectory, _PropertyChangedHandlers, L""); + WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); + public: + void SetInitialCwd(const winrt::hstring& cwd) { _VirtualWorkingDirectory = cwd; }; + private: winrt::hstring _WindowName{}; uint64_t _WindowId{ 0 }; @@ -71,7 +76,7 @@ namespace winrt::TerminalApp::implementation bool HasCommandlineArguments() const noexcept; - int32_t SetStartupCommandline(array_view actions); + int32_t SetStartupCommandline(array_view actions, winrt::hstring cwd); void SetStartupContent(const winrt::hstring& content, const Windows::Foundation::IReference& contentBounds); int32_t ExecuteCommandline(array_view actions, const winrt::hstring& cwd); void SetSettingsStartupArgs(const std::vector& actions); diff --git a/src/cascadia/TerminalApp/TerminalWindow.idl b/src/cascadia/TerminalApp/TerminalWindow.idl index 912663e4a0b..d91de2dce88 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.idl +++ b/src/cascadia/TerminalApp/TerminalWindow.idl @@ -53,7 +53,7 @@ namespace TerminalApp Boolean HasCommandlineArguments(); - Int32 SetStartupCommandline(String[] commands); + Int32 SetStartupCommandline(String[] commands, String cwd); void SetStartupContent(String json, Windows.Foundation.IReference bounds); Int32 ExecuteCommandline(String[] commands, String cwd); String ParseCommandlineMessage { get; }; diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index 163d056df88..b80ec25777a 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -175,7 +175,7 @@ void AppHost::_HandleCommandlineArgs(const Remoting::WindowRequestedArgs& window } else if (args) { - const auto result = _windowLogic.SetStartupCommandline(args.Commandline()); + const auto result = _windowLogic.SetStartupCommandline(args.Commandline(), args.CurrentDirectory()); const auto message = _windowLogic.ParseCommandlineMessage(); if (!message.empty()) { From 03e60443e5dc8c1ac4ab34ee44552ff8cc278c57 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 May 2023 08:48:12 -0500 Subject: [PATCH 02/11] cleanup for review --- src/cascadia/TerminalApp/TerminalPage.cpp | 31 +++++-------------- src/cascadia/TerminalApp/TerminalWindow.cpp | 1 + src/cascadia/TerminalApp/TerminalWindow.h | 1 + .../WindowsTerminal/WindowEmperor.cpp | 6 +++- 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 3b4becfcfe7..d311c0f1da5 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -550,46 +550,30 @@ namespace winrt::TerminalApp::implementation // Handle it on a subsequent pass of the UI thread. co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal); - // If the caller provided a CWD, switch to that directory, then switch + // If the caller provided a CWD, "switch" to that directory, then switch // back once we're done. This looks weird though, because we have to set // up the scope_exit _first_. We'll release the scope_exit if we don't // actually need it. - // auto originalRealCwd{ wil::GetCurrentDirectoryW() }; - - if (initial) - { - // _WindowProperties.VirtualWorkingDirectory(cwd.empty() ? originalRealCwd.c_str() : cwd.c_str()); - LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(L"%SystemRoot%\\System32")); - } auto originalVirtualCwd{ _WindowProperties.VirtualWorkingDirectory() }; - auto restoreCwd = wil::scope_exit([&originalVirtualCwd, this /*&originalCwd, &initial*/]() { + auto restoreCwd = wil::scope_exit([&originalVirtualCwd, this]() { // ignore errors, we'll just power on through. We'd rather do // something rather than fail silently if the directory doesn't // actually exist. - // LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(L"%SystemRoot%\\System32")); - _WindowProperties.VirtualWorkingDirectory(originalVirtualCwd); }); if (cwd.empty()) { + // We didn't actually need to change the virtual CWD, so we don't + // need to restore it restoreCwd.release(); } else { - // ignore errors, we'll just power on through. We'd rather do - // something rather than fail silently if the directory doesn't - // actually exist. - // LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(cwd.c_str())); _WindowProperties.VirtualWorkingDirectory(cwd); } - // if (initial) - // { - // _WindowProperties.VirtualWorkingDirectory(cwd.empty() ? originalCwd : cwd); - // } - if (auto page{ weakThis.get() }) { for (const auto& action : actions) @@ -1245,11 +1229,10 @@ namespace winrt::TerminalApp::implementation auto newWorkingDirectory{ settings.StartingDirectory() }; const bool looksLikeLinux = newWorkingDirectory.size() == 1 && (newWorkingDirectory[0] == L'~' || newWorkingDirectory[0] == L'/'); - // if (newWorkingDirectory.size() == 0 || looksLikeLinux) + // We only want to resolve the new WD against the CWD if it doesn't look like a Linux path (see GH#592) if (!looksLikeLinux) - { // We only want to resolve the new WD against the CWD if it doesn't look like a Linux path (see GH#592) - // auto cwdString{ wil::GetCurrentDirectoryW() }; - auto cwdString{ _WindowProperties.VirtualWorkingDirectory().c_str() }; + { + const auto cwdString{ _WindowProperties.VirtualWorkingDirectory().c_str() }; std::filesystem::path cwd{ cwdString }; cwd /= settings.StartingDirectory().c_str(); newWorkingDirectory = winrt::hstring{ cwd.wstring() }; diff --git a/src/cascadia/TerminalApp/TerminalWindow.cpp b/src/cascadia/TerminalApp/TerminalWindow.cpp index ebbb04b8428..39afdd1278a 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.cpp +++ b/src/cascadia/TerminalApp/TerminalWindow.cpp @@ -1010,6 +1010,7 @@ namespace winrt::TerminalApp::implementation // returned. // Arguments: // - args: an array of strings to process as a commandline. These args can contain spaces + // - cwd: The CWD that this window should treat as its own "virtual" CWD // Return Value: // - the result of the first command who's parsing returned a non-zero code, // or 0. (see TerminalWindow::_ParseArgs) diff --git a/src/cascadia/TerminalApp/TerminalWindow.h b/src/cascadia/TerminalApp/TerminalWindow.h index fa5e0cd3884..fb3100ea7f8 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.h +++ b/src/cascadia/TerminalApp/TerminalWindow.h @@ -53,6 +53,7 @@ namespace winrt::TerminalApp::implementation WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); public: + // Used for setting the initial CWD, before we have XAML set up for property change notifications. void SetInitialCwd(const winrt::hstring& cwd) { _VirtualWorkingDirectory = cwd; }; private: diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.cpp b/src/cascadia/WindowsTerminal/WindowEmperor.cpp index e847547c01e..e8129ca3011 100644 --- a/src/cascadia/WindowsTerminal/WindowEmperor.cpp +++ b/src/cascadia/WindowsTerminal/WindowEmperor.cpp @@ -71,7 +71,11 @@ bool WindowEmperor::HandleCommandlineArgs() { std::vector args; _buildArgsFromCommandline(args); - auto cwd{ wil::GetCurrentDirectoryW() }; + const auto cwd{ wil::GetCurrentDirectoryW() }; + + // ALWAYS change the _real_ CWD of the Terminal to system32, so that we + // don't lock the directory we were spawned in. + LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(L"%SystemRoot%\\System32")); // Get the requested initial state of the window from our startup info. For // something like `start /min`, this will set the wShowWindow member to From 553f48d38efc7c82f1b58fb7d50dc7ae1006f14d Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 1 May 2023 14:20:00 -0500 Subject: [PATCH 03/11] a toast for showing the CWD of the Terminal. This is for debugging (cherry picked from commit 072620625abcac06f4dac94d9a4a484395cf6bdc) --- .../TerminalApp/AppActionHandlers.cpp | 7 +++++ .../Resources/en-US/Resources.resw | 5 +++- src/cascadia/TerminalApp/TerminalPage.cpp | 27 +++++++++++++++++++ src/cascadia/TerminalApp/TerminalPage.h | 2 ++ src/cascadia/TerminalApp/TerminalPage.xaml | 7 +++++ .../TerminalSettingsModel/ActionAndArgs.cpp | 2 ++ .../AllShortcutActions.h | 1 + .../TerminalSettingsModel/defaults.json | 1 + 8 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 43fa9630a6a..cda4afce5f1 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -1021,6 +1021,13 @@ namespace winrt::TerminalApp::implementation args.Handled(true); } + void TerminalPage::_HandleDisplayWorkingDirectory(const IInspectable& /*sender*/, + const ActionEventArgs& args) + { + ShowTerminalWorkingDirectory(); + args.Handled(true); + } + void TerminalPage::_HandleGlobalSummon(const IInspectable& /*sender*/, const ActionEventArgs& args) { diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index f8f45105018..0322b1da9d8 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -700,6 +700,9 @@ Another window with that name already exists + + This is the CWD of the Terminal window itself + Maximize @@ -823,4 +826,4 @@ Close the active pane if multiple panes are present - \ No newline at end of file + diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index d311c0f1da5..8fae8601bdb 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -4050,6 +4050,33 @@ namespace winrt::TerminalApp::implementation } } + winrt::fire_and_forget TerminalPage::ShowTerminalWorkingDirectory() + { + auto weakThis{ get_weak() }; + co_await wil::resume_foreground(Dispatcher()); + if (auto page{ weakThis.get() }) + { + // If we haven't ever loaded the TeachingTip, then do so now and + // create the toast for it. + if (page->_windowCwdToast == nullptr) + { + if (auto tip{ page->FindName(L"WindowCwdToast").try_as() }) + { + page->_windowCwdToast = std::make_shared(tip); + // Make sure to use the weak ref when setting up this + // callback. + tip.Closed({ page->get_weak(), &TerminalPage::_FocusActiveControl }); + } + } + _UpdateTeachingTipTheme(WindowCwdToast().try_as()); + + if (page->_windowCwdToast != nullptr) + { + page->_windowCwdToast->Open(); + } + } + } + // Method Description: // - Called when the user hits the "Ok" button on the WindowRenamer TeachingTip. // - Will raise an event that will bubble up to the monarch, asking if this diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 867e93eece3..95c291ee202 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -149,6 +149,7 @@ namespace winrt::TerminalApp::implementation winrt::fire_and_forget IdentifyWindow(); winrt::fire_and_forget RenameFailed(); + winrt::fire_and_forget ShowTerminalWorkingDirectory(); winrt::fire_and_forget ProcessStartupActions(Windows::Foundation::Collections::IVector actions, const bool initial, @@ -257,6 +258,7 @@ namespace winrt::TerminalApp::implementation std::shared_ptr _windowIdToast{ nullptr }; std::shared_ptr _windowRenameFailedToast{ nullptr }; + std::shared_ptr _windowCwdToast{ nullptr }; winrt::Windows::UI::Xaml::Controls::TextBox::LayoutUpdated_revoker _renamerLayoutUpdatedRevoker; int _renamerLayoutCount{ 0 }; diff --git a/src/cascadia/TerminalApp/TerminalPage.xaml b/src/cascadia/TerminalApp/TerminalPage.xaml index ade311fcde7..28c68df249a 100644 --- a/src/cascadia/TerminalApp/TerminalPage.xaml +++ b/src/cascadia/TerminalApp/TerminalPage.xaml @@ -205,5 +205,12 @@ Text="{x:Bind WindowProperties.WindowName, Mode=OneWay}" /> + + diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp index 3efeb81d5b7..9818a2e1c85 100644 --- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp @@ -72,6 +72,7 @@ static constexpr std::string_view IdentifyWindowKey{ "identifyWindow" }; static constexpr std::string_view IdentifyWindowsKey{ "identifyWindows" }; static constexpr std::string_view RenameWindowKey{ "renameWindow" }; static constexpr std::string_view OpenWindowRenamerKey{ "openWindowRenamer" }; +static constexpr std::string_view DisplayWorkingDirectoryKey{ "displayTerminalCwd" }; static constexpr std::string_view GlobalSummonKey{ "globalSummon" }; static constexpr std::string_view QuakeModeKey{ "quakeMode" }; static constexpr std::string_view FocusPaneKey{ "focusPane" }; @@ -401,6 +402,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { ShortcutAction::IdentifyWindows, RS_(L"IdentifyWindowsCommandKey") }, { ShortcutAction::RenameWindow, RS_(L"ResetWindowNameCommandKey") }, { ShortcutAction::OpenWindowRenamer, RS_(L"OpenWindowRenamerCommandKey") }, + { ShortcutAction::DisplayWorkingDirectory, L"Display Terminal's CWD TODO! localize" }, { ShortcutAction::GlobalSummon, MustGenerate }, { ShortcutAction::QuakeMode, RS_(L"QuakeModeCommandKey") }, { ShortcutAction::FocusPane, MustGenerate }, diff --git a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h index b6a2228b88c..328fd005885 100644 --- a/src/cascadia/TerminalSettingsModel/AllShortcutActions.h +++ b/src/cascadia/TerminalSettingsModel/AllShortcutActions.h @@ -85,6 +85,7 @@ ON_ALL_ACTIONS(IdentifyWindows) \ ON_ALL_ACTIONS(RenameWindow) \ ON_ALL_ACTIONS(OpenWindowRenamer) \ + ON_ALL_ACTIONS(DisplayWorkingDirectory) \ ON_ALL_ACTIONS(GlobalSummon) \ ON_ALL_ACTIONS(QuakeMode) \ ON_ALL_ACTIONS(FocusPane) \ diff --git a/src/cascadia/TerminalSettingsModel/defaults.json b/src/cascadia/TerminalSettingsModel/defaults.json index c67187e4528..f15392a366b 100644 --- a/src/cascadia/TerminalSettingsModel/defaults.json +++ b/src/cascadia/TerminalSettingsModel/defaults.json @@ -374,6 +374,7 @@ { "command": "openSystemMenu", "keys": "alt+space" }, { "command": "quit" }, { "command": "restoreLastClosed"}, + { "command": "displayTerminalCwd"}, // Tab Management // "command": "closeTab" is unbound by default. From c83f1747d6197fdbb2ca6f88778bf71d6c84c54c Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 May 2023 12:50:42 -0500 Subject: [PATCH 04/11] cleanup for review --- src/cascadia/TerminalApp/Resources/en-US/Resources.resw | 3 --- src/cascadia/TerminalApp/TerminalPage.cpp | 1 + src/cascadia/TerminalApp/TerminalPage.xaml | 3 +-- src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp | 2 +- .../TerminalSettingsModel/Resources/en-US/Resources.resw | 3 +++ 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index 0322b1da9d8..68f6ab537b1 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -700,9 +700,6 @@ Another window with that name already exists - - This is the CWD of the Terminal window itself - Maximize diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 8fae8601bdb..a2fdc028591 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -1229,6 +1229,7 @@ namespace winrt::TerminalApp::implementation auto newWorkingDirectory{ settings.StartingDirectory() }; const bool looksLikeLinux = newWorkingDirectory.size() == 1 && (newWorkingDirectory[0] == L'~' || newWorkingDirectory[0] == L'/'); + // We only want to resolve the new WD against the CWD if it doesn't look like a Linux path (see GH#592) if (!looksLikeLinux) { diff --git a/src/cascadia/TerminalApp/TerminalPage.xaml b/src/cascadia/TerminalApp/TerminalPage.xaml index 28c68df249a..00fb12f86b4 100644 --- a/src/cascadia/TerminalApp/TerminalPage.xaml +++ b/src/cascadia/TerminalApp/TerminalPage.xaml @@ -210,7 +210,6 @@ x:Uid="WindowCwdToast" Title="{x:Bind WindowProperties.VirtualWorkingDirectory, Mode=OneWay}" x:Load="False" - IsLightDismissEnabled="True" - Subtitle="{x:Bind WindowProperties.VirtualWorkingDirectory, Mode=OneWay}" /> + IsLightDismissEnabled="True" /> diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp index 9818a2e1c85..933e0d962b3 100644 --- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp @@ -402,7 +402,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { ShortcutAction::IdentifyWindows, RS_(L"IdentifyWindowsCommandKey") }, { ShortcutAction::RenameWindow, RS_(L"ResetWindowNameCommandKey") }, { ShortcutAction::OpenWindowRenamer, RS_(L"OpenWindowRenamerCommandKey") }, - { ShortcutAction::DisplayWorkingDirectory, L"Display Terminal's CWD TODO! localize" }, + { ShortcutAction::DisplayWorkingDirectory, RS_(L"DisplayWorkingDirectoryCommandKey") }, { ShortcutAction::GlobalSummon, MustGenerate }, { ShortcutAction::QuakeMode, RS_(L"QuakeModeCommandKey") }, { ShortcutAction::FocusPane, MustGenerate }, diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw index 0b6fced889b..221bfcb3429 100644 --- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -511,6 +511,9 @@ Rename window... + + Display Terminal's working directory + Show/Hide the Terminal window From 5c377d82cdaaa4f0e2c90808cdfb65597331c9e0 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 4 May 2023 13:27:17 -0500 Subject: [PATCH 05/11] cleanup from review --- src/cascadia/TerminalApp/TerminalPage.cpp | 8 ++++++-- src/cascadia/TerminalApp/TerminalWindow.cpp | 2 +- src/cascadia/TerminalApp/TerminalWindow.h | 2 +- src/cascadia/WindowsTerminal/WindowEmperor.cpp | 12 +++++++++--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index d311c0f1da5..adc675c4f2f 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -1232,9 +1232,13 @@ namespace winrt::TerminalApp::implementation // We only want to resolve the new WD against the CWD if it doesn't look like a Linux path (see GH#592) if (!looksLikeLinux) { - const auto cwdString{ _WindowProperties.VirtualWorkingDirectory().c_str() }; + const auto currentVirtualDir{ _WindowProperties.VirtualWorkingDirectory() }; + const auto cwdString{ std::wstring_view{ currentVirtualDir } }; + const auto requestedStartingDir{ settings.StartingDirectory() }; + std::filesystem::path cwd{ cwdString }; - cwd /= settings.StartingDirectory().c_str(); + cwd /= std::wstring_view{ requestedStartingDir }; + newWorkingDirectory = winrt::hstring{ cwd.wstring() }; } diff --git a/src/cascadia/TerminalApp/TerminalWindow.cpp b/src/cascadia/TerminalApp/TerminalWindow.cpp index 39afdd1278a..7f6daeb380d 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.cpp +++ b/src/cascadia/TerminalApp/TerminalWindow.cpp @@ -1016,7 +1016,7 @@ namespace winrt::TerminalApp::implementation // or 0. (see TerminalWindow::_ParseArgs) int32_t TerminalWindow::SetStartupCommandline(array_view args, winrt::hstring cwd) { - _WindowProperties->SetInitialCwd(cwd); + _WindowProperties->SetInitialCwd(std::move(cwd)); // This is called in AppHost::ctor(), before we've created the window // (or called TerminalWindow::Initialize) diff --git a/src/cascadia/TerminalApp/TerminalWindow.h b/src/cascadia/TerminalApp/TerminalWindow.h index fb3100ea7f8..a59c139a95c 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.h +++ b/src/cascadia/TerminalApp/TerminalWindow.h @@ -54,7 +54,7 @@ namespace winrt::TerminalApp::implementation public: // Used for setting the initial CWD, before we have XAML set up for property change notifications. - void SetInitialCwd(const winrt::hstring& cwd) { _VirtualWorkingDirectory = cwd; }; + void SetInitialCwd(winrt::hstring cwd) { _VirtualWorkingDirectory = std::move(cwd); }; private: winrt::hstring _WindowName{}; diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.cpp b/src/cascadia/WindowsTerminal/WindowEmperor.cpp index e8129ca3011..882f8d097ae 100644 --- a/src/cascadia/WindowsTerminal/WindowEmperor.cpp +++ b/src/cascadia/WindowsTerminal/WindowEmperor.cpp @@ -73,9 +73,15 @@ bool WindowEmperor::HandleCommandlineArgs() _buildArgsFromCommandline(args); const auto cwd{ wil::GetCurrentDirectoryW() }; - // ALWAYS change the _real_ CWD of the Terminal to system32, so that we - // don't lock the directory we were spawned in. - LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(L"%SystemRoot%\\System32")); + { + // ALWAYS change the _real_ CWD of the Terminal to system32, so that we + // don't lock the directory we were spawned in. + std::wstring system32{}; + if (SUCCEEDED_LOG(wil::GetSystemDirectoryW(system32))) + { + LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectoryW(system32.c_str())); + } + } // Get the requested initial state of the window from our startup info. For // something like `start /min`, this will set the wShowWindow member to From c01611d5556c18dfeaf7c94176d61ac1f4c91f3b Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 11 May 2023 16:51:16 -0500 Subject: [PATCH 06/11] start writing tests --- src/types/inc/utils.hpp | 3 +++ src/types/ut_types/UtilsTests.cpp | 24 ++++++++++++++++++++++++ src/types/utils.cpp | 28 ++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/src/types/inc/utils.hpp b/src/types/inc/utils.hpp index 45e16a049de..b8ce375f1ea 100644 --- a/src/types/inc/utils.hpp +++ b/src/types/inc/utils.hpp @@ -112,4 +112,7 @@ namespace Microsoft::Console::Utils // testing easier. std::wstring_view TrimPaste(std::wstring_view textView) noexcept; + // Same deal, but in TerminalPage::_evaluatePathForCwd + std::wstring EvaluateStartingDirectory(std::wstring_view cwd, std::wstring_view startingDirectory); + } diff --git a/src/types/ut_types/UtilsTests.cpp b/src/types/ut_types/UtilsTests.cpp index f6246df87df..9fa6c7abef8 100644 --- a/src/types/ut_types/UtilsTests.cpp +++ b/src/types/ut_types/UtilsTests.cpp @@ -33,6 +33,8 @@ class UtilsTests TEST_METHOD(TestTrimTrailingWhitespace); TEST_METHOD(TestDontTrimTrailingWhitespace); + TEST_METHOD(TestEvaluateStartingDirectory); + void _VerifyXTermColorResult(const std::wstring_view wstr, DWORD colorValue); void _VerifyXTermColorInvalid(const std::wstring_view wstr); }; @@ -546,3 +548,25 @@ void UtilsTests::TestDontTrimTrailingWhitespace() // * trim when there's a tab followed by only whitespace // * not trim then there's a tab in the middle, and the string ends in whitespace } + +void UtilsTests::TestEvaluateStartingDirectory() +{ + // Continue on failures + const WEX::TestExecution::DisableVerifyExceptions disableExceptionsScope; + + auto test = [](auto& expected, auto& cwd, auto& startingDir) { + VERIFY_ARE_EQUAL(expected, EvaluateStartingDirectory(cwd, startingDir)); + }; + + { + std::wstring cwd = L"C:\\Windows\\System32"; + + test(L"C:\\Windows", cwd, L"C:\\Windows"); + test(L"C:\\Windows\\System32\\System32", cwd, L".\\System32"); // ? + test(L"~", cwd, L"~"); + test(L"~/dev", cwd, L"~/dev"); + test(L"/", cwd, L"/"); + test(L"/dev", cwd, L"/dev"); + test(L"C:\\Windows\\System32\\dev", cwd, L"./dev"); + } +} diff --git a/src/types/utils.cpp b/src/types/utils.cpp index 94813bfc967..993a120f615 100644 --- a/src/types/utils.cpp +++ b/src/types/utils.cpp @@ -828,3 +828,31 @@ std::wstring_view Utils::TrimPaste(std::wstring_view textView) noexcept return textView.substr(0, lastNonSpace + 1); } + +std::wstring Utils::EvaluateStartingDirectory( + std::wstring_view currentDirectory, + std::wstring_view startingDirectory) +{ + std::wstring resultPath{ startingDirectory }; + + const bool oldCondition = + startingDirectory.size() == 0 || startingDirectory.size() == 1 && + !(startingDirectory[0] == L'~' || startingDirectory[0] == L'/'); + + oldCondition; + + const bool newCondition = + !(resultPath.size() == 1 && + (resultPath[0] == L'~' || resultPath[0] == L'/')); + newCondition; + + // We only want to resolve the new WD against the CWD if it doesn't look like a Linux path (see GH#592) + if (oldCondition) + // if (newCondition) + { + std::filesystem::path cwd{ currentDirectory }; + cwd /= startingDirectory; + resultPath = cwd.wstring(); + } + return resultPath; +} From 51a8df706d2a8772d52b60a5ca6987ca8a3b6779 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 12 May 2023 06:44:49 -0500 Subject: [PATCH 07/11] huzzah tests pass --- src/types/ut_types/UtilsTests.cpp | 44 +++++++++++++++++++++++++++++-- src/types/utils.cpp | 16 +++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/types/ut_types/UtilsTests.cpp b/src/types/ut_types/UtilsTests.cpp index 9fa6c7abef8..f83b1b4cad7 100644 --- a/src/types/ut_types/UtilsTests.cpp +++ b/src/types/ut_types/UtilsTests.cpp @@ -558,15 +558,55 @@ void UtilsTests::TestEvaluateStartingDirectory() VERIFY_ARE_EQUAL(expected, EvaluateStartingDirectory(cwd, startingDir)); }; + // A NOTE: EvaluateStartingDirectory makes no attempt to cannonicalize the + // path. So if you do any sort of relative paths, it'll literally just + // append. + { std::wstring cwd = L"C:\\Windows\\System32"; + // Literally blank + test(L"C:\\Windows\\System32\\", cwd, L""); + + // Absolute Windows path + test(L"C:\\Windows", cwd, L"C:\\Windows"); + test(L"C:/Users/migrie", cwd, L"C:/Users/migrie"); + + // Relative Windows path + test(L"C:\\Windows\\System32\\.", cwd, L"."); // ? + test(L"C:\\Windows\\System32\\.\\System32", cwd, L".\\System32"); // ? + test(L"C:\\Windows\\System32\\./dev", cwd, L"./dev"); + + // WSL '~' path + test(L"~", cwd, L"~"); + test(L"~/dev", cwd, L"~/dev"); + + // WSL or Windows / path - this will ultimately be evaluated by the connection + test(L"/", cwd, L"/"); + test(L"/dev", cwd, L"/dev"); + } + + { + std::wstring cwd = L"C:/Users/migrie"; + + // Literally blank + test(L"C:/Users/migrie\\", cwd, L""); + + // Absolute Windows path test(L"C:\\Windows", cwd, L"C:\\Windows"); - test(L"C:\\Windows\\System32\\System32", cwd, L".\\System32"); // ? + test(L"C:/Users/migrie", cwd, L"C:/Users/migrie"); + + // Relative Windows path + test(L"C:/Users/migrie\\.", cwd, L"."); // ? + test(L"C:/Users/migrie\\.\\System32", cwd, L".\\System32"); // ? + test(L"C:/Users/migrie\\./dev", cwd, L"./dev"); + + // WSL '~' path test(L"~", cwd, L"~"); test(L"~/dev", cwd, L"~/dev"); + + // WSL or Windows / path - this will ultimately be evaluated by the connection test(L"/", cwd, L"/"); test(L"/dev", cwd, L"/dev"); - test(L"C:\\Windows\\System32\\dev", cwd, L"./dev"); } } diff --git a/src/types/utils.cpp b/src/types/utils.cpp index 993a120f615..aca9e7c6cb4 100644 --- a/src/types/utils.cpp +++ b/src/types/utils.cpp @@ -846,9 +846,21 @@ std::wstring Utils::EvaluateStartingDirectory( (resultPath[0] == L'~' || resultPath[0] == L'/')); newCondition; - // We only want to resolve the new WD against the CWD if it doesn't look like a Linux path (see GH#592) - if (oldCondition) + // We only want to resolve the new WD against the CWD if it doesn't look + // like a Linux path (see GH#592) + + // Append only if it DOESN'T look like a linux-y path. + + const bool newest = !( + // the string is at least one char AND + // that first char is `~` or `/` + resultPath.size() >= 1 && + (resultPath[0] == L'~' || resultPath[0] == L'/')); + + newest; + // if (oldCondition) // if (newCondition) + if (newest) { std::filesystem::path cwd{ currentDirectory }; cwd /= startingDirectory; From 8c797f8a6d335e18afb1067f788888e133f890ab Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 12 May 2023 07:10:35 -0500 Subject: [PATCH 08/11] OKAY it works now --- src/cascadia/TerminalApp/TerminalPage.cpp | 21 ++++++------------ src/types/utils.cpp | 26 +++++------------------ 2 files changed, 11 insertions(+), 36 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 55d4c425c2e..e7a31d6c648 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -1227,21 +1227,12 @@ namespace winrt::TerminalApp::implementation // construction, because the connection might not spawn the child // process until later, on another thread, after we've already // restored the CWD to its original value. - auto newWorkingDirectory{ settings.StartingDirectory() }; - const bool looksLikeLinux = newWorkingDirectory.size() == 1 && - (newWorkingDirectory[0] == L'~' || newWorkingDirectory[0] == L'/'); - // We only want to resolve the new WD against the CWD if it doesn't look like a Linux path (see GH#592) - if (!looksLikeLinux) - { - const auto currentVirtualDir{ _WindowProperties.VirtualWorkingDirectory() }; - const auto cwdString{ std::wstring_view{ currentVirtualDir } }; - const auto requestedStartingDir{ settings.StartingDirectory() }; - - std::filesystem::path cwd{ cwdString }; - cwd /= std::wstring_view{ requestedStartingDir }; - - newWorkingDirectory = winrt::hstring{ cwd.wstring() }; - } + const auto currentVirtualDir{ _WindowProperties.VirtualWorkingDirectory() }; + const auto cwdString{ std::wstring_view{ currentVirtualDir } }; + const auto requestedStartingDir{ settings.StartingDirectory() }; + auto newWorkingDirectory = winrt::hstring{ + Utils::EvaluateStartingDirectory(cwdString, std::wstring_view{ requestedStartingDir }) + }; auto conhostConn = TerminalConnection::ConptyConnection(); auto valueSet = TerminalConnection::ConptyConnection::CreateSettings(settings.Commandline(), diff --git a/src/types/utils.cpp b/src/types/utils.cpp index aca9e7c6cb4..31439bc9555 100644 --- a/src/types/utils.cpp +++ b/src/types/utils.cpp @@ -835,32 +835,16 @@ std::wstring Utils::EvaluateStartingDirectory( { std::wstring resultPath{ startingDirectory }; - const bool oldCondition = - startingDirectory.size() == 0 || startingDirectory.size() == 1 && - !(startingDirectory[0] == L'~' || startingDirectory[0] == L'/'); - - oldCondition; - - const bool newCondition = - !(resultPath.size() == 1 && - (resultPath[0] == L'~' || resultPath[0] == L'/')); - newCondition; - // We only want to resolve the new WD against the CWD if it doesn't look // like a Linux path (see GH#592) - // Append only if it DOESN'T look like a linux-y path. - - const bool newest = !( - // the string is at least one char AND - // that first char is `~` or `/` + // Append only if it DOESN'T look like a linux-y path. A linux-y path starts + // with `~` or `/`. + const bool looksLikeLinux = resultPath.size() >= 1 && - (resultPath[0] == L'~' || resultPath[0] == L'/')); + (resultPath[0] == L'~' || resultPath[0] == L'/'); - newest; - // if (oldCondition) - // if (newCondition) - if (newest) + if (!looksLikeLinux) { std::filesystem::path cwd{ currentDirectory }; cwd /= startingDirectory; From 45a8194d3606f37333112970ca9852a516cb62a1 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 12 May 2023 07:14:44 -0500 Subject: [PATCH 09/11] current --- .../TerminalSettingsModel/Resources/en-US/Resources.resw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw index 8da39bf404a..43506576954 100644 --- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -512,7 +512,7 @@ Rename window... - Display Terminal's working directory + Display Terminal's current working directory Show/Hide the Terminal window From 99a9038e9165cc2d3a1eca09b6089943f1cf0d2b Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 19 Jul 2023 11:18:16 -0500 Subject: [PATCH 10/11] well, definitely yank from defaults --- src/cascadia/TerminalSettingsModel/defaults.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cascadia/TerminalSettingsModel/defaults.json b/src/cascadia/TerminalSettingsModel/defaults.json index 3c9ece38487..117abb5c892 100644 --- a/src/cascadia/TerminalSettingsModel/defaults.json +++ b/src/cascadia/TerminalSettingsModel/defaults.json @@ -374,7 +374,6 @@ { "command": "openSystemMenu", "keys": "alt+space" }, { "command": "quit" }, { "command": "restoreLastClosed"}, - { "command": "displayTerminalCwd"}, // Tab Management // "command": "closeTab" is unbound by default. From b4250b82529d5af221ea16ff7352c8302ab747c0 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 19 Jul 2023 11:34:20 -0500 Subject: [PATCH 11/11] as requested --- src/cascadia/TerminalApp/AppActionHandlers.cpp | 7 +++++-- src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 2056d672d87..cad581983f3 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -1024,8 +1024,11 @@ namespace winrt::TerminalApp::implementation void TerminalPage::_HandleDisplayWorkingDirectory(const IInspectable& /*sender*/, const ActionEventArgs& args) { - ShowTerminalWorkingDirectory(); - args.Handled(true); + if (_settings.GlobalSettings().DebugFeaturesEnabled()) + { + ShowTerminalWorkingDirectory(); + args.Handled(true); + } } void TerminalPage::_HandleSearchForText(const IInspectable& /*sender*/, diff --git a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp index d6bd2a89ef5..7c9802c07cb 100644 --- a/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionAndArgs.cpp @@ -72,7 +72,7 @@ static constexpr std::string_view IdentifyWindowKey{ "identifyWindow" }; static constexpr std::string_view IdentifyWindowsKey{ "identifyWindows" }; static constexpr std::string_view RenameWindowKey{ "renameWindow" }; static constexpr std::string_view OpenWindowRenamerKey{ "openWindowRenamer" }; -static constexpr std::string_view DisplayWorkingDirectoryKey{ "displayTerminalCwd" }; +static constexpr std::string_view DisplayWorkingDirectoryKey{ "debugTerminalCwd" }; static constexpr std::string_view SearchForTextKey{ "searchWeb" }; static constexpr std::string_view GlobalSummonKey{ "globalSummon" }; static constexpr std::string_view QuakeModeKey{ "quakeMode" };