工作提供者
使用者通常會在 Visual Studio Code 的 tasks.json
檔案中定義工作。然而,在軟體開發過程中,有些工作可以透過具有工作提供者的 VS Code 擴充功能自動偵測到。當從 VS Code 執行 工作:執行工作 命令時,所有啟用的工作提供者都會貢獻使用者可以執行的工作。雖然 tasks.json
檔案讓使用者可以針對特定資料夾或工作區手動定義工作,但工作提供者可以偵測工作區的詳細資訊,然後自動建立對應的 VS Code 工作。例如,工作提供者可以檢查是否有特定的組建檔案,例如 make
或 Rakefile
,並建立組建工作。本主題說明擴充功能如何自動偵測並向終端使用者提供工作。
本指南教您如何建置一個工作提供者,以自動偵測在 Rakefiles 中定義的工作。完整的原始碼位於:https://github.com/microsoft/vscode-extension-samples/tree/main/task-provider-sample。
工作定義
為了在系統中唯一識別工作,貢獻工作的擴充功能需要定義識別工作的屬性。在 Rake 範例中,工作定義如下所示
"taskDefinitions": [
{
"type": "rake",
"required": [
"task"
],
"properties": {
"task": {
"type": "string",
"description": "The Rake task to customize"
},
"file": {
"type": "string",
"description": "The Rake file that provides the task. Can be omitted."
}
}
}
]
這會為 rake
工作貢獻一個工作定義。工作定義有兩個屬性 task
和 file
。task
是 Rake 工作的名稱,而 file
指向包含該工作的 `Rakefile`。`task` 屬性是必要的,`file` 屬性是選用的。如果省略 `file` 屬性,則會使用工作區資料夾根目錄中的 `Rakefile`。
When 子句
工作定義可以選擇性地具有 when
屬性。`when` 屬性指定此類型工作可用的條件。`when` 屬性的運作方式與 VS Code 中其他具有 `when` 屬性的地方相同。在 VS Code 中的其他地方,都有 `when` 屬性。建立工作定義時,應始終考慮以下上下文
shellExecutionSupported
:當 VS Code 可以執行ShellExecution
工作時為 True,例如當 VS Code 作為桌面應用程式執行時,或當使用遠端擴充功能之一(例如 Dev Containers)時。processExecutionSupported
:當 VS Code 可以執行ProcessExecution
工作時為 True,例如當 VS Code 作為桌面應用程式執行時,或當使用遠端擴充功能之一(例如 Dev Containers)時。目前,它將始終具有與shellExecutionSupported
相同的值。customExecutionSupported
:當 VS Code 可以執行CustomExecution
時為 True。這始終為 True。
工作提供者
與語言提供者類似,語言提供者讓擴充功能支援程式碼完成,擴充功能可以註冊工作提供者來計算所有可用的工作。這是使用 `vscode.tasks` 命名空間完成的,如下列程式碼片段所示
import * as vscode from 'vscode';
let rakePromise: Thenable<vscode.Task[]> | undefined = undefined;
const taskProvider = vscode.tasks.registerTaskProvider('rake', {
provideTasks: () => {
if (!rakePromise) {
rakePromise = getRakeTasks();
}
return rakePromise;
},
resolveTask(_task: vscode.Task): vscode.Task | undefined {
const task = _task.definition.task;
// A Rake task consists of a task and an optional file as specified in RakeTaskDefinition
// Make sure that this looks like a Rake task by checking that there is a task.
if (task) {
// resolveTask requires that the same definition object be used.
const definition: RakeTaskDefinition = <any>_task.definition;
return new vscode.Task(
definition,
_task.scope ?? vscode.TaskScope.Workspace,
definition.task,
'rake',
new vscode.ShellExecution(`rake ${definition.task}`)
);
}
return undefined;
}
});
與 provideTasks
類似,`resolveTask` 方法由 VS Code 呼叫,以從擴充功能取得工作。可以呼叫 `resolveTask` 而不是 `provideTasks`,其目的是為實作它的提供者提供可選的效能提升。例如,如果使用者有一個快速鍵,用於執行擴充功能提供的工作,則 VS Code 最好為該工作提供者呼叫 `resolveTask`,並快速取得一個工作,而不是必須呼叫 `provideTasks` 並等待擴充功能提供其所有工作。最佳實務是設定允許使用者關閉個別工作提供者的設定,這很常見。使用者可能會注意到,從特定提供者取得工作速度較慢,並關閉該提供者。在這種情況下,使用者可能仍在其 `tasks.json` 中參考來自此提供者的一些工作。如果未實作 `resolveTask`,則會發出警告,指出未建立 `tasks.json` 中的工作。透過 `resolveTask`,擴充功能仍然可以為 `tasks.json` 中定義的工作提供工作。
getRakeTasks
實作執行以下操作
- 列出每個工作區資料夾中使用 `rake -AT -f Rakefile` 命令在 `Rakefile` 中定義的所有 rake 工作。
- 剖析 stdio 輸出。
- 針對每個列出的工作,建立 `vscode.Task` 實作。
由於 Rake 工作實例化需要 `package.json` 檔案中定義的工作定義,因此 VS Code 也使用 TypeScript 介面定義結構,如下所示
interface RakeTaskDefinition extends vscode.TaskDefinition {
/**
* The task name
*/
task: string;
/**
* The rake file containing the task
*/
file?: string;
}
假設輸出來自第一個工作區資料夾中名為 `compile` 的工作,則對應的工作建立如下所示
let task = new vscode.Task(
{ type: 'rake', task: 'compile' },
vscode.workspace.workspaceFolders[0],
'compile',
'rake',
new vscode.ShellExecution('rake compile')
);
針對輸出中列出的每個工作,都會使用上述模式建立對應的 VS Code 工作,然後傳回來自 `getRakeTasks` 呼叫的所有工作陣列。
`ShellExecution` 在特定於作業系統的 shell 中執行 `rake compile` 命令(例如,在 Windows 下,命令將在 PowerShell 中執行,在 Ubuntu 下,命令將在 bash 中執行)。如果工作應直接執行進程(而不產生 shell),則可以使用 `vscode.ProcessExecution`。`ProcessExecution` 的優點是擴充功能可以完全控制傳遞給進程的引數。使用 `ShellExecution` 可以利用 shell 命令解釋(例如 bash 下的萬用字元展開)。如果 `ShellExecution` 是使用單行命令列建立的,則擴充功能需要確保命令內部的正確引號和跳脫字元(例如處理空白字元)。
CustomExecution
一般而言,最好使用 `ShellExecution` 或 `ProcessExecution`,因為它們很簡單。但是,如果您的工作需要在執行之間儲存大量狀態、無法作為單獨的腳本或進程良好運作,或者需要廣泛處理輸出,則 `CustomExecution` 可能是一個不錯的選擇。`CustomExecution` 的現有用途通常用於複雜的組建系統。`CustomExecution` 只有一個回呼,該回呼在執行工作時執行。這允許工作可以執行的操作具有更大的彈性,但也意味著工作提供者負責任何需要發生的進程管理和輸出剖析。工作提供者還負責實作 `Pseudoterminal` 並從 `CustomExecution` 回呼中傳回它。
return new vscode.Task(
definition,
vscode.TaskScope.Workspace,
`${flavor} ${flags.join(' ')}`,
CustomBuildTaskProvider.CustomBuildScriptType,
new vscode.CustomExecution(
async (): Promise<vscode.Pseudoterminal> => {
// When the task is executed, this callback will run. Here, we setup for running the task.
return new CustomBuildTaskTerminal(
this.workspaceRoot,
flavor,
flags,
() => this.sharedState,
(state: string) => (this.sharedState = state)
);
}
)
);
包含 `Pseudoterminal` 實作的完整範例位於 https://github.com/microsoft/vscode-extension-samples/tree/main/task-provider-sample/src/customTaskProvider.ts。