如何在vscode扩展中实现save-to-file-check-overwrite?

时间:2017-04-18 12:51:19

标签: typescript visual-studio-code vscode-extensions

我必须在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)已经执行之后打开代码。这不是一个大问题,因为canWrite此时falseshowWarningMessage,但是,一旦showInputBox然后返回,则外部可执行的任何代码不再执行(来自if (canWrite)) ,即"code" so I can post this 不再执行(正如我所料)。是否无法嵌套2个人或者我还有什么其他错误?

有经验的打字稿/ vscode develper如何处理这项任务?

1 个答案:

答案 0 :(得分:1)

showWarningMessage根据需要不可用,你无法嵌套它。相反,您必须创建自己的Thenable方法,这需要一些重构。

主要想法是保存必须返回Promise,并且会控制showWarningMessage返回(需要时)

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);
        }
    });
}

还将在磁盘上编写图表作为新函数提取,称为后者:

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 + "'.");
    });
}

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

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)
                }
            });

    }
})