ist jetzt verfügbar! Lesen Sie über die neuen Funktionen und Fehlerbehebungen vom November.

Aufgabenanbieter

Benutzer definieren normalerweise Tasks in Visual Studio Code in einer tasks.json Datei. Es gibt jedoch einige Tasks während der Softwareentwicklung, die von einer VS Code-Erweiterung mit einem Task Provider automatisch erkannt werden können. Wenn der Befehl Tasks: Task ausführen von VS Code aus gestartet wird, tragen alle aktiven Task Provider Tasks bei, die der Benutzer ausführen kann. Während die tasks.json Datei es dem Benutzer ermöglicht, einen Task für einen bestimmten Ordner oder Arbeitsbereich manuell zu definieren, kann ein Task Provider Details über einen Arbeitsbereich erkennen und dann automatisch einen entsprechenden VS Code Task erstellen. Zum Beispiel könnte ein Task Provider prüfen, ob eine bestimmte Build-Datei wie make oder Rakefile vorhanden ist, und einen Build-Task erstellen. Dieses Thema beschreibt, wie Erweiterungen Tasks für Endbenutzer automatisch erkennen und bereitstellen können.

Diese Anleitung zeigt Ihnen, wie Sie einen Task Provider erstellen, der in Rakefiles definierte Tasks automatisch erkennt. Der vollständige Quellcode ist verfügbar unter: https://github.com/microsoft/vscode-extension-samples/tree/main/task-provider-sample.

Task-Definition

Um einen Task im System eindeutig zu identifizieren, muss eine Erweiterung, die einen Task beisteuert, die Eigenschaften definieren, die einen Task identifizieren. Im Rake-Beispiel sieht die Task-Definition wie folgt aus:

"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."
            }
        }
    }
]

Dies trägt eine Task-Definition für rake-Tasks bei. Die Task-Definition hat zwei Attribute: task und file. task ist der Name des Rake-Tasks und file verweist auf die Rakefile, die den Task enthält. Die Eigenschaft task ist erforderlich, die Eigenschaft file ist optional. Wenn das Attribut file weggelassen wird, wird die Rakefile im Stammverzeichnis des Arbeitsbereichsordners verwendet.

Wenn-Klausel

Eine Task-Definition kann optional eine when-Eigenschaft haben. Die when-Eigenschaft gibt die Bedingung an, unter der ein Task dieses Typs verfügbar ist. Die when-Eigenschaft funktioniert auf die gleiche Weise wie an anderen Stellen in VS Code, wo es eine when-Eigenschaft gibt. Die folgenden Kontexte sollten bei der Erstellung einer Task-Definition immer berücksichtigt werden:

  • shellExecutionSupported: Wahr, wenn VS Code ShellExecution-Tasks ausführen kann, z. B. wenn VS Code als Desktop-Anwendung ausgeführt wird oder wenn eine der Remote-Erweiterungen wie Dev Containers verwendet wird.
  • processExecutionSupported: Wahr, wenn VS Code ProcessExecution-Tasks ausführen kann, z. B. wenn VS Code als Desktop-Anwendung ausgeführt wird oder wenn eine der Remote-Erweiterungen wie Dev Containers verwendet wird. Derzeit wird dieser Wert immer mit shellExecutionSupported übereinstimmen.
  • customExecutionSupported: Wahr, wenn VS Code CustomExecution ausführen kann. Dies ist immer wahr.

Task Provider

Analog zu Sprach-Providern, die Erweiterungen die Unterstützung von Code-Vervollständigung ermöglichen, kann eine Erweiterung einen Task Provider registrieren, um alle verfügbaren Tasks zu berechnen. Dies geschieht über den vscode.tasks-Namespace, wie im folgenden Code-Snippet gezeigt:

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;
  }
});

