如何在 vscode 扩展中实现保存到文件检查覆盖?

How to implement save-to-file-check-overwrite in a vscode extension?

我必须在 Visual Studio 代码扩展中实现一个非常典型的编程模式:将一些东西保存到文件中,但是在这样做之前检查目标文件是否存在并询问用户是否可以覆盖如果是的话。

通常我会打开一个文件保存对话框,要求用户给我一个文件名,这个对话框会做所有必要的检查,并在必要时得到用户确认。但是在 vscode 中我们没有文件保存对话框(但是 a feature request 中有它)。所以我试图用我们现有的有限手段来实现这一点。幸运的是,几周前,一个新的选项参数被添加到消息对话框中,使它们成为模态的。但不知何故,我无法把握正确的时机。这是我的代码:

    window.showInputBox({
        placeHolder: "<Enter full file name here>",
        prompt: "Enter the name to an html file to save the diagram\n" }
    ).then((value: string) => {
        if (value) {
            let canWrite = true;
            if (fs.existsSync(value)) {
                canWrite = false;
                window.showWarningMessage("The specified file exists already", { modal: true }, ...[ "Overwrite" ]).then((action: string) => {
                    if (action === "Overwrite") {
                        canWrite = true;
                    }
                });
            }

            if (canWrite) {
                var stream = fs.createWriteStream(value, { encoding: "utf-8", autoClose: true });
                stream.on("error", function (error: any) {
                    window.showErrorMessage("Could not write to file '" + value + "'. " + error);
                });
                stream.once('open', function (fd) {
                    stream.write(text);
                    stream.end();

                    window.showInformationMessage("Diagram successfully written to file '" + value + "'.");
                });
            }
        }
    })

问题是对 window.showWarningMessage 的调用是非阻塞的,这意味着当对话框(它本身是模态的)在 if (canWrite) 已经执行后打开代码。这不是一个大问题,因为此时 canWritefalse,但是,一旦 showWarningMessage thenable returns 在外部 thenable 中不再执行任何代码(来自 showInputBox),即 if (canWrite) 不会再次执行(如我所料)。嵌套 2 个 thenables 是不可能的还是我做错了什么?

经验丰富的 typescript/vscode 开发人员将如何处理此任务?

showWarningMessage 不能按您的需要使用,不能嵌套。相反,您必须创建自己的 Thenable 方法,这需要进行一些重构。

主要思想是你的储蓄必须return一个Promise,它会控制showWarningMessagereturn (需要时)

function saveDiagram(text, filename): Promise<string | boolean> {
    return new Promise((resolve, reject) => {
        if (fs.existsSync(filename)) {
            vscode.window.showWarningMessage("The specified file exists already", { modal: true }, ...[ "Overwrite" ]).then((action: string) => {
                if (action === "Overwrite") {
                    resolve(filename);
                } else {
                    resolve(false);
                }
            });
        } else {
            resolve(filename);
        }
    });
}

同时将你的 Writing Diagram on Disk 提取为一个新函数,稍后调用:

function writeDiagramOnDisk(text, filename) {
    var stream = fs.createWriteStream(filename, { encoding: "utf-8", autoClose: true });
    stream.on("error", function (error: any) {
        vscode.window.showErrorMessage("Could not write to file '" + filename + "'. " + error);
    });
    stream.once('open', function (fd) {
        stream.write(text);
        stream.end();

        vscode.window.showInformationMessage("Diagram successfully written to file '" + filename + "'.");
    });
}

现在您的扩展代码将采用 thenable 方法,正如您所期望的那样:

vscode.window.showInputBox({
    placeHolder: "<Enter full file name here>",
    prompt: "Enter the name to an html file to save the diagram\n" }
).then((value: string) => {
    if (value) {
        saveDiagram(text, value)
            .then((filename) => {
                if (filename) {
                    writeDiagramOnDisk(text, filename)
                }
            });

    }
})