diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index cfbdd696652..9165ba861d4 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -1,3 +1,4 @@ +import path = require('path'); import * as vscode from 'vscode'; import { Env } from './client'; import { log } from "./util"; @@ -253,7 +254,10 @@ export function substituteVariablesInEnv(env: Env): Env { resolved.add(dep); } } else { - // TODO: handle VSCode variables + envWithDeps[dep] = { + value: computeVscodeVar(dep), + deps: [] + }; } } const toResolve = new Set(Object.keys(envWithDeps)); @@ -279,3 +283,52 @@ export function substituteVariablesInEnv(env: Env): Env { } return resolvedEnv; } + +function computeVscodeVar(varName: string): string { + // https://code.visualstudio.com/docs/editor/variables-reference + const supportedVariables: { [k: string]: () => string } = { + workspaceFolder: () => { + const folders = vscode.workspace.workspaceFolders ?? []; + if (folders.length === 1) { + // TODO: support for remote workspaces? + return folders[0].uri.fsPath; + } else if (folders.length > 1) { + // could use currently opened document to detect the correct + // workspace. However, that would be determined by the document + // user has opened on Editor startup. Could lead to + // unpredictable workspace selection in practice. + // It's better to pick the first one + return folders[0].uri.fsPath; + } else { + // no workspace opened + return ''; + } + }, + + workspaceFolderBasename: () => { + const workspaceFolder = computeVscodeVar('workspaceFolder'); + if (workspaceFolder) { + return path.basename(workspaceFolder); + } else { + return ''; + } + }, + + cwd: () => process.cwd(), + + // see + // https://github.com/microsoft/vscode/blob/08ac1bb67ca2459496b272d8f4a908757f24f56f/src/vs/workbench/api/common/extHostVariableResolverService.ts#L81 + // or + // https://github.com/microsoft/vscode/blob/29eb316bb9f154b7870eb5204ec7f2e7cf649bec/src/vs/server/node/remoteTerminalChannel.ts#L56 + execPath: () => process.env.VSCODE_EXEC_PATH ?? process.execPath, + + pathSeparator: () => path.sep + }; + + if (varName in supportedVariables) { + return supportedVariables[varName](); + } else { + // can't resolve, keep the expression as is + return '${' + varName + '}'; + } +} diff --git a/editors/code/tests/runTests.ts b/editors/code/tests/runTests.ts index 7a8f3ef698b..6172cc7d5f9 100644 --- a/editors/code/tests/runTests.ts +++ b/editors/code/tests/runTests.ts @@ -14,7 +14,7 @@ async function main() { let minimalVersion: string = json.engines.vscode; if (minimalVersion.startsWith('^')) minimalVersion = minimalVersion.slice(1); - const launchArgs = ["--disable-extensions"]; + const launchArgs = ["--disable-extensions", extensionDevelopmentPath]; // All test suites (either unit tests or integration tests) should be in subfolders. const extensionTestsPath = path.resolve(__dirname, './unit/index'); diff --git a/editors/code/tests/unit/settings.test.ts b/editors/code/tests/unit/settings.test.ts index f4b022b421c..dca4e38d138 100644 --- a/editors/code/tests/unit/settings.test.ts +++ b/editors/code/tests/unit/settings.test.ts @@ -49,5 +49,13 @@ export async function getTests(ctx: Context) { const actualEnv = await substituteVariablesInEnv(envJson); assert.deepStrictEqual(actualEnv, expectedEnv); }); + + suite.addTest('should support VSCode variables', async () => { + const envJson = { + USING_VSCODE_VAR: "${workspaceFolderBasename}" + }; + const actualEnv = await substituteVariablesInEnv(envJson); + assert.deepStrictEqual(actualEnv.USING_VSCODE_VAR, 'code'); + }); }); }