VSCode: 在内存中创建一个带有URI 的文档用于自动化测试?

VSCode: Create a document in memory with URI for automated testing?

背景

我创建了一个与文档交互的扩展。为了测试扩展我需要创建文档,扩展可以使用。扩展 必须通过 uri.

访问文档

目前我正在使用 vscode.workspace.openTextDocument({content: _content, language: _language}); 创建文档。问题是,它没有有效的 URI。

问题

如何在内存中创建具有有效 URI 的虚拟文档?

由于没有本地解决方案,我创建了我的解决方案并想在这里分享:

A TextDocumentContentProvider 用于内存中的文件。示例用法如下所示

memoryfile.ts

import * as vscode from 'vscode';

const _SCHEME = "inmemoryfile";

/**
 *  Registration function for In-Memory files.
 *  You need to call this once, if you want to make use of
 *  `MemoryFile`s.
 **/
export function register_memoryFileProvider ({ subscriptions }: vscode.ExtensionContext)
{
  const myProvider = new (class implements vscode.TextDocumentContentProvider
        {
            provideTextDocumentContent(uri: vscode.Uri): string
            {
                let memDoc = MemoryFile.getDocument (uri);
                if (memDoc == null)
                    return "";
                return memDoc.read ();
            }
  })();
  subscriptions.push(vscode.workspace.registerTextDocumentContentProvider(
        _SCHEME, myProvider));
}




/**
 *  Management class for in-memory files.
 **/
class MemoryFileManagement
{
    private static _documents: {[key: string]: MemoryFile} = {};
    private static _lastDocId: number = 0;



    public static getDocument(uri: vscode.Uri) : MemoryFile | null
    {
        return MemoryFileManagement._documents[uri.path];
    }



    private static _getNextDocId(): string{
        MemoryFileManagement._lastDocId++;
        return "_" + MemoryFileManagement._lastDocId + "_";
    }



    public static createDocument(extension = "")
    {
      let path = MemoryFileManagement._getNextDocId ();

        if (extension != "")
            path += "." + extension;

        let self = new MemoryFile(path);

        MemoryFileManagement._documents[path] = self;

        return self;
    }
}



/**
 * A file in memory
 **/
export class MemoryFile
{
    /******************
     ** Static Area  **
     ******************/

    public static getDocument(uri: vscode.Uri) : MemoryFile | null {
        return MemoryFileManagement.getDocument (uri);
    }

    public static createDocument(extension = "") {
        return MemoryFileManagement.createDocument (extension);
    }



    /******************
     ** Object Area  **
     ******************/

    public content: string = "";
    public uri: vscode.Uri;

    constructor (path: string)
    {
        this.uri = vscode.Uri.from ({scheme: _SCHEME, path: path})
    }


    public write(strContent: string){
        this.content += strContent;
    }


    public read(): string {
        return this.content;
    }


    public getUri(): vscode.Uri {
        return this.uri;
    }
}

用法示例

注册提供商

您需要在测试代码开头的某处注册提供者(我在 index.ts 实例化 Mocha 之前注册):

register_memoryFileProvider (extensionContext);

(How do I get the extension context?)

创建文档

创建和使用文件的过程如下:

// create the in-memory document
let memfile = MemoryFile.createDocument ("ts");
memfile.write ("my content");

// create a vscode.TextDocument from the in-memory document.
let doc = await vscode.workspace.openTextDocument (memfile.getUri ());

备注

  • 请注意,LSP 命令可能不适用于方法,因为它们可能已注册到某个特定的 schema.

正如 rioV8 所说,您还可以使用现有文档并更改其内容。这里的代码:

export class TmpFile
{
  private static _lastDocId: number = 0;
    private static _getNextDocId(): string{
        this._lastDocId++;
        return "tmpfile_" + this._lastDocId;
    }

    public static async createDocument(strContent: string, extension:string = "")
        : Promise<vscode.TextDocument | null>
    {
        let folder = "/tmp"
        let filename = this._getNextDocId ();
        let ext = (extension != "" ? "." + extension : "");


        const newFile = vscode.Uri.parse('untitled:' + path.join(folder, filename + ext));

        {
            const edit = new vscode.WorkspaceEdit();
            edit.insert(newFile, new vscode.Position(0, 0), strContent);
            
            let success = await vscode.workspace.applyEdit(edit);           
            
            if (!success)
                return null;
        }

        let document = await vscode.workspace.openTextDocument(newFile);
        return document;
    }
}

专业人士

  • 它是一个文件(架构),因此所有 LSP 命令都可以使用
  • 路径(上面使用的)甚至不需要存在。

缺点

  • 文件真的在编辑器中打开了。您需要稍后关闭它
  • 该文件是编辑器中的更改文件,因此它会要求您在关闭时保存更改。
  • 无法在 vscode 中关闭文件。您只能 运行:
vscode.window.showTextDocument(doc.uri, {preview: true, preserveFocus: false})
    .then(() => {        
        return vscode.commands.executeCommand('workbench.action.closeActiveEditor');
    });
```<br>
which is a rather nasty workaround.