Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/cascadia/TerminalApp/AppActionHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1475,7 +1475,7 @@ namespace winrt::TerminalApp::implementation
WI_IsAnyFlagSet(source, SuggestionsSource::CommandHistory | SuggestionsSource::QuickFixes);
if (const auto& control{ _GetActiveControl() })
{
currentWorkingDirectory = control.CurrentWorkingDirectory();
currentWorkingDirectory = control.WorkingDirectory();

if (shouldGetContext)
{
Expand Down
6 changes: 2 additions & 4 deletions src/cascadia/TerminalApp/TerminalPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1600,8 +1600,7 @@ namespace winrt::TerminalApp::implementation

// Replace the Starting directory with the CWD, if given
const auto workingDirectory = control.WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
if (Utils::IsValidDirectory(workingDirectory.c_str()))
{
controlSettings.DefaultSettings()->StartingDirectory(workingDirectory);
}
Expand Down Expand Up @@ -3555,8 +3554,7 @@ namespace winrt::TerminalApp::implementation
profile = GetClosestProfileForDuplicationOfProfile(profile);
controlSettings = Settings::TerminalSettings::CreateWithProfile(_settings, profile);
const auto workingDirectory = tabImpl->GetActiveTerminalControl().WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
if (Utils::IsValidDirectory(workingDirectory.c_str()))
{
controlSettings.DefaultSettings()->StartingDirectory(workingDirectory);
}
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalApp/TerminalPaneContent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ namespace winrt::TerminalApp::implementation

args.Profile(::Microsoft::Console::Utils::GuidToString(_profile.Guid()));
// If we know the user's working directory use it instead of the profile.
if (const auto dir = _control.WorkingDirectory(); !dir.empty())
if (const auto dir = _control.WorkingDirectory(); ::Microsoft::Console::Utils::IsValidDirectory(dir.c_str()))
{
args.StartingDirectory(dir);
}
Expand Down
5 changes: 0 additions & 5 deletions src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2420,11 +2420,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return *context;
}

winrt::hstring ControlCore::CurrentWorkingDirectory() const
{
return winrt::hstring{ _terminal->GetWorkingDirectory() };
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i s2g, we just had a whole-ass duplicate of this function?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah lol. I was super surprised about that too. We don't have skeletons in our basement, we got entire graveyards apparently lmao.

}

bool ControlCore::QuickFixesAvailable() const noexcept
{
return _cachedQuickFixes && _cachedQuickFixes.Size() > 0;
Expand Down
2 changes: 0 additions & 2 deletions src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation

void ContextMenuSelectCommand();
void ContextMenuSelectOutput();

winrt::hstring CurrentWorkingDirectory() const;
#pragma endregion

#pragma region ITerminalInput
Expand Down
2 changes: 0 additions & 2 deletions src/cascadia/TerminalControl/ICoreState.idl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,5 @@ namespace Microsoft.Terminal.Control
void SelectOutput(Boolean goUp);
IVector<ScrollMark> ScrollMarks { get; };

String CurrentWorkingDirectory { get; };

};
}
4 changes: 0 additions & 4 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3713,10 +3713,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
return _core.CommandHistory();
}
winrt::hstring TermControl::CurrentWorkingDirectory() const
{
return _core.CurrentWorkingDirectory();
}

