Skip to content

Commit dcc31cb

Browse files
committed
Escape single quotes while translating dropped Win32 paths
When file/folder is dropped to the terminal, its path is translated and quoted with a pair of single quotes if necessary. However, despite that the Win32 subsystem allows single quote, the terminal control does not escape it. It causes a path containing one or more single quotes incorrect on the POSIX shell context (see Issue #18006 for an example). With this commit, the terminal control escapes a single quote with a valid escape sequence `'\''` (finish quote, print a single quote then begin quote again).
1 parent 282670a commit dcc31cb

File tree

1 file changed

+12
-0
lines changed

1 file changed

+12
-0
lines changed

src/cascadia/TerminalControl/TermControl.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
6666
/* Cygwin */ L"/cygdrive/",
6767
/* MSYS2 */ L"/",
6868
};
69+
static constexpr wil::zwstring_view sSingleQuoteEscape = L"'\\''";
70+
static constexpr auto cchSingleQuoteEscape = sSingleQuoteEscape.size();
6971

7072
if (translationStyle == PathTranslationStyle::None)
7173
{
@@ -75,6 +77,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
7577
// All of the other path translation modes current result in /-delimited paths
7678
std::replace(fullPath.begin(), fullPath.end(), L'\\', L'/');
7779

80+
// Escape single quotes, assuming translated paths are always quoted by single quotes.
81+
size_t pos = 0;
82+
while ((pos = fullPath.find(L'\'', pos)) != std::wstring::npos)
83+
{
84+
// ' -> '\''
85+
fullPath.replace(pos, 1, sSingleQuoteEscape);
86+
// Arithmetic overflow is not a problem since an exception would have occured above on such cases.
87+
pos += cchSingleQuoteEscape;
88+
}
89+
7890
if (fullPath.size() >= 2 && fullPath.at(1) == L':')
7991
{
8092
// C:/foo/bar -> Cc/foo/bar

0 commit comments

Comments
 (0)