Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/common/cancellation.ts
3292 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Emitter, Event } from './event.js';
7
import { DisposableStore, IDisposable } from './lifecycle.js';
8
9
export interface CancellationToken {
10
11
/**
12
* A flag signalling is cancellation has been requested.
13
*/
14
readonly isCancellationRequested: boolean;
15
16
/**
17
* An event which fires when cancellation is requested. This event
18
* only ever fires `once` as cancellation can only happen once. Listeners
19
* that are registered after cancellation will be called (next event loop run),
20
* but also only once.
21
*
22
* @event
23
*/
24
readonly onCancellationRequested: (listener: (e: any) => any, thisArgs?: any, disposables?: IDisposable[]) => IDisposable;
25
}
26
27
const shortcutEvent: Event<any> = Object.freeze(function (callback, context?): IDisposable {
28
const handle = setTimeout(callback.bind(context), 0);
29
return { dispose() { clearTimeout(handle); } };
30
});
31
32
export namespace CancellationToken {
33
34
export function isCancellationToken(thing: unknown): thing is CancellationToken {
35
if (thing === CancellationToken.None || thing === CancellationToken.Cancelled) {
36
return true;
37
}
38
if (thing instanceof MutableToken) {
39
return true;
40
}
41
if (!thing || typeof thing !== 'object') {
42
return false;
43
}
44
return typeof (thing as CancellationToken).isCancellationRequested === 'boolean'
45
&& typeof (thing as CancellationToken).onCancellationRequested === 'function';
46
}
47
48
49
export const None = Object.freeze<CancellationToken>({
50
isCancellationRequested: false,
51
onCancellationRequested: Event.None
52
});
53
54
export const Cancelled = Object.freeze<CancellationToken>({
55
isCancellationRequested: true,
56
onCancellationRequested: shortcutEvent
57
});
58
}
59
60
class MutableToken implements CancellationToken {
61
62
private _isCancelled: boolean = false;
63
private _emitter: Emitter<any> | null = null;
64
65
public cancel() {
66
if (!this._isCancelled) {
67
this._isCancelled = true;
68
if (this._emitter) {
69
this._emitter.fire(undefined);
70
this.dispose();
71
}
72
}
73
}
74
75
get isCancellationRequested(): boolean {
76
return this._isCancelled;
77
}
78
79
get onCancellationRequested(): Event<any> {
80
if (this._isCancelled) {
81
return shortcutEvent;
82
}
83
if (!this._emitter) {
84
this._emitter = new Emitter<any>();
85
}
86
return this._emitter.event;
87
}
88
89
public dispose(): void {
90
if (this._emitter) {
91
this._emitter.dispose();
92
this._emitter = null;
93
}
94
}
95
}
96
97
export class CancellationTokenSource {
98
99
private _token?: CancellationToken = undefined;
100
private _parentListener?: IDisposable = undefined;
101
102
constructor(parent?: CancellationToken) {
103
this._parentListener = parent && parent.onCancellationRequested(this.cancel, this);
104
}
105
106
get token(): CancellationToken {
107
if (!this._token) {
108
// be lazy and create the token only when
109
// actually needed
110
this._token = new MutableToken();
111
}
112
return this._token;
113
}
114
115
cancel(): void {
116
if (!this._token) {
117
// save an object by returning the default
118
// cancelled token when cancellation happens
119
// before someone asks for the token
120
this._token = CancellationToken.Cancelled;
121
122
} else if (this._token instanceof MutableToken) {
123
// actually cancel
124
this._token.cancel();
125
}
126
}
127
128
dispose(cancel: boolean = false): void {
129
if (cancel) {
130
this.cancel();
131
}
132
this._parentListener?.dispose();
133
if (!this._token) {
134
// ensure to initialize with an empty token if we had none
135
this._token = CancellationToken.None;
136
137
} else if (this._token instanceof MutableToken) {
138
// actually dispose
139
this._token.dispose();
140
}
141
}
142
}
143
144
export function cancelOnDispose(store: DisposableStore): CancellationToken {
145
const source = new CancellationTokenSource();
146
store.add({ dispose() { source.cancel(); } });
147
return source.token;
148
}
149
150