void TermControl::UpdateWinGetSuggestions(Windows::Foundation::Collections::IVector<hstring> suggestions)
{
Expand Down
2 changes: 0 additions & 2 deletions src/cascadia/TerminalControl/TermControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ScrollToMark(const Control::ScrollToMarkDirection& direction);
void SelectCommand(const bool goUp);
void SelectOutput(const bool goUp);

winrt::hstring CurrentWorkingDirectory() const;
#pragma endregion

void ScrollViewport(int viewTop);
Expand Down
2 changes: 1 addition & 1 deletion src/common.build.pre.props
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@

<!-- For ALL build types-->
<PropertyGroup Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<LinkIncremental>false</LinkIncremental>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
Expand Down
5 changes: 1 addition & 4 deletions src/terminal/adapter/ITermDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch
virtual void BackIndex() = 0; // DECBI
virtual void ForwardIndex() = 0; // DECFI
virtual void SetWindowTitle(std::wstring_view title) = 0; // DECSWT, OscWindowTitle
virtual void SetCurrentWorkingDirectory(const std::wstring_view uri) = 0; // OSC 7
virtual void HorizontalTabSet() = 0; // HTS
virtual void ForwardTab(const VTInt numTabs) = 0; // CHT, HT
virtual void BackwardsTab(const VTInt numTabs) = 0; // CBT
Expand Down Expand Up @@ -156,13 +157,9 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch
virtual void EndHyperlink() = 0;

virtual void DoConEmuAction(const std::wstring_view string) = 0;

virtual void DoITerm2Action(const std::wstring_view string) = 0;

virtual void DoFinalTermAction(const std::wstring_view string) = 0;

virtual void DoVsCodeAction(const std::wstring_view string) = 0;

virtual void DoWTAction(const std::wstring_view string) = 0;

virtual StringHandler DefineSixelImage(const VTInt macroParameter,
Expand Down
21 changes: 21 additions & 0 deletions src/terminal/adapter/adaptDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2615,6 +2615,27 @@ void AdaptDispatch::SetWindowTitle(std::wstring_view title)
_api.SetWindowTitle(title);
}

// OSC 7 - Set Current Working Directory
// While ConEmu's OSC 9;9 works well for native Windows paths,
// OSC 7 uses file URIs, which may not always work.
void AdaptDispatch::SetCurrentWorkingDirectory(std::wstring_view uri)
{
// Ensure that the URI has a null terminator.
std::wstring path{uri};

// PathCreateFromUrlW supports writing to the input pointer,
// and the resulting path can never be longer than the URI.
const auto ptr = path.data();
auto len = gsl::narrow<DWORD>(path.size());
THROW_IF_FAILED(PathCreateFromUrlW(ptr, ptr, &len, 0));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will add a dependency from conhost on the library containing PathCreateFromUrlW; is that acceptable?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.... it's in kernelbase?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    api-ms-win-core-url-l1-1-0
      PathCreateFromUrlW

hmm where are you hosted little guy

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

> $d.Apis["PathCreateFromUrlW"][1].Binary


Architecture                       : Amd64
BinplacePath                       : kernelbase.dll

wellp

path.resize(len);

if (til::is_legal_path(path))
{
_api.SetWorkingDirectory(path);
}
}

//Routine Description:
// HTS - sets a VT tab stop in the cursor's current column.
//Arguments:
Expand Down
1 change: 1 addition & 0 deletions src/terminal/adapter/adaptDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ namespace Microsoft::Console::VirtualTerminal
void BackIndex() override; // DECBI
void ForwardIndex() override; // DECFI
void SetWindowTitle(const std::wstring_view title) override; // DECSWT, OSCWindowTitle
void SetCurrentWorkingDirectory(std::wstring_view uri) override; // OSC 7
void HorizontalTabSet() override; // HTS
void ForwardTab(const VTInt numTabs) override; // CHT, HT
void BackwardsTab(const VTInt numTabs) override; // CBT
Expand Down
3 changes: 2 additions & 1 deletion src/terminal/adapter/precomp.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ Module Name:
// This includes support libraries from the CRT, STL, WIL, and GSL
#include "LibraryIncludes.h"

#include <cmath>
#include <Shlwapi.h>

#define ENABLE_INTSAFE_SIGNED_FUNCTIONS
#include <intsafe.h>

Expand Down
1 change: 1 addition & 0 deletions src/terminal/adapter/termDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons
void BackIndex() override {} // DECBI
void ForwardIndex() override {} // DECFI
void SetWindowTitle(std::wstring_view /*title*/) override {} // DECSWT, OscWindowTitle
void SetCurrentWorkingDirectory(std::wstring_view /*uri*/) override {} // OSC 7
void HorizontalTabSet() override {} // HTS
void ForwardTab(const VTInt /*numTabs*/) override {} // CHT, HT
void BackwardsTab(const VTInt /*numTabs*/) override {} // CBT
Expand Down
3 changes: 1 addition & 2 deletions src/terminal/parser/OutputStateMachineEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -865,8 +865,7 @@ bool OutputStateMachineEngine::ActionOscDispatch(const size_t parameter, const s
break;
}
case OscActionCodes::CurrentWorkingDirectory:
// TODO: Add support for OSC 7 = CWD sequences?
// In GH#8214 it was decided that it's a bad idea due to WSL compat.
_dispatch->SetCurrentWorkingDirectory(string);
break;
case OscActionCodes::Hyperlink:
{
Expand Down
2 changes: 2 additions & 0 deletions src/types/inc/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ namespace Microsoft::Console::Utils

const wchar_t* FindActionableControlCharacter(const wchar_t* beg, const size_t len) noexcept;

bool IsValidDirectory(const wchar_t* path) noexcept;

// Same deal, but in TerminalPage::_evaluatePathForCwd
std::wstring EvaluateStartingDirectory(std::wstring_view cwd, std::wstring_view startingDirectory);

Expand Down
13 changes: 13 additions & 0 deletions src/types/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,19 @@ const wchar_t* Utils::FindActionableControlCharacter(const wchar_t* beg, const s
return it;
}

// Returns `path` if it's a valid directory. Otherwise, returns an empty string.
bool Utils::IsValidDirectory(const wchar_t* path) noexcept
{
if (path == nullptr || *path == L'\0')
{
return false;
}

WIN32_FILE_ATTRIBUTE_DATA data;
const auto ok = GetFileAttributesExW(path, GetFileExInfoStandard, &data);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of std::filesystem::access or whatever? cool w/ me

Copy link
Copy Markdown
Member Author

@lhecker lhecker Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I just hate that the std::filesystem::path objects are expensive to construct. Under the hood, it gets passed to __std_fs_get_stats, which - and you will never guess this - takes a null-terminated string. 🤦‍♂️

Hurr durr "C++ is for low level zero overhead real man's man engineering."
Meanwhile: Wrap in wstring to unwrap in pointer. lmao

return ok && (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
}

#pragma warning(pop)

std::wstring Utils::EvaluateStartingDirectory(
Expand Down
Loading