虛擬文件
文字文件內容提供者 (text document content provider) API 允許您在 Visual Studio Code 中從任意來源建立唯讀文件。您可以在此處找到包含原始程式碼的範例擴充功能:https://github.com/microsoft/vscode-extension-samples/blob/main/virtual-document-sample/README.md。
TextDocumentContentProvider
此 API 的運作方式是宣告一個 URI 配置 (scheme),您的提供者將為該配置回傳文字內容。在註冊提供者時必須指定此配置,且事後無法更改。同一個提供者可用於多個配置,單一配置也可以註冊多個提供者。
vscode.workspace.registerTextDocumentContentProvider(myScheme, myProvider);
呼叫 registerTextDocumentContentProvider 會回傳一個可拋棄 (disposable) 物件,用於撤銷註冊。提供者只需實作 provideTextDocumentContent 函式,該函式會透過 URI 和取消權杖 (cancellation token) 進行呼叫。
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。
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;
//...
})();
事件發送器 (event emitter) 有一個 fire 方法,可用於在文件發生變更時通知 VS Code。已變更的文件由傳遞給 fire 方法作為參數的 URI 識別。若該文件仍處於開啟狀態,提供者隨後將再次被呼叫以提供更新後的內容。
這就是讓 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 選單,預設情況下,該選單會顯示所有指令。

事件與可見性
文件提供者在 VS Code 中屬於一等公民,其內容會出現在一般文字文件中,並使用與檔案相同的基礎架構等。然而,這也意味著「您的」文件無法隱藏,它們會出現在 onDidOpenTextDocument 和 onDidCloseTextDocument 事件中,也是 vscode.workspace.textDocuments 的一部分。對所有人而言的規則是:檢查文件的 scheme,然後決定是否要針對該文件執行操作。
檔案系統 API
如果您需要更高的靈活性與功能,請參考 FileSystemProvider API。它允許您實作完整的檔案系統,包含檔案、資料夾、二進位資料、檔案刪除、建立等功能。
您可以在此處找到包含原始程式碼的範例擴充功能:https://github.com/microsoft/vscode-extension-samples/tree/main/fsprovider-sample/README.md。
當 VS Code 在此類檔案系統的資料夾或工作區開啟時,我們稱之為虛擬工作區 (virtual workspace)。當虛擬工作區在 VS Code 視窗中開啟時,左下角的遠端指示器會顯示標籤,類似於遠端視窗。請參閱虛擬工作區指南 (Virtual Workspace Guide) 以了解擴充功能如何支援該設定。