🚀 在 VS Code 中

虛擬文件

文字文件內容提供者 API 允許您從任意來源在 Visual Studio Code 中建立唯讀文件。您可以在以下位置找到包含原始碼的範例擴充功能:https://github.com/microsoft/vscode-extension-samples/blob/main/virtual-document-sample/README.md

TextDocumentContentProvider

此 API 的運作方式是聲明一個 uri 方案,您的提供者會針對該方案傳回文字內容。該方案必須在註冊提供者時提供,並且之後無法變更。相同的提供者可以用於多個方案,並且可以為單一方案註冊多個提供者。

vscode.workspace.registerTextDocumentContentProvider(myScheme, myProvider);

呼叫 registerTextDocumentContentProvider 會傳回一個可支配物件,可用於撤銷註冊。提供者僅需實作 provideTextDocumentContent 函數,該函數會使用 uri 和取消權杖呼叫。

const myProvider = new (class implements vscode.TextDocumentContentProvider {
  provideTextDocumentContent(uri: vscode.Uri): string {
    // invoke cowsay, use uri-path as text
    return cowsay.say({ text: uri.path });
  }
})();

請注意,提供者不會為虛擬文件建立 uri - 其角色是針對給定的 uri 提供內容。相對地,內容提供者會連結到開啟文件邏輯,以便始終考慮提供者。

此範例使用 'cowsay' 命令來製作一個 uri,編輯器應隨後顯示該 uri

vscode.commands.registerCommand('cowsay.say', async () => {
  let what = await vscode.window.showInputBox({ placeHolder: 'cow say?' });
  if (what) {
    let uri = vscode.Uri.parse('cowsay:' + what);
    let doc = await vscode.workspace.openTextDocument(uri); // calls back into the provider
    await vscode.window.showTextDocument(doc, { preview: false });
  }
});

該命令會提示輸入,建立 cowsay 方案的 uri,開啟該 uri 的文件,最後開啟該文件的編輯器。在步驟 3 開啟文件時,系統會要求提供者提供該 uri 的內容。

如此一來,我們就有了一個功能完整的文字文件內容提供者。接下來的章節將說明如何更新虛擬文件,以及如何為虛擬文件註冊 UI 命令。

更新虛擬文件

根據情境,虛擬文件可能會變更。為了支援這一點,提供者可以實作 onDidChange 事件。

vscode.Event 類型定義了 VS Code 中事件的合約。實作事件的最簡單方法是 vscode.EventEmitter,如下所示

const myProvider = new (class implements vscode.TextDocumentContentProvider {
  // emitter and its event
  onDidChangeEmitter = new vscode.EventEmitter<vscode.Uri>();
  onDidChange = this.onDidChangeEmitter.event;

  //...
})();

事件發射器具有一個 fire 方法,可用於在文件中發生變更時通知 VS Code。已變更的文件由其 uri 識別,uri 作為引數提供給 fire 方法。然後將再次呼叫提供者以提供更新的內容,假設文件仍處於開啟狀態。

這就是讓 VS Code 監聽虛擬文件變更所需的一切。若要查看更複雜的範例,其中利用了此功能,請查看:https://github.com/microsoft/vscode-extension-samples/blob/main/contentprovider-sample/README.md

新增編輯器命令

可以新增僅與關聯內容提供者所提供文件互動的編輯器動作。這是一個範例命令,用於反轉乳牛剛才說的話

// register a command that updates the current cowsay
subscriptions.push(
  vscode.commands.registerCommand('cowsay.backwards', async () => {
    if (!vscode.window.activeTextEditor) {
      return; // no editor
    }
    let { document } = vscode.window.activeTextEditor;
    if (document.uri.scheme !== myScheme) {
      return; // not my scheme
    }
    // get path-components, reverse it, and create a new uri
    let say = document.uri.path;
    let newSay = say
      .split('')
      .reverse()
      .join('');
    let newUri = document.uri.with({ path: newSay });
    await vscode.window.showTextDocument(newUri, { preview: false });
  })
);

上面的程式碼片段檢查我們是否有一個活動編輯器,以及其文件是否為我們的方案之一。由於命令對所有人都是可用的(且可執行的),因此需要這些檢查。然後,uri 的路徑元件會被反轉,並從中建立一個新的 uri,最後開啟一個編輯器。

為了使用編輯器命令來完成工作,需要在 package.json 中加入宣告式部分。在 contributes 區段中,加入此組態

"menus": {
  "editor/title": [
    {
      "command": "cowsay.backwards",
      "group": "navigation",
      "when": "resourceScheme == cowsay"
    }
  ]
}

這會參考在 contributes/commands 區段中定義的 cowsay.backwards 命令,並表示它應出現在編輯器標題選單(右上角的工具列)中。現在,僅此一項就表示該命令始終顯示,適用於每個編輯器。這就是 when 子句的用途 - 它描述了顯示動作必須為真的條件。在此範例中,它指出編輯器中文件的方案必須是 cowsay 方案。然後針對 commandPalette 選單重複組態 - 預設情況下它會顯示所有命令。

cowsay-bwd

事件和可見性

文件提供者在 VS Code 中是一等公民,其內容會顯示在常規文字文件中,它們使用與檔案等相同的基礎架構。但是,這也表示「您的」文件無法隱藏,它們會出現在 onDidOpenTextDocumentonDidCloseTextDocument 事件中,它們是 vscode.workspace.textDocuments 的一部分等等。適用於所有人的規則是檢查文件的 scheme,然後決定是否要對文件執行某些操作。

檔案系統 API

如果您需要更大的彈性和功能,請查看 FileSystemProvider API。它允許實作完整檔案系統,具有檔案、資料夾、二進位資料、檔案刪除、建立等功能。

您可以在以下位置找到包含原始碼的範例擴充功能:https://github.com/microsoft/vscode-extension-samples/tree/main/fsprovider-sample/README.md

當 VS Code 在此類檔案系統的資料夾或工作區上開啟時,我們稱之為虛擬工作區。當虛擬工作區在 VS Code 視窗中開啟時,這會在左下角的遠端指示器中以標籤顯示,類似於遠端視窗。請參閱虛擬工作區指南,瞭解擴充功能如何支援該設定。