diff --git a/src/vs/platform/terminal/common/terminalEnvironment.ts b/src/vs/platform/terminal/common/terminalEnvironment.ts index 1d24a24f60d..7f7ab14a2db 100644 --- a/src/vs/platform/terminal/common/terminalEnvironment.ts +++ b/src/vs/platform/terminal/common/terminalEnvironment.ts @@ -3,6 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { OperatingSystem, OS } from 'vs/base/common/platform'; + export function escapeNonWindowsPath(path: string): string { let newPath = path; if (newPath.indexOf('\\') !== 0) { @@ -35,3 +37,20 @@ export function collapseTildePath(path: string | undefined, userHome: string | u } return `~${separator}${path.slice(userHome.length + 1)}`; } + +/** + * Sanitizes a cwd string, removing any wrapping quotes and making the Windows drive letter + * uppercase. + * @param cwd The directory to sanitize. + */ +export function sanitizeCwd(cwd: string): string { + // Sanity check that the cwd is not wrapped in quotes (see #160109) + if (cwd.match(/^['"].*['"]$/)) { + cwd = cwd.substring(1, cwd.length - 1); + } + // Make the drive letter uppercase on Windows (see #9448) + if (OS === OperatingSystem.Windows && cwd && cwd[1] === ':') { + return cwd[0].toUpperCase() + cwd.substring(1); + } + return cwd; +} diff --git a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts index 47ebe176985..b1a1e4498f9 100644 --- a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts +++ b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts @@ -20,6 +20,7 @@ import { BufferMarkCapability } from 'vs/platform/terminal/common/capabilities/b // eslint-disable-next-line local/code-import-patterns import type { ITerminalAddon, Terminal } from 'xterm-headless'; import { URI } from 'vs/base/common/uri'; +import { sanitizeCwd } from 'vs/platform/terminal/common/terminalEnvironment'; /** @@ -383,6 +384,7 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati } private _updateCwd(value: string) { + value = sanitizeCwd(value); this._createOrGetCwdDetection().updateCwd(value); const commandDetection = this.capabilities.get(TerminalCapability.CommandDetection); commandDetection?.setCwd(value); diff --git a/src/vs/platform/terminal/test/common/terminalEnvironment.test.ts b/src/vs/platform/terminal/test/common/terminalEnvironment.test.ts index 2c58f9ec1fd..5f8aaca7e15 100644 --- a/src/vs/platform/terminal/test/common/terminalEnvironment.test.ts +++ b/src/vs/platform/terminal/test/common/terminalEnvironment.test.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { strictEqual } from 'assert'; -import { collapseTildePath } from 'vs/platform/terminal/common/terminalEnvironment'; +import { OperatingSystem, OS } from 'vs/base/common/platform'; +import { collapseTildePath, sanitizeCwd } from 'vs/platform/terminal/common/terminalEnvironment'; suite('terminalEnvironment', () => { suite('collapseTildePath', () => { @@ -37,4 +38,15 @@ suite('terminalEnvironment', () => { strictEqual(collapseTildePath('/foo/bar/baz', '/foo/', '/'), '~/bar/baz'); }); }); + suite('sanitizeCwd', () => { + if (OS === OperatingSystem.Windows) { + test('should make the Windows drive letter uppercase', () => { + strictEqual(sanitizeCwd('c:\\foo\\bar'), 'C:\\foo\\bar'); + }); + } + test('should remove any wrapping quotes', () => { + strictEqual(sanitizeCwd('\'/foo/bar\''), '/foo/bar'); + strictEqual(sanitizeCwd('"/foo/bar"'), '/foo/bar'); + }); + }); }); diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index 5a17c3c3f69..290023e91b6 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -14,7 +14,8 @@ import { IConfigurationResolverService } from 'vs/workbench/services/configurati import { sanitizeProcessEnvironment } from 'vs/base/common/processes'; import { ILogService } from 'vs/platform/log/common/log'; import { IShellLaunchConfig, ITerminalEnvironment, TerminalSettingId, TerminalSettingPrefix } from 'vs/platform/terminal/common/terminal'; -import { IProcessEnvironment, isWindows, locale, OperatingSystem, OS, platform, Platform } from 'vs/base/common/platform'; +import { IProcessEnvironment, isWindows, locale, platform, Platform } from 'vs/base/common/platform'; +import { sanitizeCwd } from 'vs/platform/terminal/common/terminalEnvironment'; export function mergeEnvironments(parent: IProcessEnvironment, other: ITerminalEnvironment | undefined): void { if (!other) { @@ -190,7 +191,7 @@ export async function getCwd( if (shell.cwd) { const unresolved = (typeof shell.cwd === 'object') ? shell.cwd.fsPath : shell.cwd; const resolved = await _resolveCwd(unresolved, variableResolver); - return _sanitizeCwd(resolved || unresolved); + return sanitizeCwd(resolved || unresolved); } let cwd: string | undefined; @@ -213,7 +214,7 @@ export async function getCwd( cwd = root ? root.fsPath : userHome || ''; } - return _sanitizeCwd(cwd); + return sanitizeCwd(cwd); } async function _resolveCwd(cwd: string, variableResolver: VariableResolver | undefined, logService?: ILogService): Promise { @@ -228,18 +229,6 @@ async function _resolveCwd(cwd: string, variableResolver: VariableResolver | und return cwd; } -function _sanitizeCwd(cwd: string): string { - // Sanity check that the cwd is not wrapped in quotes (see #160109) - if (cwd.match(/$['"].*['"]^/)) { - cwd = cwd.substring(1, cwd.length - 1); - } - // Make the drive letter uppercase on Windows (see #9448) - if (OS === OperatingSystem.Windows && cwd && cwd[1] === ':') { - return cwd[0].toUpperCase() + cwd.substr(1); - } - return cwd; -} - export type TerminalShellSetting = ( TerminalSettingId.AutomationShellWindows | TerminalSettingId.AutomationShellMacOs