Remove vs dependency in common

Fixes #5631
This commit is contained in:
Daniel Imms
2026-01-30 06:03:16 -08:00
parent 2521bab72f
commit e8d99d50a6
52 changed files with 286 additions and 86 deletions
+2 -2
View File
@@ -4,8 +4,8 @@
*/
import { ICircularList } from 'common/Types';
import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { Disposable } from 'common/Lifecycle';
import { Emitter } from 'common/Event';
export interface IInsertEvent {
index: number;
+2 -2
View File
@@ -37,8 +37,8 @@ import { IBufferSet } from 'common/buffer/Types';
import { InputHandler } from 'common/InputHandler';
import { WriteBuffer } from 'common/input/WriteBuffer';
import { OscLinkService } from 'common/services/OscLinkService';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'common/Event';
import { Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle';
// Only trigger this warning a single time per session
let hasWriteSyncWarnHappened = false;
+105
View File
@@ -0,0 +1,105 @@
/**
* Copyright (c) 2024-2026 The xterm.js authors. All rights reserved.
* @license MIT
*
* Minimal event utilities for xterm.js core.
* Simplified from VS Code's event.ts - no leak detection/profiling.
*/
import { IDisposable, DisposableStore, toDisposable } from 'common/Lifecycle';
export interface Event<T> {
(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;
}
export class Emitter<T> {
private _listeners: Array<{ fn: (e: T) => any; thisArgs: any }> = [];
private _disposed = false;
private _event: Event<T> | undefined;
public get event(): Event<T> {
if (!this._event) {
this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {
if (this._disposed) {
return toDisposable(() => {});
}
const entry = { fn: listener, thisArgs };
this._listeners.push(entry);
const result = toDisposable(() => {
const idx = this._listeners.indexOf(entry);
if (idx !== -1) {
this._listeners.splice(idx, 1);
}
});
if (disposables) {
if (Array.isArray(disposables)) {
disposables.push(result);
} else {
disposables.add(result);
}
}
return result;
};
}
return this._event;
}
public fire(event: T): void {
if (this._disposed) {
return;
}
// Snapshot listeners to allow modifications during iteration
const listeners = this._listeners.slice();
for (const { fn, thisArgs } of listeners) {
fn.call(thisArgs, event);
}
}
public dispose(): void {
if (this._disposed) {
return;
}
this._disposed = true;
this._listeners.length = 0;
}
}
export namespace Event {
export function forward<T>(from: Event<T>, to: Emitter<T>): IDisposable {
return from(e => to.fire(e));
}
export function map<I, O>(event: Event<I>, map: (i: I) => O): Event<O> {
return (listener: (e: O) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {
return event(i => listener.call(thisArgs, map(i)), undefined, disposables);
};
}
export function any<T>(...events: Event<T>[]): Event<T>;
export function any(...events: Event<any>[]): Event<void>;
export function any<T>(...events: Event<T>[]): Event<T> {
return (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {
const store = new DisposableStore();
for (const event of events) {
store.add(event(e => listener.call(thisArgs, e)));
}
if (disposables) {
if (Array.isArray(disposables)) {
disposables.push(store);
} else {
disposables.add(store);
}
}
return store;
};
}
export function runAndSubscribe<T>(event: Event<T>, handler: (e: T | undefined) => void): IDisposable {
handler(undefined);
return event(e => handler(e));
}
}
+2 -2
View File
@@ -8,7 +8,7 @@ import { IInputHandler, IAttributeData, IDisposable, IWindowOptions, IColorEvent
import { C0, C1 } from 'common/data/EscapeSequences';
import { CHARSETS, DEFAULT_CHARSET } from 'common/data/Charsets';
import { EscapeSequenceParser } from 'common/parser/EscapeSequenceParser';
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'common/Lifecycle';
import { StringToUtf32, stringFromCodePoint, Utf8ToUtf32 } from 'common/input/TextDecoder';
import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
import { IParsingState, IEscapeSequenceParser, IParams, IFunctionIdentifier } from 'common/parser/Types';
@@ -21,7 +21,7 @@ import { OscHandler } from 'common/parser/OscParser';
import { DcsHandler } from 'common/parser/DcsParser';
import { IBuffer } from 'common/buffer/Types';
import { parseColor } from 'common/input/XParseColor';
import { Emitter } from 'vs/base/common/event';
import { Emitter } from 'common/Event';
import { XTERM_VERSION } from 'common/Version';
/**
+100
View File
@@ -0,0 +1,100 @@
/**
* Copyright (c) 2024-2026 The xterm.js authors. All rights reserved.
* @license MIT
*
* Minimal lifecycle utilities for xterm.js core.
* Simplified from VS Code's lifecycle.ts - no tracking/leak detection.
*/
export interface IDisposable {
dispose(): void;
}
export function toDisposable(fn: () => void): IDisposable {
return { dispose: fn };
}
export function dispose<T extends IDisposable>(disposables: T | T[] | undefined): void {
if (!disposables) {
return;
}
if (Array.isArray(disposables)) {
for (const d of disposables) {
d.dispose();
}
} else {
disposables.dispose();
}
}
export function combinedDisposable(...disposables: IDisposable[]): IDisposable {
return toDisposable(() => dispose(disposables));
}
export class DisposableStore implements IDisposable {
private readonly _disposables = new Set<IDisposable>();
private _isDisposed = false;
public get isDisposed(): boolean {
return this._isDisposed;
}
public add<T extends IDisposable>(o: T): T {
if (this._isDisposed) {
o.dispose();
} else {
this._disposables.add(o);
}
return o;
}
public dispose(): void {
if (this._isDisposed) {
return;
}
this._isDisposed = true;
for (const d of this._disposables) {
d.dispose();
}
this._disposables.clear();
}
}
export abstract class Disposable implements IDisposable {
protected readonly _store = new DisposableStore();
public dispose(): void {
this._store.dispose();
}
protected _register<T extends IDisposable>(o: T): T {
return this._store.add(o);
}
}
export class MutableDisposable<T extends IDisposable> implements IDisposable {
private _value: T | undefined;
private _isDisposed = false;
public get value(): T | undefined {
return this._isDisposed ? undefined : this._value;
}
public set value(value: T | undefined) {
if (this._isDisposed || value === this._value) {
return;
}
this._value?.dispose();
this._value = value;
}
public clear(): void {
this.value = undefined;
}
public dispose(): void {
this._isDisposed = true;
this._value?.dispose();
this._value = undefined;
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ import { BufferSet } from 'common/buffer/BufferSet';
import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEventType, ICharset, IModes, IAttributeData, IOscLinkData, IDisposable } from 'common/Types';
import { UnicodeV6 } from 'common/input/UnicodeV6';
import { IDecorationOptions, IDecoration } from '@xterm/xterm';
import { Emitter, type Event } from 'vs/base/common/event';
import { Emitter, type Event } from 'common/Event';
export class MockBufferService implements IBufferService {
public serviceBrand: any;
+1 -1
View File
@@ -9,7 +9,7 @@ import { IBufferSet } from 'common/buffer/Types';
import { IParams } from 'common/parser/Types';
import { ICoreMouseService, ICoreService, IOptionsService, IUnicodeService } from 'common/services/Services';
import { IFunctionIdentifier, ITerminalOptions as IPublicTerminalOptions } from '@xterm/xterm';
import type { Emitter, Event } from 'vs/base/common/event';
import type { Emitter, Event } from 'common/Event';
export interface ICoreTerminal {
coreMouseService: ICoreMouseService;
+2 -2
View File
@@ -3,12 +3,12 @@
* @license MIT
*/
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'common/Lifecycle';
import { IAttributeData } from 'common/Types';
import { Buffer } from 'common/buffer/Buffer';
import { IBuffer, IBufferSet } from 'common/buffer/Types';
import { IBufferService, IOptionsService } from 'common/services/Services';
import { Emitter } from 'vs/base/common/event';
import { Emitter } from 'common/Event';
/**
* The BufferSet represents the set of two buffers used by xterm terminals (normal and alt) and
+2 -2
View File
@@ -4,8 +4,8 @@
*/
import { IDisposable, IMarker } from 'common/Types';
import { Emitter } from 'vs/base/common/event';
import { dispose } from 'vs/base/common/lifecycle';
import { Emitter } from 'common/Event';
import { dispose } from 'common/Lifecycle';
export class Marker implements IMarker {
private static _nextId = 1;
+1 -1
View File
@@ -4,7 +4,7 @@
*/
import { IAttributeData, ICircularList, IBufferLine, ICellData, IMarker, ICharset, IDisposable } from 'common/Types';
import type { Event } from 'vs/base/common/event';
import type { Event } from 'common/Event';
// BufferIndex denotes a position in the buffer: [rowIndex, colIndex]
export type BufferIndex = [number, number];
+2 -2
View File
@@ -4,8 +4,8 @@
* @license MIT
*/
import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { Disposable } from 'common/Lifecycle';
import { Emitter } from 'common/Event';
declare const setTimeout: (handler: () => void, timeout?: number) => void;
+1 -1
View File
@@ -5,7 +5,7 @@
import { IParsingState, IDcsHandler, IEscapeSequenceParser, IParams, IOscHandler, IHandlerCollection, CsiHandlerType, OscFallbackHandlerType, IOscParser, EscHandlerType, IDcsParser, DcsFallbackHandlerType, IFunctionIdentifier, ExecuteFallbackHandlerType, CsiFallbackHandlerType, EscFallbackHandlerType, PrintHandlerType, PrintFallbackHandlerType, ExecuteHandlerType, IParserStackState, ParserStackType, ResumableHandlersType } from 'common/parser/Types';
import { ParserState, ParserAction } from 'common/parser/Constants';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { IDisposable } from 'common/Types';
import { Params } from 'common/parser/Params';
import { OscParser } from 'common/parser/OscParser';
+2 -2
View File
@@ -6,8 +6,8 @@
import { IBuffer as IBufferApi, IBufferNamespace as IBufferNamespaceApi } from '@xterm/xterm';
import { BufferApiView } from 'common/public/BufferApiView';
import { ICoreTerminal } from 'common/Types';
import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { Disposable } from 'common/Lifecycle';
import { Emitter } from 'common/Event';
export class BufferNamespaceApi extends Disposable implements IBufferNamespaceApi {
private _normal: BufferApiView;
+2 -2
View File
@@ -3,12 +3,12 @@
* @license MIT
*/
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'common/Lifecycle';
import { IAttributeData, IBufferLine } from 'common/Types';
import { BufferSet } from 'common/buffer/BufferSet';
import { IBuffer, IBufferSet } from 'common/buffer/Types';
import { IBufferService, IOptionsService, type IBufferResizeEvent } from 'common/services/Services';
import { Emitter } from 'vs/base/common/event';
import { Emitter } from 'common/Event';
export const MINIMUM_COLS = 2; // Less than 2 can mess with wide chars
export const MINIMUM_ROWS = 1;
+2 -2
View File
@@ -4,8 +4,8 @@
*/
import { IBufferService, ICoreService, ICoreMouseService, IOptionsService } from 'common/services/Services';
import { ICoreMouseProtocol, ICoreMouseEvent, CoreMouseEncoding, CoreMouseEventType, CoreMouseButton, CoreMouseAction } from 'common/Types';
import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { Disposable } from 'common/Lifecycle';
import { Emitter } from 'common/Event';
/**
* Supported default protocols.
+2 -2
View File
@@ -4,10 +4,10 @@
*/
import { clone } from 'common/Clone';
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'common/Lifecycle';
import { IDecPrivateModes, IKittyKeyboardState, IModes } from 'common/Types';
import { IBufferService, ICoreService, ILogService, IOptionsService } from 'common/services/Services';
import { Emitter } from 'vs/base/common/event';
import { Emitter } from 'common/Event';
const DEFAULT_MODES: IModes = Object.freeze({
insertMode: false
@@ -6,8 +6,8 @@
import { assert } from 'chai';
import { DecorationService } from './DecorationService';
import { IMarker } from 'common/Types';
import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { Disposable } from 'common/Lifecycle';
import { Emitter } from 'common/Event';
function createFakeMarker(line: number): IMarker {
return Object.freeze(new class extends Disposable {
+2 -2
View File
@@ -4,12 +4,12 @@
*/
import { css } from 'common/Color';
import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore, toDisposable } from 'common/Lifecycle';
import { IDecorationService, IInternalDecoration } from 'common/services/Services';
import { SortedList } from 'common/SortedList';
import { IColor } from 'common/Types';
import { IDecoration, IDecorationOptions, IMarker } from '@xterm/xterm';
import { Emitter } from 'vs/base/common/event';
import { Emitter } from 'common/Event';
// Work variables to avoid garbage collection
let $xmin = 0;
+1 -1
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'common/Lifecycle';
import { ILogService, IOptionsService, LogLevelEnum } from 'common/services/Services';
type LogType = (message?: any, ...optionalParams: any[]) => void;
+2 -2
View File
@@ -3,11 +3,11 @@
* @license MIT
*/
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { isMac } from 'common/Platform';
import { CursorStyle, IDisposable } from 'common/Types';
import { FontWeight, IOptionsService, ITerminalOptions } from 'common/services/Services';
import { Emitter } from 'vs/base/common/event';
import { Emitter } from 'common/Event';
export const DEFAULT_OPTIONS: Readonly<Required<ITerminalOptions>> = {
cols: 80,
+1 -1
View File
@@ -7,7 +7,7 @@ import { IDecoration, IDecorationOptions, ILinkHandler, ILogger, IWindowsPty, ty
import { CoreMouseEncoding, CoreMouseEventType, CursorInactiveStyle, CursorStyle, IAttributeData, ICharset, IColor, ICoreMouseEvent, ICoreMouseProtocol, IDecPrivateModes, IDisposable, IKittyKeyboardState, IModes, IOscLinkData, IWindowOptions } from 'common/Types';
import { IBuffer, IBufferSet } from 'common/buffer/Types';
import { createDecorator } from 'common/services/ServiceRegistry';
import type { Emitter, Event } from 'vs/base/common/event';
import type { Emitter, Event } from 'common/Event';
export const IBufferService = createDecorator<IBufferService>('BufferService');
export interface IBufferService {
+1 -1
View File
@@ -5,7 +5,7 @@
import { UnicodeV6 } from 'common/input/UnicodeV6';
import { IUnicodeService, IUnicodeVersionProvider, UnicodeCharProperties, UnicodeCharWidth } from 'common/services/Services';
import { Emitter } from 'vs/base/common/event';
import { Emitter } from 'common/Event';
export class UnicodeService implements IUnicodeService {
public serviceBrand: any;
+1 -4
View File
@@ -11,14 +11,11 @@
],
"baseUrl": "..",
"paths": {
"vs/*": [ "./vs/*" ]
"common/*": [ "./common/*" ]
}
},
"include": [
"./**/*",
"../../typings/xterm.d.ts"
],
"references": [
{ "path": "../vs" }
]
}