From d2ed3d5ca106212ee35e28bfae3f3dd163249caa Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Sat, 23 Nov 2024 01:01:44 +0000 Subject: [PATCH] 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, the terminal control does not escape single quotes (allowed in the Win32 subsystem) that need escapes when translated. On the translation styles other than "none" (note: all other translation styles are currently intended for the POSIX shell), it causes incorrect path to be pasted when the path contains one or more single quotes (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) when the path translation is required. --- src/cascadia/TerminalControl/TermControl.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index d7bf9f496a4..bc005ba5c15 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -66,6 +66,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation /* Cygwin */ L"/cygdrive/", /* MSYS2 */ L"/", }; + static constexpr wil::zwstring_view sSingleQuoteEscape = L"'\\''"; + static constexpr auto cchSingleQuoteEscape = sSingleQuoteEscape.size(); if (translationStyle == PathTranslationStyle::None) { @@ -75,6 +77,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation // All of the other path translation modes current result in /-delimited paths std::replace(fullPath.begin(), fullPath.end(), L'\\', L'/'); + // Escape single quotes, assuming translated paths are always quoted by a pair of single quotes. + size_t pos = 0; + while ((pos = fullPath.find(L'\'', pos)) != std::wstring::npos) + { + // ' -> '\'' (for POSIX shell) + fullPath.replace(pos, 1, sSingleQuoteEscape); + // Arithmetic overflow cannot occur here. + pos += cchSingleQuoteEscape; + } + if (fullPath.size() >= 2 && fullPath.at(1) == L':') { // C:/foo/bar -> Cc/foo/bar