Ähnlich wie provideTasks wird die Methode resolveTask von VS Code aufgerufen, um Tasks von der Erweiterung zu erhalten. resolveTask kann anstelle von provideTasks aufgerufen werden und zielt darauf ab, eine optionale Leistungssteigerung für Provider zu erzielen, die sie implementieren. Wenn ein Benutzer beispielsweise eine Tastenkombination hat, die einen von der Erweiterung bereitgestellten Task ausführt, wäre es für VS Code besser, resolveTask für diesen Task Provider aufzurufen und schnell nur diesen einen Task abzurufen, anstatt provideTasks aufrufen und darauf warten zu müssen, dass die Erweiterung alle ihre Tasks bereitstellt. Es ist eine gute Praxis, eine Einstellung zu haben, die es Benutzern ermöglicht, einzelne Task Provider zu deaktivieren, daher ist dies üblich. Ein Benutzer bemerkt möglicherweise, dass Tasks von einem bestimmten Provider langsamer abgerufen werden, und deaktiviert den Provider. In diesem Fall kann der Benutzer möglicherweise immer noch einige der Tasks von diesem Provider in seiner tasks.json referenzieren. Wenn resolveTask nicht implementiert ist, wird eine Warnung ausgegeben, dass der Task in seiner tasks.json nicht erstellt wurde. Mit resolveTask kann eine Erweiterung immer noch einen Task für den in tasks.json definierten Task bereitstellen.

Die Implementierung von getRakeTasks tut Folgendes:

  • Listet alle in einer Rakefile definierten Rake-Tasks mit dem Befehl rake -AT -f Rakefile für jeden Arbeitsbereichsordner auf.
  • Parst die Standard-Ein-/Ausgabe (stdio).
  • Erstellt für jeden aufgeführten Task eine vscode.Task-Implementierung.

Da die Instanziierung eines Rake-Tasks eine Task-Definition erfordert, wie sie in der package.json Datei definiert ist, definiert VS Code die Struktur auch mit einer TypeScript-Schnittstelle wie dieser:

interface RakeTaskDefinition extends vscode.TaskDefinition {
  /**
   * The task name
   */
  task: string;

  /**
   * The rake file containing the task
   */
  file?: string;
}

Unter der Annahme, dass die Ausgabe von einem Task namens compile im ersten Arbeitsbereichsordner stammt, sieht die entsprechende Task-Erstellung dann wie folgt aus:

let task = new vscode.Task(
  { type: 'rake', task: 'compile' },
  vscode.workspace.workspaceFolders[0],
  'compile',
  'rake',
  new vscode.ShellExecution('rake compile')
);

Für jeden in der Ausgabe aufgeführten Task wird ein entsprechender VS Code-Task mit dem obigen Muster erstellt und dann wird das Array aller Tasks aus dem getRakeTasks-Aufruf zurückgegeben.

ShellExecution führt den Befehl rake compile in der für das Betriebssystem spezifischen Shell aus (z. B. unter Windows wird der Befehl in PowerShell ausgeführt, unter Ubuntu in Bash). Wenn der Task direkt einen Prozess ausführen soll (ohne eine Shell zu starten), kann vscode.ProcessExecution verwendet werden. ProcessExecution hat den Vorteil, dass die Erweiterung die vollständige Kontrolle über die an den Prozess übergebenen Argumente hat. Die Verwendung von ShellExecution nutzt die Interpretation von Shell-Befehlen (wie z. B. Wildcard-Erweiterung unter Bash). Wenn ShellExecution mit einer einzelnen Befehlszeile erstellt wird, muss die Erweiterung die richtige Anführungszeichensetzung und Maskierung (z. B. zur Behandlung von Leerzeichen) innerhalb des Befehls sicherstellen.

CustomExecution

Im Allgemeinen ist es am besten, ShellExecution oder ProcessExecution zu verwenden, da sie einfach sind. Wenn Ihr Task jedoch viel gespeicherten Zustand zwischen den Ausführungen benötigt, nicht gut als separates Skript oder Prozess funktioniert oder eine umfangreiche Ausgabebehandlung erfordert, könnte CustomExecution eine gute Wahl sein. Bestehende Verwendungen von CustomExecution sind normalerweise für komplexe Build-Systeme. Eine CustomExecution hat nur einen Callback, der zum Zeitpunkt der Task-Ausführung ausgeführt wird. Dies ermöglicht eine größere Flexibilität bei dem, was der Task tun kann, bedeutet aber auch, dass der Task Provider für die Prozessverwaltung und die Ausgabeanalyse verantwortlich ist. Der Task Provider ist auch dafür verantwortlich, Pseudoterminal zu implementieren und es aus dem CustomExecution-Callback zurückzugeben.

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)
      );
    }
  )
);

Das vollständige Beispiel, einschließlich der Implementierung von Pseudoterminal, finden Sie unter https://github.com/microsoft/vscode-extension-samples/tree/main/task-provider-sample/src/customTaskProvider.ts.

© . This site is unofficial and not affiliated with Microsoft.