Cancel progress programmatically in Visual Studio Code extensions

December 20, 2022

With the Visual Studio Code progress notification (vscode.window.withProgress), you can make it cancellable. This cancellable option allows the user to cancel it by clicking on a cancel button.

Progress notification in Visual Studio Code
Progress notification in Visual Studio Code

What if you want to cancel it programmatically? That was the case for one of my extensions. When a user performs another action triggered outside the progress, it should stop the current progress and remove the notification.

For example, in your progress, you are processing all files because the user requested to analyze these. Once the user opens another view or requests to analyze a single file, the other progress can be stopped.

The cancellation token

With the progress its callback, you get a CancellationToken argument, although this token can only be used to monitor if the user has canceled the operation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
vscode.window.withProgress({
    title: 'Please wait...',
    location: vscode.ProgressLocation.Notification,
    cancellable: true
  },
  async (progress, token) => {
  // You code to process the progress

  const seconds = 10;
  for (let i = 0; i < seconds; i++) {
    // Increment is summed up with the previous value
    progress.report({ increment: seconds })
    await sleep(1000);
  }
});

If we want to do this programmatically, you must create your own CancellationToken logic. The nice thing is that Visual Studio Code’s extension API already provides this.

To create your cancellation logic, you can use the vscode.CancellationTokenSource class. When creating a new instance, you will get a cancellation token that you can cancel and dismiss. All you have to do is hook it up in your progress and listen to the cancellation trigger.

The code for this looks as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import * as vscode from 'vscode';

const sleep = (time: number) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(true);
    }, time);
  });
}

let customCancellationToken: vscode.CancellationTokenSource | null = null;

export function activate(context: vscode.ExtensionContext) {

  vscode.window.withProgress({
    title: 'Please wait...',
    location: vscode.ProgressLocation.Notification,
    cancellable: true
  },
  async (progress, token) => {
    return new Promise((async (resolve) => {
      // You code to process the progress

      customCancellationToken = new vscode.CancellationTokenSource();

      customCancellationToken.token.onCancellationRequested(() => {
        customCancellationToken?.dispose();
        customCancellationToken = null;

        vscode.window.showInformationMessage("Cancelled the progress");
        resolve(null);
        return;
      });

      const seconds = 30;
      for (let i = 0; i < seconds; i++) {
        await sleep(1000);
      }
            
      resolve(null);
    }));
  });


  // Cancel the progress after 10 seconds
  setTimeout(() => {
    if (customCancellationToken) {
      customCancellationToken.cancel();
    }
  }, 10000);
}

info The above code snippet creates a progress notification for 30 seconds, but after 10 seconds, it will get canceled programmatically.

Cancelled message from the code snippet
Cancelled message from the code snippet

Comments