diff --git a/src/core/extension.ts b/src/core/extension.ts index 166b1193..2f4d892e 100644 --- a/src/core/extension.ts +++ b/src/core/extension.ts @@ -142,11 +142,10 @@ export default class ExtensionCore extends EventEmitter implements Dispo return workspace.getWorkspaceFolder(Uri.file(filePath))?.uri; } - if (!options.silent) { - if (options.token && options.token.isCancellationRequested) return; - const picked = await window.showWorkspaceFolderPick(); - if (picked) return picked.uri; - } + if (options.silent || options.token?.isCancellationRequested) return; + + const picked = await window.showWorkspaceFolderPick(); + if (picked) return picked.uri; } async activate(context: ExtensionContext = this.context) { diff --git a/src/structures/Timeout.ts b/src/structures/Timeout.ts index d6306ccd..47a74032 100644 --- a/src/structures/Timeout.ts +++ b/src/structures/Timeout.ts @@ -1,44 +1,51 @@ -const MAX_TIMER_DELAY = 2147483647; +const _maxTimerDelay = 2147483647; -export default class Timeout { - constructor(callback: () => unknown, delay: number = 0) { +export default class Timeout implements NodeJS.Timeout { + constructor(callback: () => unknown, delay: number = 1) { this.#callback = callback; this.#remain = this.#delay = delay; this.#start(); } + _onTimeout(...args: any[]): void { + this.#timeout._onTimeout(...args); + } + #callback: () => unknown; - #called: boolean = false; + #called!: boolean; #delay: number; #remain!: number; #timeout!: NodeJS.Timeout; #start() { this.#called = false; - if (this.#remain > MAX_TIMER_DELAY) { - this.#timeout = setTimeout(() => { - this.#remain -= MAX_TIMER_DELAY; - if (this.#remain > MAX_TIMER_DELAY) - this.#timeout.refresh(); - else this.#start(); - }, MAX_TIMER_DELAY).unref(); + if (this.#remain > _maxTimerDelay) { + this.#timeout = setTimeout(this.#autoRefreshCallback.bind(this), _maxTimerDelay).unref(); } else { - this.#timeout = setTimeout(() => { - this.#called = true; - this.#callback(); - }, this.#remain).unref(); + this.#timeout = setTimeout(this.#lastCallback.bind(this), this.#remain).unref(); } } + #autoRefreshCallback() { + this.#remain -= _maxTimerDelay; + if (this.#remain > _maxTimerDelay) return this.#timeout.refresh(); + this.#start(); + } + + #lastCallback() { + this.#called = true; + this.#callback(); + } + get delay() { return this.#delay; } /** @readonly */ get remain() { return this.#remain; } set delay(delay) { - const diff = delay - this.#delay; - this.#delay = delay; + const diff = delay - this.#delay; + this.#remain += diff; if (this.#called) return; @@ -47,16 +54,16 @@ export default class Timeout { } /** If true, the `Timeout` object will keep the Node.js event loop active. */ - get hasRef() { - return this.#timeout.hasRef(); - } + hasRef() { return this.#timeout.hasRef(); } ref() { this.#timeout.ref(); + return this; } unref() { this.#timeout.unref(); + return this; } reset() { @@ -64,6 +71,11 @@ export default class Timeout { this.restart(); } + refresh() { + this.#timeout.refresh(); + return this; + } + restart() { this.close(); this.#start(); @@ -71,9 +83,12 @@ export default class Timeout { close() { clearTimeout(this.#timeout); + return this; } - dispose() { - this.close(); - } + dispose() { this.#timeout[Symbol.dispose](); } + + [Symbol.toPrimitive]() { return this.#timeout[Symbol.toPrimitive](); } + + [Symbol.dispose]() { this.#timeout[Symbol.dispose](); } } diff --git a/src/structures/TimerMap.ts b/src/structures/TimerMap.ts index d0aca69d..872fe926 100644 --- a/src/structures/TimerMap.ts +++ b/src/structures/TimerMap.ts @@ -1,6 +1,6 @@ import type { Disposable } from "vscode"; -const MAX_TIMER_DELAY = 2147483647; +const _maxTimerDelay = 2147483647; export interface TimerMapOptions { /** @@ -13,9 +13,9 @@ export interface TimerMapOptions { autoUnref?: boolean } -export default class TimerMap extends Map implements Disposable { +export default class TimerMap extends Map implements Disposable { constructor( - entries?: readonly (readonly [K, V])[] | Iterable | null, + entries?: readonly (readonly [K, T])[] | Iterable | null, options?: TimerMapOptions, ) { super(entries); @@ -50,7 +50,7 @@ export default class TimerMap exte return this.get(key)?.refresh(); } - set(key: K, timeout: V): this { + set(key: K, timeout: T): this { this.clearTimeout(key); return super.set(key, timeout); } @@ -72,25 +72,28 @@ export default class TimerMap exte setTimeout(key: K, callback: () => void, delay: number = 1): void { this.clearTimeout(key); - if (delay > MAX_TIMER_DELAY) return this._autoRefresh(key, callback, delay); + if (delay > _maxTimerDelay) return this.#autoRefresh(key, callback, delay); + + const timer = setTimeout(this.#wrapCallback(key, callback), delay); - const timer = setTimeout(this._wrapCallback(key, callback), delay); if (this.autoUnref) timer.unref(); - super.set(key, timer as V); + + super.set(key, timer as T); } - protected _autoRefresh(key: K, callback: () => void, delay: number) { + #autoRefresh(key: K, callback: () => void, delay: number) { const timer = setTimeout(() => { - delay -= MAX_TIMER_DELAY; - if (delay > MAX_TIMER_DELAY) return timer.refresh(); + delay -= _maxTimerDelay; + if (delay > _maxTimerDelay) return timer.refresh(); this.setTimeout(key, callback, delay); - }, MAX_TIMER_DELAY); + }, _maxTimerDelay); if (this.autoUnref) timer.unref(); - super.set(key, timer as V); + + super.set(key, timer as T); } - protected _wrapCallback(key: K, callback: () => void) { + #wrapCallback(key: K, callback: () => void) { return () => { super.delete(key); callback();