I am trying to create a simple VSCode extension to run a set of commands when I open a folder. Basically these commands will set up our development environment. I have started off creating the boilerplace and ran through the example that VSCode provided but I am not clear how to run system commands. Appreciate any help or point me to some documentation about this topic.
You can browse and install extensions from within VS Code. Bring up the Extensions view by clicking on the Extensions icon in the Activity Bar on the side of VS Code or the View: Extensions command (Ctrl+Shift+X). This will show you a list of the most popular VS Code extensions on the VS Code Marketplace.
Go to tools, External tools in visual Studio. Click Add, name the new command then you can point to a batch file command using the browse ellipses. When you save it, you will then see the new menu item under tools.
Your extension environment has access to node.js libraries, so you can just use child_process
or any helper libraries to execute commands:
const cp = require('child_process') cp.exec('pwd', (err, stdout, stderr) => { console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); if (err) { console.log('error: ' + err); } });
One alternative could be to use the Terminal API which is the best option if you have the need for the process to be fully observable and controllable to/by the user.
Biggest downside: The Terminal API does not yet offer a way to introspect the processes that run inside of it.
If you actually want to run the process in the terminal, the only way to do this safely for now, would be to use a two-layer approach, where you start a wrapper process that in turn launches and observes the actual process (taken in via command line args).
We tried this ourselves.
In our first approach, the wrapper used a socket.io
connection that allows for communication with and control by the extension.
In our second approach, we simplified and instead created the terminal using bash -c
(non-interactive shell), and used a file watcher to get the results instead. Easier this way but after the process is done, the user won't be able to use the Terminal window (because its non-interactive). A lot less error-prone and does not require fulfilling socket.io dependency.
TerminalWrapper
which runs the command inside a wrapper process, and waits for a file to contain the results.const cwd = '.'; const command = `node -e "console.log('hi!');"`; const { code } = await TerminalWrapper.execInTerminal(cwd, command, {}).waitForResult(); if (code) { const processExecMsg = `${cwd}$ ${command}`; throw new Error(`Process failed with exit code ${code} (${processExecMsg})`); }
Biggest downside with the second approach is that we now need bash
to be present, however (i) we do have a dependency checker that will warn you if you don't and explain how to get it, and (ii) using a unified shell, makes running commands a lot easier, as we now have a pretty strong unified feature set, we know we can rely on, rather than only being able to use common command execution syntax, and (iii) we can even run *.sh
files without having to worry.
All of the following imagery and excerpts are just straight up copy-and-paste'd from their official sample repository:
context.subscriptions.push(vscode.commands.registerCommand('terminalTest.createAndSend', () => { const terminal = vscode.window.createTerminal(`Ext Terminal #${NEXT_TERM_ID++}`); terminal.sendText("echo 'Sent text immediately after creating'"); }));
vscode.window.onDidChangeActiveTerminal(e => { console.log(`Active terminal changed, name=${e ? e.name : 'undefined'}`); });
function selectTerminal(): Thenable<vscode.Terminal | undefined> { interface TerminalQuickPickItem extends vscode.QuickPickItem { terminal: vscode.Terminal; } const terminals = <vscode.Terminal[]>(<any>vscode.window).terminals; const items: TerminalQuickPickItem[] = terminals.map(t => { return { label: `name: ${t.name}`, terminal: t }; }); return vscode.window.showQuickPick(items).then(item => { return item ? item.terminal : undefined; }); }
...and a lot more!...
(<3 for the VSCode team and their hard work.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With