Reorganize src/common into platform (base, encoding, data, buffer, parser, input), integration (services, terminal), and public API layers. - Move core utilities to common/base/ - Move TextDecoder to common/encoding/ - Move Types, CircularList, Color, TaskQueue, SortedList to common/services/ - Move CoreTerminal, InputHandler, WindowsMode to common/terminal/ - Define ICharset in common/data/Charsets.ts (re-exported from Types) - Update imports across src/, addons/, and test/ - Add per-layer tsconfig.json files and REARCHITECTURE.md - Root common/tsconfig.json remains the composite build entry Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
142 lines
3.5 KiB
TypeScript
142 lines
3.5 KiB
TypeScript
/**
|
|
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
|
* @license MIT
|
|
*
|
|
* Minimal async helpers for xterm.js core.
|
|
*/
|
|
|
|
import { DisposableStore, IDisposable, toDisposable } from 'common/base/Lifecycle';
|
|
|
|
export function timeout(millis: number): Promise<void> {
|
|
return new Promise(resolve => setTimeout(resolve, millis));
|
|
}
|
|
|
|
/**
|
|
* Creates a timeout that can be disposed using its returned value.
|
|
* @param handler The timeout handler.
|
|
* @param timeout An optional timeout in milliseconds.
|
|
* @param store An optional {@link DisposableStore} that will have the timeout disposable managed
|
|
* automatically.
|
|
*/
|
|
export function disposableTimeout(handler: () => void, timeout = 0, store?: DisposableStore): IDisposable {
|
|
const timer = setTimeout(() => {
|
|
handler();
|
|
if (store) {
|
|
disposable.dispose();
|
|
}
|
|
}, timeout);
|
|
const disposable = toDisposable(() => {
|
|
clearTimeout(timer);
|
|
});
|
|
store?.add(disposable);
|
|
return disposable;
|
|
}
|
|
|
|
export class TimeoutTimer implements IDisposable {
|
|
private _token: any = -1;
|
|
private _isDisposed = false;
|
|
|
|
public dispose(): void {
|
|
this.cancel();
|
|
this._isDisposed = true;
|
|
}
|
|
|
|
public cancel(): void {
|
|
if (this._token !== -1) {
|
|
clearTimeout(this._token);
|
|
this._token = -1;
|
|
}
|
|
}
|
|
|
|
public cancelAndSet(runner: () => void, timeout: number): void {
|
|
if (this._isDisposed) {
|
|
throw new Error('Calling cancelAndSet on a disposed TimeoutTimer');
|
|
}
|
|
this.cancel();
|
|
this._token = setTimeout(() => {
|
|
this._token = -1;
|
|
runner();
|
|
}, timeout);
|
|
}
|
|
|
|
public setIfNotSet(runner: () => void, timeout: number): void {
|
|
if (this._isDisposed) {
|
|
throw new Error('Calling setIfNotSet on a disposed TimeoutTimer');
|
|
}
|
|
if (this._token !== -1) {
|
|
return;
|
|
}
|
|
this._token = setTimeout(() => {
|
|
this._token = -1;
|
|
runner();
|
|
}, timeout);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Schedules a single runner on the microtask queue. Unlike {@link TimeoutTimer}, a scheduled
|
|
* microtask cannot be unqueued; {@link cancel} prevents the runner from executing if it has not
|
|
* run yet.
|
|
*/
|
|
export class MicrotaskTimer implements IDisposable {
|
|
private _isScheduled = false;
|
|
private _isDisposed = false;
|
|
|
|
public dispose(): void {
|
|
this.cancel();
|
|
this._isDisposed = true;
|
|
}
|
|
|
|
public cancel(): void {
|
|
this._isScheduled = false;
|
|
}
|
|
|
|
public set(runner: () => void): void {
|
|
if (this._isDisposed) {
|
|
throw new Error('Calling set on a disposed MicrotaskTimer');
|
|
}
|
|
if (this._isScheduled) {
|
|
return;
|
|
}
|
|
this._isScheduled = true;
|
|
queueMicrotask(() => {
|
|
if (!this._isScheduled) {
|
|
return;
|
|
}
|
|
this._isScheduled = false;
|
|
runner();
|
|
});
|
|
}
|
|
}
|
|
|
|
export class IntervalTimer implements IDisposable {
|
|
private _disposable: IDisposable | undefined;
|
|
private _isDisposed = false;
|
|
|
|
public cancel(): void {
|
|
this._disposable?.dispose();
|
|
this._disposable = undefined;
|
|
}
|
|
|
|
public cancelAndSet(runner: () => void, interval: number, context: Window | typeof globalThis = globalThis): void {
|
|
if (this._isDisposed) {
|
|
throw new Error('Calling cancelAndSet on a disposed IntervalTimer');
|
|
}
|
|
this.cancel();
|
|
const handle = context.setInterval(() => {
|
|
runner();
|
|
}, interval);
|
|
this._disposable = {
|
|
dispose: () => {
|
|
context.clearInterval(handle as any);
|
|
this._disposable = undefined;
|
|
}
|
|
};
|
|
}
|
|
|
|
public dispose(): void {
|
|
this.cancel();
|
|
this._isDisposed = true;
|
|
}
|
|
}
|