I have a VSCode extension that starts a Python debugging session when a program I run hits a breakpoint. However the Python program currently communicates with the extension by writing to a file that's watched by the extension.
Hacky but it works, except if I have two instances of VSCode open they race to start debugging.
Is there any way for a program run from VSCode's embedded terminal to figure out which VSCode instance it is running in, so that the extension can figure out if it's connected to the same instance?
CodePudding user response:
You can do this! The official Git extension has to do something similar for askpass support. Basically in your extension's activate()
function you do this:
export function activate(context: ExtensionContext) {
const ipcPath = getIpcPath(context);
context.environmentVariableCollection.replace("MY_EXTENSION_IPC_PATH", ipcPath);
That will set an environment variable in all integrated shells that your programs can then read. I suspect there may be issues if your extension is activated on demand (I guess it's only going to apply to new terminals after your extension is activated) so you may need to play around with your extension's activationEvents
in package.json
.
To communicate with the extension you can use IPC, but you need a unique IPC path. Unfortunately it doesn't seem like the ExtensionContext
has any kind of unique identifiers in it, so I kind of hacked it like this:
let extensionInstance = 0;
function getIpcPath(context: ExtensionContext): string {
const hash = crypto.createHash("sha1");
hash.update(`${context.storageUri}${ extensionInstance}${process.pid}`);
const id = hash.digest("hex").slice(0, 10);
if (process.platform === "win32") {
return `\\\\.\\pipe\\my_extension_ipc_${id}`;
}
if (process.env["XDG_RUNTIME_DIR"] !== undefined) {
return path.join(process.env["XDG_RUNTIME_DIR"], `my_extension_ipc_${id}.sock`);
}
return path.join(os.tmpdir(), `my_extension_ipc_${id}.sock`);
}
This is pretty similar to what the Git extension does. Not quite the same but it seems to work.
Finally I pass the IPC path as a command line argument to my extension's language server so it can start listening at that address.
let serverOptions: ServerOptions = {
run: {
command: serverCommand,
args: ["--ipc-path", ipcPath],
},
debug: {
command: serverCommand,
args: ["--ipc-path", ipcPath, "--debug"],
},
};
Seems to work ok!