diff --git a/package-lock.json b/package-lock.json index 514363a8a74..11311ca686d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -199,7 +199,7 @@ "util": "^0.12.4" }, "engines": { - "vscode": "^1.104.0" + "vscode": "^1.102.0" }, "optionalDependencies": { "fsevents": "^2.3.2" diff --git a/package.json b/package.json index a5981e1ce85..4c3f487ed30 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "theme": "light" }, "engines": { - "vscode": "^1.104.0" + "vscode": "^1.102.0" }, "l10n": "./l10n", "extensionKind": [ diff --git a/src/platform/common/extensions.unit.test.ts b/src/platform/common/extensions.unit.test.ts index 5481b4dd368..efd6eee0949 100644 --- a/src/platform/common/extensions.unit.test.ts +++ b/src/platform/common/extensions.unit.test.ts @@ -87,4 +87,45 @@ suite('String Extensions', () => { expect(trimQuotes(quotedString3)).to.be.equal(expectedString); expect(trimQuotes(quotedString4)).to.be.equal(expectedString); }); + + // Tests for Windows paths with special characters (issue #16932) + test('Should quote Windows paths with spaces in username', () => { + const pathToTest = 'C:\\Users\\John Smith\\AppData\\Local\\env\\python.exe'; + expect(toCommandArgument(pathToTest)).to.be.equal(`"${pathToTest}"`); + }); + test('Should quote Windows paths with parentheses in username', () => { + const pathToTest = 'C:\\Users\\John(Contractor)\\AppData\\Local\\env\\python.exe'; + expect(toCommandArgument(pathToTest)).to.be.equal(`"${pathToTest}"`); + }); + test('Should quote Windows paths with both spaces and parentheses', () => { + const pathToTest = 'C:\\Users\\John Smith (Contractor)\\AppData\\Local\\env\\python.exe'; + expect(toCommandArgument(pathToTest)).to.be.equal(`"${pathToTest}"`); + }); + test('Should quote file paths with special characters and normalize slashes', () => { + const pathToTest = 'C:\\Users\\John(Contractor)\\AppData\\Local\\env\\python.exe'; + const expectedPath = 'C:/Users/John(Contractor)/AppData/Local/env/python.exe'; + expect(fileToCommandArgument(pathToTest)).to.be.equal(`"${expectedPath}"`); + }); + test('Should handle already quoted paths correctly', () => { + const pathToTest = '"C:\\Users\\John(Contractor)\\AppData\\Local\\env\\python.exe"'; + // toCommandArgument should not double-quote if already quoted + expect(toCommandArgument(pathToTest)).to.be.equal(pathToTest); + }); + test('Should quote paths with other shell metacharacters', () => { + const pathWithAmpersand = 'C:\\Users\\John&Jane\\python.exe'; + const pathWithPipe = 'C:\\Users\\John|Jane\\python.exe'; + const pathWithLessThan = 'C:\\Users\\John { + const normalPath = 'C:\\Users\\JohnSmith\\AppData\\Local\\env\\python.exe'; + expect(toCommandArgument(normalPath)).to.be.equal(normalPath); + }); }); diff --git a/src/platform/common/helpers.ts b/src/platform/common/helpers.ts index 8e9ab27ded3..ea99f3e6392 100644 --- a/src/platform/common/helpers.ts +++ b/src/platform/common/helpers.ts @@ -23,19 +23,22 @@ export function splitLines( /** * Appropriately formats a string so it can be used as an argument for a command in a shell. - * E.g. if an argument contains a space, then it will be enclosed within double quotes. + * E.g. if an argument contains a space or special characters, then it will be enclosed within double quotes. * @param {String} value. */ export function toCommandArgument(value: string): string { if (!value) { return value; } - return value.indexOf(' ') >= 0 && !value.startsWith('"') && !value.endsWith('"') ? `"${value}"` : value.toString(); + // Check for special characters that require quoting in shell commands + // This includes spaces, parentheses, and other shell metacharacters + const needsQuoting = /[\s()&|<>^]/.test(value); + return needsQuoting && !value.startsWith('"') && !value.endsWith('"') ? `"${value}"` : value.toString(); } /** * Appropriately formats a a file path so it can be used as an argument for a command in a shell. - * E.g. if an argument contains a space, then it will be enclosed within double quotes. + * E.g. if an argument contains a space or special characters, then it will be enclosed within double quotes. */ export function fileToCommandArgument(value: string): string { if (!value) {