Repository: vscode
Issue: Expose API for variable substitution in contributed configuration
Labels: feature-request,api

So now we have a bunch of variable substitutions we can use in `.vscode/tasks.json`

```
${workspaceFolder} - the path of the folder opened in VS Code
${workspaceFolderBasename} - the name of the folder opened in VS Code without any slashes (/)
${file} - the current opened file
${relativeFile} - the current opened file relative to workspaceFolder
${fileBasename} - the current opened file's basename
${fileBasenameNoExtension} - the current opened file's basename with no file extension
${fileDirname} - the current opened file's dirname
${fileExtname} - the current opened file's extension
${cwd} - the task runner's current working directory on startup
${lineNumber} - the current selected line number in the active file
${env:Name} - the `Name` variable from the environment
${config:Name} - example: ${config:editor.fontSize}
${command:CommandID} - example: ${command:explorer.newFolder}
```

But what if an extension wants to give the user the ability to use substitution for the configuration points it contributes, the extension developer has to implement that all themselves. While it is totally possible to support all of these substitutions, even inlined commands, from an extension the developer has to reinvent the wheel and maintain compatibility with future/past versions of VSCode.

It would be great if there was a way for an extension to make use of the existing variable substitution logic. Unfortunately, [this is pretty deeply embedded](https://github.com/Microsoft/vscode/blob/b0793e672ddda64d26796873b35c5afafc215090/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts#L600) into vscode and not something made readily accessible to extension developers.

I'm sure that there will be demand for **custom substitution**s and for **limiting what kind of substitutions are allowed**. 

Really rough, but this is how something like this could look.

`./package.json`
```json5
"contributes": {
  "substitutions": {
    "prompt-debug.colorOfSky": {
      "description": "..."
    }
    "prompt-debug.binaryPath": {
      "description": "..."
    }
  },
  "configuration": {
    "properties": {
      "prompt-debug.autoResolveScript": {
        "description": "A javascript or typescript file which is exports a function named 'autoResolve' that resolves a file path to run.",
        "title": "Auto Resolve Script",
        "type": "string",
        "required": false,
		"substitutions": false, // substitutions disabled (default)
        "substitutions": "*", // allow all registered substitutions
		"substitutions": [
		  "*", // allow all registered substitutions
		  "-command:*" // exclude commands from substitutions
		  "command:explorer.newFolder" // with the exception of the newFolder command
		],
        "substitutions": [
    	  "substitution:prompt-debug.*" // allow all of the substitutions prompt-debug contributes
		  "-substitution:prompt-debug.binaryPath" // with the exception of binaryPath 
		]
	}
}
```

`./src/extension.ts`
```typescript
export function activate(context: vscode.ExtensionContext) {
  vscode.substitutions.registerSubstitution('prompt-debug.colorOfSky', () => (Math.random() > 0.5) ? 'blue' : 'grey');
  vscode.substitutions.registerSubstitution('prompt-debug.binaryPath', async () => {
    const binaryPath = await someAsycStuff();
	if (binaryPath) return binaryPath;
    else return '/usr/bin/derp';
  });
}
```

Obviously `vscode.workspace.getConfiguration().get('prompt-debug.autoResolveScript');` would have to be async because substitutions with commands can take a while to evaluate.. I have a few good ideas, but I'm tired of typing so we can bikeshed later if anyone is actually interested in this.. lol