如何从VSCode扩展运行系统命令

rna*_*sap 15 visual-studio-code vscode-extensions

我正在尝试创建一个简单的VSCode扩展,以便在打开文件夹时运行一组命令.基本上这些命令将建立我们的开发环境.我已经开始创建锅炉并运行VSCode提供的示例,但我不清楚如何运行系统命令.感谢任何帮助或指出我有关此主题的一些文档.

Mat*_*ner 16

您的扩展环境可以访问node.js库,因此您可以使用child_process或任何帮助程序库来执行命令:

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);
    }
});
Run Code Online (Sandbox Code Playgroud)

  • 这是我们应该做这样的事情的方式吗?那没有VSCode优雅的API?就像用户突然关闭VSCode一样?这意味着我的扩展外部进程可能永远运行? (9认同)
  • 不,它是一个 child_process,在这种情况下,当 VSCode 进程终止时,任何子进程也会终止。 (2认同)
  • @MatBee 可悲的是,这不是子进程的工作方式。请参阅:/sf/ask/597336421/ (2认同)

Dom*_*omi 13

一种替代方法是使用终端 API,如果您需要让用户/由用户完全观察和控制流程,这是最佳选择。

最大的缺点:终端 API还没有提供一种方法来检查在其中运行的进程。

如果您确实想在终端中运行该进程,那么目前安全地执行此操作的唯一方法是使用两层方法,在该方法中您启动一个包装进程,该进程依次启动并观察实际进程(取自通过命令行参数)。

我们自制的TerminalWrapper

我们自己试过这个。

  • 在我们的第一种方法中,包装器使用了socket.io允许与扩展通信并由扩展控制的连接。

  • 在我们的第二种方法中,我们简化并改为使用bash -c(非交互式 shell)创建终端,并使用文件观察器来获取结果。这种方式更容易,但在该过程完成后,用户将无法使用终端窗口(因为它是非交互式的)。更不容易出错,并且不需要满足 socket.io 依赖项。

实施细则

  1. 在我们的扩展中,我们使用 aTerminalWrapper在包装进程内运行命令,并等待包含结果的文件。
  2. 包装过程在这里。它将结果写入文件。
  3. 这里的用法示例:
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})`);
}
Run Code Online (Sandbox Code Playgroud)

第二种方法的最大缺点是我们现在需要bash在场,但是 (i) 我们确实有一个依赖项检查器,如果您不这样做,它会警告您并解释如何获取它,以及 (ii) 使用统一的 shell,使运行命令变得更加容易,因为我们现在拥有非常强大的统一功能集,我们知道我们可以依赖,而不仅仅是能够使用常见的命令执行语法,并且 (iii) 我们甚至可以运行*.sh文件而不必担心.

介绍:VSCode 终端 API

以下所有图像和摘录都直接从其官方示例存储库中复制和粘贴:

创建终端并在其中运行命令

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'");
}));
Run Code Online (Sandbox Code Playgroud)

终端激活事件

vscode.window.onDidChangeActiveTerminal(e => {
    console.log(`Active terminal changed, name=${e ? e.name : 'undefined'}`);
});
Run Code Online (Sandbox Code Playgroud)

终端快速选择项目

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;
    });
}
Run Code Online (Sandbox Code Playgroud)

……还有更多!……

终端 API 示例命令

(<3 代表 VSCode 团队和他们的辛勤工作。)


Yon*_*ang 6

我所做的是创建一个基于 Promise 的实用程序函数,以使用 child_process 运行所有 shell 命令

import * as cp from "child_process";

const execShell = (cmd: string) =>
    new Promise<string>((resolve, reject) => {
        cp.exec(cmd, (err, out) => {
            if (err) {
                return reject(err);
            }
            return resolve(out);
        });
    });
Run Code Online (Sandbox Code Playgroud)

获取当前目录

const currentDir = await execShell('pwd');
Run Code Online (Sandbox Code Playgroud)

获取当前的 git 分支名称

const branchName = await execShell('git rev-parse --abbrev-ref HEAD');
Run Code Online (Sandbox Code Playgroud)