任務提供程式
使用者通常在 Visual Studio Code 的 tasks.json
檔案中定義任務。然而,在軟體開發過程中,有些任務可以由 VS Code 擴充套件透過任務提供程式自動檢測到。當從 VS Code 執行 Tasks: Run Task 命令時,所有活動任務提供程式都會貢獻使用者可以執行的任務。雖然 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
屬性的地方相同。建立任務定義時應始終考慮以下上下文
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
一樣,VS Code 呼叫 resolveTask
方法來從擴充套件中獲取任務。可以呼叫 resolveTask
而不是 provideTasks
,其目的是為實現它的提供程式提供可選的效能提升。例如,如果使用者有一個執行擴充套件提供的任務的鍵繫結,那麼 VS Code 呼叫該任務提供程式的 resolveTask
並快速獲取一個任務會更好,而不是必須呼叫 provideTasks
並等待擴充套件提供其所有任務。最好有一個設定允許使用者關閉單個任務提供程式,所以這很常見。使用者可能會注意到來自特定提供程式的任務獲取速度較慢並關閉該提供程式。在這種情況下,使用者可能仍然在他們的 tasks.json
中引用來自此提供程式的一些任務。如果未實現 resolveTask
,則會發出警告,指出其 tasks.json
中定義的任務未建立。透過 resolveTask
,擴充套件仍然可以為 tasks.json
中定義的任務提供任務。
getRakeTasks
的實現執行以下操作
- 使用
rake -AT -f Rakefile
命令列出每個工作區資料夾中Rakefile
中定義的所有 rake 任務。 - 解析標準輸出。
- 對於每個列出的任務,建立一個
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
是使用單個命令列建立的,則擴充套件需要確保命令中的正確引用和轉義(例如處理空格)。
自定義執行
一般來說,最好使用 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。