mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Remove more parts
This commit is contained in:
@@ -11,7 +11,7 @@ import { ScrollbarArrow, ScrollbarArrowOptions } from './scrollbarArrow';
|
||||
import { ScrollbarState } from './scrollbarState';
|
||||
import { ScrollbarVisibilityController } from './scrollbarVisibilityController';
|
||||
import { Widget } from './widget';
|
||||
import * as platform from './platform';
|
||||
import * as platform from 'common/Platform';
|
||||
import { INewScrollPosition, Scrollable, ScrollbarVisibility } from './scrollable';
|
||||
|
||||
/**
|
||||
@@ -31,7 +31,7 @@ export interface ScrollbarHost {
|
||||
onDragEnd(): void;
|
||||
}
|
||||
|
||||
export interface AbstractScrollbarOptions {
|
||||
interface AbstractScrollbarOptions {
|
||||
lazyRender: boolean;
|
||||
host: ScrollbarHost;
|
||||
scrollbarState: ScrollbarState;
|
||||
|
||||
@@ -6,11 +6,3 @@
|
||||
export function tail<T>(array: ArrayLike<T>, n: number = 0): T | undefined {
|
||||
return array[array.length - (1 + n)];
|
||||
}
|
||||
|
||||
export function tail2<T>(arr: T[]): [T[], T] {
|
||||
if (arr.length === 0) {
|
||||
throw new Error('Invalid tail call');
|
||||
}
|
||||
|
||||
return [arr.slice(0, arr.length - 1), arr[arr.length - 1]];
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { IDisposable } from './lifecycle';
|
||||
|
||||
export class TimeoutTimer implements IDisposable {
|
||||
private _token: any = -1;
|
||||
private _isDisposed = false;
|
||||
|
||||
dispose(): void {
|
||||
this.cancel();
|
||||
this._isDisposed = true;
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
if (this._token !== -1) {
|
||||
clearTimeout(this._token);
|
||||
this._token = -1;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
export class IntervalTimer implements IDisposable {
|
||||
private _disposable: IDisposable | undefined;
|
||||
private _isDisposed = false;
|
||||
|
||||
cancel(): void {
|
||||
this._disposable?.dispose();
|
||||
this._disposable = undefined;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.cancel();
|
||||
this._isDisposed = true;
|
||||
}
|
||||
}
|
||||
@@ -3,139 +3,12 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CodeWindow, mainWindow } from './window';
|
||||
import { Emitter } from './event';
|
||||
|
||||
class WindowManager {
|
||||
|
||||
static readonly INSTANCE = new WindowManager();
|
||||
|
||||
// --- Zoom Level
|
||||
|
||||
private readonly mapWindowIdToZoomLevel = new Map<number, number>();
|
||||
|
||||
private readonly _onDidChangeZoomLevel = new Emitter<number>();
|
||||
readonly onDidChangeZoomLevel = this._onDidChangeZoomLevel.event;
|
||||
|
||||
getZoomLevel(targetWindow: Window): number {
|
||||
return this.mapWindowIdToZoomLevel.get(this.getWindowId(targetWindow)) ?? 0;
|
||||
}
|
||||
setZoomLevel(zoomLevel: number, targetWindow: Window): void {
|
||||
if (this.getZoomLevel(targetWindow) === zoomLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetWindowId = this.getWindowId(targetWindow);
|
||||
this.mapWindowIdToZoomLevel.set(targetWindowId, zoomLevel);
|
||||
this._onDidChangeZoomLevel.fire(targetWindowId);
|
||||
}
|
||||
|
||||
// --- Zoom Factor
|
||||
|
||||
private readonly mapWindowIdToZoomFactor = new Map<number, number>();
|
||||
|
||||
getZoomFactor(targetWindow: Window): number {
|
||||
return this.mapWindowIdToZoomFactor.get(this.getWindowId(targetWindow)) ?? 1;
|
||||
}
|
||||
setZoomFactor(zoomFactor: number, targetWindow: Window): void {
|
||||
this.mapWindowIdToZoomFactor.set(this.getWindowId(targetWindow), zoomFactor);
|
||||
}
|
||||
|
||||
// --- Fullscreen
|
||||
|
||||
private readonly _onDidChangeFullscreen = new Emitter<number>();
|
||||
readonly onDidChangeFullscreen = this._onDidChangeFullscreen.event;
|
||||
|
||||
private readonly mapWindowIdToFullScreen = new Map<number, boolean>();
|
||||
|
||||
setFullscreen(fullscreen: boolean, targetWindow: Window): void {
|
||||
if (this.isFullscreen(targetWindow) === fullscreen) {
|
||||
return;
|
||||
}
|
||||
|
||||
const windowId = this.getWindowId(targetWindow);
|
||||
this.mapWindowIdToFullScreen.set(windowId, fullscreen);
|
||||
this._onDidChangeFullscreen.fire(windowId);
|
||||
}
|
||||
isFullscreen(targetWindow: Window): boolean {
|
||||
return !!this.mapWindowIdToFullScreen.get(this.getWindowId(targetWindow));
|
||||
}
|
||||
|
||||
private getWindowId(targetWindow: Window): number {
|
||||
return (targetWindow as CodeWindow).vscodeWindowId;
|
||||
}
|
||||
}
|
||||
|
||||
export function addMatchMediaChangeListener(targetWindow: Window, query: string | MediaQueryList, callback: (this: MediaQueryList, ev: MediaQueryListEvent) => any): void {
|
||||
if (typeof query === 'string') {
|
||||
query = targetWindow.matchMedia(query);
|
||||
}
|
||||
query.addEventListener('change', callback);
|
||||
}
|
||||
|
||||
/** A zoom index, e.g. 1, 2, 3 */
|
||||
export function setZoomLevel(zoomLevel: number, targetWindow: Window): void {
|
||||
WindowManager.INSTANCE.setZoomLevel(zoomLevel, targetWindow);
|
||||
}
|
||||
export function getZoomLevel(targetWindow: Window): number {
|
||||
return WindowManager.INSTANCE.getZoomLevel(targetWindow);
|
||||
}
|
||||
export const onDidChangeZoomLevel = WindowManager.INSTANCE.onDidChangeZoomLevel;
|
||||
|
||||
/** The zoom scale for an index, e.g. 1, 1.2, 1.4 */
|
||||
export function getZoomFactor(targetWindow: Window): number {
|
||||
return WindowManager.INSTANCE.getZoomFactor(targetWindow);
|
||||
}
|
||||
export function setZoomFactor(zoomFactor: number, targetWindow: Window): void {
|
||||
WindowManager.INSTANCE.setZoomFactor(zoomFactor, targetWindow);
|
||||
}
|
||||
|
||||
export function setFullscreen(fullscreen: boolean, targetWindow: Window): void {
|
||||
WindowManager.INSTANCE.setFullscreen(fullscreen, targetWindow);
|
||||
}
|
||||
export function isFullscreen(targetWindow: Window): boolean {
|
||||
return WindowManager.INSTANCE.isFullscreen(targetWindow);
|
||||
}
|
||||
export const onDidChangeFullscreen = WindowManager.INSTANCE.onDidChangeFullscreen;
|
||||
|
||||
const userAgent = typeof navigator === 'object' ? navigator.userAgent : '';
|
||||
|
||||
export const isFirefox = (userAgent.indexOf('Firefox') >= 0);
|
||||
export const isWebKit = (userAgent.indexOf('AppleWebKit') >= 0);
|
||||
export const isChrome = (userAgent.indexOf('Chrome') >= 0);
|
||||
export const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0));
|
||||
export const isWebkitWebView = (!isChrome && !isSafari && isWebKit);
|
||||
export const isElectron = (userAgent.indexOf('Electron/') >= 0);
|
||||
export const isAndroid = (userAgent.indexOf('Android') >= 0);
|
||||
|
||||
let standalone = false;
|
||||
if (typeof mainWindow.matchMedia === 'function') {
|
||||
const standaloneMatchMedia = mainWindow.matchMedia('(display-mode: standalone) or (display-mode: window-controls-overlay)');
|
||||
const fullScreenMatchMedia = mainWindow.matchMedia('(display-mode: fullscreen)');
|
||||
standalone = standaloneMatchMedia.matches;
|
||||
addMatchMediaChangeListener(mainWindow, standaloneMatchMedia, ({ matches }) => {
|
||||
// entering fullscreen would change standaloneMatchMedia.matches to false
|
||||
// if standalone is true (running as PWA) and entering fullscreen, skip this change
|
||||
if (standalone && fullScreenMatchMedia.matches) {
|
||||
return;
|
||||
}
|
||||
// otherwise update standalone (browser to PWA or PWA to browser)
|
||||
standalone = matches;
|
||||
});
|
||||
}
|
||||
export function isStandalone(): boolean {
|
||||
return standalone;
|
||||
}
|
||||
|
||||
// Visible means that the feature is enabled, not necessarily being rendered
|
||||
// e.g. visible is true even in fullscreen mode where the controls are hidden
|
||||
// See docs at https://developer.mozilla.org/en-US/docs/Web/API/WindowControlsOverlay/visible
|
||||
export function isWCOEnabled(): boolean {
|
||||
return (navigator as any)?.windowControlsOverlay?.visible;
|
||||
}
|
||||
|
||||
// Returns the bounding rect of the titlebar area if it is supported and defined
|
||||
// See docs at https://developer.mozilla.org/en-US/docs/Web/API/WindowControlsOverlay/getTitlebarAreaRect
|
||||
export function getWCOBoundingRect(): DOMRect | undefined {
|
||||
return (navigator as any)?.windowControlsOverlay?.getTitlebarAreaRect();
|
||||
export function getZoomFactor(_targetWindow: Window): number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* An interface for a JavaScript object that
|
||||
* acts a dictionary. The keys are strings.
|
||||
*/
|
||||
export type IStringDictionary<V> = Record<string, V>;
|
||||
|
||||
/**
|
||||
* An interface for a JavaScript object that
|
||||
* acts a dictionary. The keys are numbers.
|
||||
*/
|
||||
export type INumberDictionary<V> = Record<number, V>;
|
||||
|
||||
/**
|
||||
* Groups the collection into a dictionary based on the provided
|
||||
* group function.
|
||||
*/
|
||||
export function groupBy<K extends string | number | symbol, V>(data: V[], groupFn: (element: V) => K): Record<K, V[]> {
|
||||
const result: Record<K, V[]> = Object.create(null);
|
||||
for (const element of data) {
|
||||
const key = groupFn(element);
|
||||
let target = result[key];
|
||||
if (!target) {
|
||||
target = result[key] = [];
|
||||
}
|
||||
target.push(element);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function diffSets<T>(before: Set<T>, after: Set<T>): { removed: T[], added: T[] } {
|
||||
const removed: T[] = [];
|
||||
const added: T[] = [];
|
||||
for (const element of before) {
|
||||
if (!after.has(element)) {
|
||||
removed.push(element);
|
||||
}
|
||||
}
|
||||
for (const element of after) {
|
||||
if (!before.has(element)) {
|
||||
added.push(element);
|
||||
}
|
||||
}
|
||||
return { removed, added };
|
||||
}
|
||||
|
||||
export function diffMaps<K, V>(before: Map<K, V>, after: Map<K, V>): { removed: V[], added: V[] } {
|
||||
const removed: V[] = [];
|
||||
const added: V[] = [];
|
||||
for (const [index, value] of before) {
|
||||
if (!after.has(index)) {
|
||||
removed.push(value);
|
||||
}
|
||||
}
|
||||
for (const [index, value] of after) {
|
||||
if (!before.has(index)) {
|
||||
added.push(value);
|
||||
}
|
||||
}
|
||||
return { removed, added };
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the intersection of two sets.
|
||||
*
|
||||
* @param setA - The first set.
|
||||
* @param setB - The second iterable.
|
||||
* @returns A new set containing the elements that are in both `setA` and `setB`.
|
||||
*/
|
||||
export function intersection<T>(setA: Set<T>, setB: Iterable<T>): Set<T> {
|
||||
const result = new Set<T>();
|
||||
for (const elem of setB) {
|
||||
if (setA.has(elem)) {
|
||||
result.add(elem);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export class SetWithKey<T> implements Set<T> {
|
||||
private _map = new Map<any, T>();
|
||||
|
||||
constructor(values: T[], private toKey: (t: T) => any) {
|
||||
for (const value of values) {
|
||||
this.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this._map.size;
|
||||
}
|
||||
|
||||
add(value: T): this {
|
||||
const key = this.toKey(value);
|
||||
this._map.set(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
delete(value: T): boolean {
|
||||
return this._map.delete(this.toKey(value));
|
||||
}
|
||||
|
||||
has(value: T): boolean {
|
||||
return this._map.has(this.toKey(value));
|
||||
}
|
||||
|
||||
*entries(): IterableIterator<[T, T]> {
|
||||
for (const entry of this._map.values()) {
|
||||
yield [entry, entry];
|
||||
}
|
||||
}
|
||||
|
||||
keys(): IterableIterator<T> {
|
||||
return this.values();
|
||||
}
|
||||
|
||||
*values(): IterableIterator<T> {
|
||||
for (const entry of this._map.values()) {
|
||||
yield entry;
|
||||
}
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this._map.clear();
|
||||
}
|
||||
|
||||
forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: any): void {
|
||||
this._map.forEach(entry => callbackfn.call(thisArg, entry, entry, this));
|
||||
}
|
||||
|
||||
[Symbol.iterator](): IterableIterator<T> {
|
||||
return this.values();
|
||||
}
|
||||
|
||||
[Symbol.toStringTag]: string = 'SetWithKey';
|
||||
}
|
||||
@@ -3,27 +3,6 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
function createDecorator(mapFn: (fn: Function, key: string) => Function): Function {
|
||||
return (target: any, key: string, descriptor: any) => {
|
||||
let fnKey: string | null = null;
|
||||
let fn: Function | null = null;
|
||||
|
||||
if (typeof descriptor.value === 'function') {
|
||||
fnKey = 'value';
|
||||
fn = descriptor.value;
|
||||
} else if (typeof descriptor.get === 'function') {
|
||||
fnKey = 'get';
|
||||
fn = descriptor.get;
|
||||
}
|
||||
|
||||
if (!fn) {
|
||||
throw new Error('not supported');
|
||||
}
|
||||
|
||||
descriptor[fnKey!] = mapFn(fn, key);
|
||||
};
|
||||
}
|
||||
|
||||
export function memoize(_target: any, key: string, descriptor: any) {
|
||||
let fnKey: string | null = null;
|
||||
let fn: Function | null = null;
|
||||
@@ -59,72 +38,3 @@ export function memoize(_target: any, key: string, descriptor: any) {
|
||||
};
|
||||
}
|
||||
|
||||
export interface IDebounceReducer<T> {
|
||||
(previousValue: T, ...args: any[]): T;
|
||||
}
|
||||
|
||||
export function debounce<T>(delay: number, reducer?: IDebounceReducer<T>, initialValueProvider?: () => T): Function {
|
||||
return createDecorator((fn, key) => {
|
||||
const timerKey = `$debounce$${key}`;
|
||||
const resultKey = `$debounce$result$${key}`;
|
||||
|
||||
return function (this: any, ...args: any[]) {
|
||||
if (!this[resultKey]) {
|
||||
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
|
||||
}
|
||||
|
||||
clearTimeout(this[timerKey]);
|
||||
|
||||
if (reducer) {
|
||||
this[resultKey] = reducer(this[resultKey], ...args);
|
||||
args = [this[resultKey]];
|
||||
}
|
||||
|
||||
this[timerKey] = setTimeout(() => {
|
||||
fn.apply(this, args);
|
||||
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
|
||||
}, delay);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function throttle<T>(delay: number, reducer?: IDebounceReducer<T>, initialValueProvider?: () => T): Function {
|
||||
return createDecorator((fn, key) => {
|
||||
const timerKey = `$throttle$timer$${key}`;
|
||||
const resultKey = `$throttle$result$${key}`;
|
||||
const lastRunKey = `$throttle$lastRun$${key}`;
|
||||
const pendingKey = `$throttle$pending$${key}`;
|
||||
|
||||
return function (this: any, ...args: any[]) {
|
||||
if (!this[resultKey]) {
|
||||
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
|
||||
}
|
||||
if (this[lastRunKey] === null || this[lastRunKey] === undefined) {
|
||||
this[lastRunKey] = -Number.MAX_VALUE;
|
||||
}
|
||||
|
||||
if (reducer) {
|
||||
this[resultKey] = reducer(this[resultKey], ...args);
|
||||
}
|
||||
|
||||
if (this[pendingKey]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextTime = this[lastRunKey] + delay;
|
||||
if (nextTime <= Date.now()) {
|
||||
this[lastRunKey] = Date.now();
|
||||
fn.apply(this, [this[resultKey]]);
|
||||
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
|
||||
} else {
|
||||
this[pendingKey] = true;
|
||||
this[timerKey] = setTimeout(() => {
|
||||
this[pendingKey] = false;
|
||||
this[lastRunKey] = Date.now();
|
||||
fn.apply(this, [this[resultKey]]);
|
||||
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
|
||||
}, nextTime - Date.now());
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { IntervalTimer } from './async';
|
||||
import { Emitter, Event } from './event';
|
||||
import { DisposableStore, IDisposable } from './lifecycle';
|
||||
import { IntervalTimer } from 'common/Async';
|
||||
import { Emitter, IEvent } from 'common/Event';
|
||||
import { DisposableStore, IDisposable } from 'common/Lifecycle';
|
||||
|
||||
export interface IRegisteredWindow {
|
||||
readonly window: Window;
|
||||
@@ -13,7 +13,7 @@ export interface IRegisteredWindow {
|
||||
}
|
||||
|
||||
const _onDidRegisterWindow = new Emitter<IRegisteredWindow>();
|
||||
export const onDidRegisterWindow: Event<IRegisteredWindow> = _onDidRegisterWindow.event;
|
||||
export const onDidRegisterWindow: IEvent<IRegisteredWindow> = _onDidRegisterWindow.event;
|
||||
|
||||
export function registerWindow(window: Window): IDisposable {
|
||||
const disposables = new DisposableStore();
|
||||
@@ -88,14 +88,7 @@ export const EventType = {
|
||||
WHEEL: 'wheel'
|
||||
} as const;
|
||||
|
||||
export interface IDomNodePagePosition {
|
||||
left: number;
|
||||
top: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export function getDomNodePagePosition(domNode: HTMLElement): IDomNodePagePosition {
|
||||
export function getDomNodePagePosition(domNode: HTMLElement): { left: number, top: number, width: number, height: number } {
|
||||
const bb = domNode.getBoundingClientRect();
|
||||
const win = getWindow(domNode);
|
||||
return {
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*
|
||||
* Minimal event utilities for scrollable components.
|
||||
*/
|
||||
|
||||
import { Disposable, DisposableStore, IDisposable, toDisposable } from './lifecycle';
|
||||
|
||||
export interface Event<T> {
|
||||
(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;
|
||||
}
|
||||
|
||||
export class Emitter<T> {
|
||||
private _listeners: { fn: (e: T) => any, thisArgs: any }[] = [];
|
||||
private _disposed = false;
|
||||
private _event: Event<T> | undefined;
|
||||
|
||||
public get event(): Event<T> {
|
||||
if (this._event) {
|
||||
return this._event;
|
||||
}
|
||||
this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {
|
||||
if (this._disposed) {
|
||||
return Disposable.None;
|
||||
}
|
||||
|
||||
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 || this._listeners.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (this._listeners.length === 1) {
|
||||
const { fn, thisArgs } = this._listeners[0];
|
||||
fn.call(thisArgs, event);
|
||||
return;
|
||||
}
|
||||
|
||||
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 const None: Event<any> = () => Disposable.None;
|
||||
|
||||
export function runAndSubscribe<T>(event: Event<T>, handler: (e: T) => void, initial: T): IDisposable;
|
||||
export function runAndSubscribe<T>(event: Event<T>, handler: (e: T | undefined) => void): IDisposable;
|
||||
export function runAndSubscribe<T>(event: Event<T>, handler: (e: T | undefined) => void, initial?: T): IDisposable {
|
||||
handler(initial);
|
||||
return event(e => handler(e));
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Given a function, returns a function that is only calling that function once.
|
||||
*/
|
||||
export function createSingleCallFunction<T extends Function>(this: unknown, fn: T, fnDidRunCallback?: () => void): T {
|
||||
const _this = this;
|
||||
let didCall = false;
|
||||
let result: unknown;
|
||||
|
||||
return function () {
|
||||
if (didCall) {
|
||||
return result;
|
||||
}
|
||||
|
||||
didCall = true;
|
||||
if (fnDidRunCallback) {
|
||||
try {
|
||||
result = fn.apply(_this, arguments);
|
||||
} finally {
|
||||
fnDidRunCallback();
|
||||
}
|
||||
} else {
|
||||
result = fn.apply(_this, arguments);
|
||||
}
|
||||
|
||||
return result;
|
||||
} as unknown as T;
|
||||
}
|
||||
@@ -4,21 +4,16 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from './dom';
|
||||
import { DisposableStore, IDisposable, toDisposable } from './lifecycle';
|
||||
import { DisposableStore, IDisposable, toDisposable } from 'common/Lifecycle';
|
||||
|
||||
export interface IPointerMoveCallback {
|
||||
(event: PointerEvent): void;
|
||||
}
|
||||
|
||||
export interface IOnStopCallback {
|
||||
(browserEvent?: PointerEvent | KeyboardEvent): void;
|
||||
}
|
||||
type PointerMoveCallback = (event: PointerEvent) => void;
|
||||
type OnStopCallback = (browserEvent?: PointerEvent | KeyboardEvent) => void;
|
||||
|
||||
export class GlobalPointerMoveMonitor implements IDisposable {
|
||||
|
||||
private readonly _hooks = new DisposableStore();
|
||||
private _pointerMoveCallback: IPointerMoveCallback | null = null;
|
||||
private _onStopCallback: IOnStopCallback | null = null;
|
||||
private _pointerMoveCallback: PointerMoveCallback | null = null;
|
||||
private _onStopCallback: OnStopCallback | null = null;
|
||||
|
||||
public dispose(): void {
|
||||
this.stopMonitoring(false);
|
||||
@@ -48,8 +43,8 @@ export class GlobalPointerMoveMonitor implements IDisposable {
|
||||
initialElement: Element,
|
||||
pointerId: number,
|
||||
initialButtons: number,
|
||||
pointerMoveCallback: IPointerMoveCallback,
|
||||
onStopCallback: IOnStopCallback
|
||||
pointerMoveCallback: PointerMoveCallback,
|
||||
onStopCallback: OnStopCallback
|
||||
): void {
|
||||
if (this.isMonitoring()) {
|
||||
this.stopMonitoring(false);
|
||||
|
||||
@@ -114,22 +114,3 @@ export class IframeUtils {
|
||||
/**
|
||||
* Returns a sha-256 composed of `parentOrigin` and `salt` converted to base 32
|
||||
*/
|
||||
export async function parentOriginHash(parentOrigin: string, salt: string): Promise<string> {
|
||||
// This same code is also inlined at `src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html`
|
||||
if (!crypto.subtle) {
|
||||
throw new Error(`'crypto.subtle' is not available so webviews will not work. This is likely because the editor is not running in a secure context (https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts).`);
|
||||
}
|
||||
|
||||
const strData = JSON.stringify({ parentOrigin, salt });
|
||||
const encoder = new TextEncoder();
|
||||
const arrData = encoder.encode(strData);
|
||||
const hash = await crypto.subtle.digest('sha-256', arrData);
|
||||
return sha256AsBase32(hash);
|
||||
}
|
||||
|
||||
function sha256AsBase32(bytes: ArrayBuffer): string {
|
||||
const array = Array.from(new Uint8Array(bytes));
|
||||
const hexArray = array.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
// sha256 has 256 bits, so we need at most ceil(lg(2^256-1)/lg(32)) = 52 chars to represent it in base 32
|
||||
return BigInt(`0x${hexArray}`).toString(32).padStart(52, '0');
|
||||
}
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export namespace Iterable {
|
||||
|
||||
export function is<T = any>(thing: any): thing is Iterable<T> {
|
||||
return thing && typeof thing === 'object' && typeof thing[Symbol.iterator] === 'function';
|
||||
}
|
||||
|
||||
const _empty: Iterable<any> = Object.freeze([]);
|
||||
export function empty<T = any>(): Iterable<T> {
|
||||
return _empty;
|
||||
}
|
||||
|
||||
export function* single<T>(element: T): Iterable<T> {
|
||||
yield element;
|
||||
}
|
||||
|
||||
export function wrap<T>(iterableOrElement: Iterable<T> | T): Iterable<T> {
|
||||
if (is(iterableOrElement)) {
|
||||
return iterableOrElement;
|
||||
}
|
||||
return single(iterableOrElement);
|
||||
|
||||
}
|
||||
|
||||
export function from<T>(iterable: Iterable<T> | undefined | null): Iterable<T> {
|
||||
return iterable || _empty;
|
||||
}
|
||||
|
||||
export function* reverse<T>(array: T[]): Iterable<T> {
|
||||
for (let i = array.length - 1; i >= 0; i--) {
|
||||
yield array[i];
|
||||
}
|
||||
}
|
||||
|
||||
export function isEmpty<T>(iterable: Iterable<T> | undefined | null): boolean {
|
||||
return !iterable || iterable[Symbol.iterator]().next().done === true;
|
||||
}
|
||||
|
||||
export function first<T>(iterable: Iterable<T>): T | undefined {
|
||||
return iterable[Symbol.iterator]().next().value;
|
||||
}
|
||||
|
||||
export function some<T>(iterable: Iterable<T>, predicate: (t: T, i: number) => unknown): boolean {
|
||||
let i = 0;
|
||||
for (const element of iterable) {
|
||||
if (predicate(element, i++)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function find<T, R extends T>(iterable: Iterable<T>, predicate: (t: T) => t is R): R | undefined;
|
||||
export function find<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): T | undefined;
|
||||
export function find<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): T | undefined {
|
||||
for (const element of iterable) {
|
||||
if (predicate(element)) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function filter<T, R extends T>(iterable: Iterable<T>, predicate: (t: T) => t is R): Iterable<R>;
|
||||
export function filter<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): Iterable<T>;
|
||||
export function* filter<T>(iterable: Iterable<T>, predicate: (t: T) => boolean): Iterable<T> {
|
||||
for (const element of iterable) {
|
||||
if (predicate(element)) {
|
||||
yield element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function* map<T, R>(iterable: Iterable<T>, fn: (t: T, index: number) => R): Iterable<R> {
|
||||
let index = 0;
|
||||
for (const element of iterable) {
|
||||
yield fn(element, index++);
|
||||
}
|
||||
}
|
||||
|
||||
export function* flatMap<T, R>(iterable: Iterable<T>, fn: (t: T, index: number) => Iterable<R>): Iterable<R> {
|
||||
let index = 0;
|
||||
for (const element of iterable) {
|
||||
yield* fn(element, index++);
|
||||
}
|
||||
}
|
||||
|
||||
export function* concat<T>(...iterables: Iterable<T>[]): Iterable<T> {
|
||||
for (const iterable of iterables) {
|
||||
yield* iterable;
|
||||
}
|
||||
}
|
||||
|
||||
export function reduce<T, R>(iterable: Iterable<T>, reducer: (previousValue: R, currentValue: T) => R, initialValue: R): R {
|
||||
let value = initialValue;
|
||||
for (const element of iterable) {
|
||||
value = reducer(value, element);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterable slice of the array, with the same semantics as `array.slice()`.
|
||||
*/
|
||||
export function* slice<T>(arr: ReadonlyArray<T>, from: number, to = arr.length): Iterable<T> {
|
||||
if (from < 0) {
|
||||
from += arr.length;
|
||||
}
|
||||
|
||||
if (to < 0) {
|
||||
to += arr.length;
|
||||
} else if (to > arr.length) {
|
||||
to = arr.length;
|
||||
}
|
||||
|
||||
for (; from < to; from++) {
|
||||
yield arr[from];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes `atMost` elements from iterable and returns the consumed elements,
|
||||
* and an iterable for the rest of the elements.
|
||||
*/
|
||||
export function consume<T>(iterable: Iterable<T>, atMost: number = Number.POSITIVE_INFINITY): [T[], Iterable<T>] {
|
||||
const consumed: T[] = [];
|
||||
|
||||
if (atMost === 0) {
|
||||
return [consumed, iterable];
|
||||
}
|
||||
|
||||
const iterator = iterable[Symbol.iterator]();
|
||||
|
||||
for (let i = 0; i < atMost; i++) {
|
||||
const next = iterator.next();
|
||||
|
||||
if (next.done) {
|
||||
return [consumed, Iterable.empty()];
|
||||
}
|
||||
|
||||
consumed.push(next.value);
|
||||
}
|
||||
|
||||
return [consumed, { [Symbol.iterator]() { return iterator; } }];
|
||||
}
|
||||
|
||||
export async function asyncToArray<T>(iterable: AsyncIterable<T>): Promise<T[]> {
|
||||
const result: T[] = [];
|
||||
for await (const item of iterable) {
|
||||
result.push(item);
|
||||
}
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*
|
||||
* Minimal lifecycle utilities for scrollable components.
|
||||
*/
|
||||
|
||||
export interface IDisposable {
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export function toDisposable(fn: () => void): IDisposable {
|
||||
return { dispose: fn };
|
||||
}
|
||||
|
||||
export function dispose<T extends IDisposable>(disposable: T): T;
|
||||
export function dispose<T extends IDisposable>(disposable: T | undefined): T | undefined;
|
||||
export function dispose<T extends IDisposable>(disposables: T[]): T[];
|
||||
export function dispose<T extends IDisposable>(arg: T | T[] | undefined): T | T[] | undefined {
|
||||
if (!arg) {
|
||||
return arg;
|
||||
}
|
||||
if (Array.isArray(arg)) {
|
||||
for (const d of arg) {
|
||||
d.dispose();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
arg.dispose();
|
||||
return arg;
|
||||
}
|
||||
|
||||
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 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();
|
||||
}
|
||||
|
||||
public clear(): void {
|
||||
for (const d of this._disposables) {
|
||||
d.dispose();
|
||||
}
|
||||
this._disposables.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class Disposable implements IDisposable {
|
||||
static readonly None: IDisposable = Object.freeze({ dispose() { } });
|
||||
|
||||
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 function markAsSingleton<T extends IDisposable>(singleton: T): T {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
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,202 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export function getOrSet<K, V>(map: Map<K, V>, key: K, value: V): V {
|
||||
let result = map.get(key);
|
||||
if (result === undefined) {
|
||||
result = value;
|
||||
map.set(key, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function mapToString<K, V>(map: Map<K, V>): string {
|
||||
const entries: string[] = [];
|
||||
map.forEach((value, key) => {
|
||||
entries.push(`${key} => ${value}`);
|
||||
});
|
||||
|
||||
return `Map(${map.size}) {${entries.join(', ')}}`;
|
||||
}
|
||||
|
||||
export function setToString<K>(set: Set<K>): string {
|
||||
const entries: K[] = [];
|
||||
set.forEach(value => {
|
||||
entries.push(value);
|
||||
});
|
||||
|
||||
return `Set(${set.size}) {${entries.join(', ')}}`;
|
||||
}
|
||||
|
||||
export const enum Touch {
|
||||
None = 0,
|
||||
AsOld = 1,
|
||||
AsNew = 2
|
||||
}
|
||||
|
||||
export class CounterSet<T> {
|
||||
|
||||
private map = new Map<T, number>();
|
||||
|
||||
add(value: T): CounterSet<T> {
|
||||
this.map.set(value, (this.map.get(value) || 0) + 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
delete(value: T): boolean {
|
||||
let counter = this.map.get(value) || 0;
|
||||
|
||||
if (counter === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
counter--;
|
||||
|
||||
if (counter === 0) {
|
||||
this.map.delete(value);
|
||||
} else {
|
||||
this.map.set(value, counter);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
has(value: T): boolean {
|
||||
return this.map.has(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A map that allows access both by keys and values.
|
||||
* **NOTE**: values need to be unique.
|
||||
*/
|
||||
export class BidirectionalMap<K, V> {
|
||||
|
||||
private readonly _m1 = new Map<K, V>();
|
||||
private readonly _m2 = new Map<V, K>();
|
||||
|
||||
constructor(entries?: ReadonlyArray<readonly [K, V]>) {
|
||||
if (entries) {
|
||||
for (const [key, value] of entries) {
|
||||
this.set(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this._m1.clear();
|
||||
this._m2.clear();
|
||||
}
|
||||
|
||||
set(key: K, value: V): void {
|
||||
this._m1.set(key, value);
|
||||
this._m2.set(value, key);
|
||||
}
|
||||
|
||||
get(key: K): V | undefined {
|
||||
return this._m1.get(key);
|
||||
}
|
||||
|
||||
getKey(value: V): K | undefined {
|
||||
return this._m2.get(value);
|
||||
}
|
||||
|
||||
delete(key: K): boolean {
|
||||
const value = this._m1.get(key);
|
||||
if (value === undefined) {
|
||||
return false;
|
||||
}
|
||||
this._m1.delete(key);
|
||||
this._m2.delete(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
forEach(callbackfn: (value: V, key: K, map: BidirectionalMap<K, V>) => void, thisArg?: any): void {
|
||||
this._m1.forEach((value, key) => {
|
||||
callbackfn.call(thisArg, value, key, this);
|
||||
});
|
||||
}
|
||||
|
||||
keys(): IterableIterator<K> {
|
||||
return this._m1.keys();
|
||||
}
|
||||
|
||||
values(): IterableIterator<V> {
|
||||
return this._m1.values();
|
||||
}
|
||||
}
|
||||
|
||||
export class SetMap<K, V> {
|
||||
|
||||
private map = new Map<K, Set<V>>();
|
||||
|
||||
add(key: K, value: V): void {
|
||||
let values = this.map.get(key);
|
||||
|
||||
if (!values) {
|
||||
values = new Set<V>();
|
||||
this.map.set(key, values);
|
||||
}
|
||||
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
delete(key: K, value: V): void {
|
||||
const values = this.map.get(key);
|
||||
|
||||
if (!values) {
|
||||
return;
|
||||
}
|
||||
|
||||
values.delete(value);
|
||||
|
||||
if (values.size === 0) {
|
||||
this.map.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
forEach(key: K, fn: (value: V) => void): void {
|
||||
const values = this.map.get(key);
|
||||
|
||||
if (!values) {
|
||||
return;
|
||||
}
|
||||
|
||||
values.forEach(fn);
|
||||
}
|
||||
|
||||
get(key: K): ReadonlySet<V> {
|
||||
const values = this.map.get(key);
|
||||
if (!values) {
|
||||
return new Set<V>();
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
export function mapsStrictEqualIgnoreOrder(a: Map<unknown, unknown>, b: Map<unknown, unknown>): boolean {
|
||||
if (a === b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a.size !== b.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const [key, value] of a) {
|
||||
if (!b.has(key) || b.get(key) !== value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const [key] of b) {
|
||||
if (!a.has(key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as browser from './browser';
|
||||
import { IframeUtils } from './iframe';
|
||||
import * as platform from './platform';
|
||||
import * as platform from 'common/Platform';
|
||||
|
||||
export interface IMouseEvent {
|
||||
readonly browserEvent: MouseEvent;
|
||||
@@ -148,7 +148,7 @@ export class StandardWheelEvent {
|
||||
const ev = e as unknown as WheelEvent;
|
||||
|
||||
if (ev.deltaMode === ev.DOM_DELTA_LINE) {
|
||||
if (browser.isFirefox && !platform.isMacintosh) {
|
||||
if (browser.isFirefox && !platform.isMac) {
|
||||
this.deltaY = -e.deltaY / 3;
|
||||
} else {
|
||||
this.deltaY = -e.deltaY;
|
||||
@@ -172,7 +172,7 @@ export class StandardWheelEvent {
|
||||
const ev = e as unknown as WheelEvent;
|
||||
|
||||
if (ev.deltaMode === ev.DOM_DELTA_LINE) {
|
||||
if (browser.isFirefox && !platform.isMacintosh) {
|
||||
if (browser.isFirefox && !platform.isMac) {
|
||||
this.deltaX = -e.deltaX / 3;
|
||||
} else {
|
||||
this.deltaX = -e.deltaX;
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export interface ILocalizeInfo {
|
||||
key: string;
|
||||
comment: string[];
|
||||
}
|
||||
|
||||
export function localize(info: ILocalizeInfo | string, message: string, ...args: (string | number | boolean | undefined | null)[]): string {
|
||||
return message;
|
||||
}
|
||||
|
||||
export interface INLSLanguagePackConfiguration {
|
||||
|
||||
/**
|
||||
* The path to the translations config file that contains pointers to
|
||||
* all message bundles for `main` and extensions.
|
||||
*/
|
||||
readonly translationsConfigFile: string;
|
||||
|
||||
/**
|
||||
* The path to the file containing the translations for this language
|
||||
* pack as flat string array.
|
||||
*/
|
||||
readonly messagesFile: string;
|
||||
|
||||
/**
|
||||
* The path to the file that can be used to signal a corrupt language
|
||||
* pack, for example when reading the `messagesFile` fails. This will
|
||||
* instruct the application to re-create the cache on next startup.
|
||||
*/
|
||||
readonly corruptMarkerFile: string;
|
||||
}
|
||||
|
||||
export interface INLSConfiguration {
|
||||
|
||||
/**
|
||||
* Locale as defined in `argv.json` or `app.getLocale()`.
|
||||
*/
|
||||
readonly userLocale: string;
|
||||
|
||||
/**
|
||||
* Locale as defined by the OS (e.g. `app.getPreferredSystemLanguages()`).
|
||||
*/
|
||||
readonly osLocale: string;
|
||||
|
||||
/**
|
||||
* The actual language of the UI that ends up being used considering `userLocale`
|
||||
* and `osLocale`.
|
||||
*/
|
||||
readonly resolvedLanguage: string;
|
||||
|
||||
/**
|
||||
* Defined if a language pack is used that is not the
|
||||
* default english language pack. This requires a language
|
||||
* pack to be installed as extension.
|
||||
*/
|
||||
readonly languagePack?: INLSLanguagePackConfiguration;
|
||||
|
||||
/**
|
||||
* The path to the file containing the default english messages
|
||||
* as flat string array. The file is only present in built
|
||||
* versions of the application.
|
||||
*/
|
||||
readonly defaultMessagesFile: string;
|
||||
|
||||
/**
|
||||
* Below properties are deprecated and only there to continue support
|
||||
* for `vscode-nls` module that depends on them.
|
||||
* Refs https://github.com/microsoft/vscode-nls/blob/main/src/node/main.ts#L36-L46
|
||||
*/
|
||||
/** @deprecated */
|
||||
readonly locale: string;
|
||||
/** @deprecated */
|
||||
readonly availableLanguages: Record<string, string>;
|
||||
/** @deprecated */
|
||||
readonly _languagePackSupport?: boolean;
|
||||
/** @deprecated */
|
||||
readonly _languagePackId?: string;
|
||||
/** @deprecated */
|
||||
readonly _translationsConfigFile?: string;
|
||||
/** @deprecated */
|
||||
readonly _cacheRoot?: string;
|
||||
/** @deprecated */
|
||||
readonly _resolvedLanguagePackCoreLocation?: string;
|
||||
/** @deprecated */
|
||||
readonly _corruptedFile?: string;
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export function clamp(value: number, min: number, max: number): number {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
|
||||
export function rot(index: number, modulo: number): number {
|
||||
return (modulo + (index % modulo)) % modulo;
|
||||
}
|
||||
|
||||
export class Counter {
|
||||
private _next = 0;
|
||||
|
||||
getNext(): number {
|
||||
return this._next++;
|
||||
}
|
||||
}
|
||||
|
||||
export class MovingAverage {
|
||||
|
||||
private _n = 1;
|
||||
private _val = 0;
|
||||
|
||||
update(value: number): number {
|
||||
this._val = this._val + (value - this._val) / this._n;
|
||||
this._n += 1;
|
||||
return this._val;
|
||||
}
|
||||
|
||||
get value(): number {
|
||||
return this._val;
|
||||
}
|
||||
}
|
||||
|
||||
export class SlidingWindowAverage {
|
||||
|
||||
private _n: number = 0;
|
||||
private _val = 0;
|
||||
|
||||
private readonly _values: number[] = [];
|
||||
private _index: number = 0;
|
||||
private _sum = 0;
|
||||
|
||||
constructor(size: number) {
|
||||
this._values = new Array(size);
|
||||
this._values.fill(0, 0, size);
|
||||
}
|
||||
|
||||
update(value: number): number {
|
||||
const oldValue = this._values[this._index];
|
||||
this._values[this._index] = value;
|
||||
this._index = (this._index + 1) % this._values.length;
|
||||
|
||||
this._sum -= oldValue;
|
||||
this._sum += value;
|
||||
|
||||
if (this._n < this._values.length) {
|
||||
this._n += 1;
|
||||
}
|
||||
|
||||
this._val = this._sum / this._n;
|
||||
return this._val;
|
||||
}
|
||||
|
||||
get value(): number {
|
||||
return this._val;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns whether the point is within the triangle formed by the following 6 x/y point pairs */
|
||||
export function isPointWithinTriangle(
|
||||
x: number, y: number,
|
||||
ax: number, ay: number,
|
||||
bx: number, by: number,
|
||||
cx: number, cy: number
|
||||
) {
|
||||
const v0x = cx - ax;
|
||||
const v0y = cy - ay;
|
||||
const v1x = bx - ax;
|
||||
const v1y = by - ay;
|
||||
const v2x = x - ax;
|
||||
const v2y = y - ay;
|
||||
|
||||
const dot00 = v0x * v0x + v0y * v0y;
|
||||
const dot01 = v0x * v1x + v0y * v1y;
|
||||
const dot02 = v0x * v2x + v0y * v2y;
|
||||
const dot11 = v1x * v1x + v1y * v1y;
|
||||
const dot12 = v1x * v2x + v1y * v2y;
|
||||
|
||||
const invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
|
||||
const u = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
||||
const v = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
||||
|
||||
return u >= 0 && v >= 0 && u + v < 1;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
const userAgent = typeof navigator === 'object' ? navigator.userAgent : '';
|
||||
const platform = typeof navigator === 'object' ? navigator.platform : '';
|
||||
|
||||
export const isMacintosh = platform.indexOf('Mac') >= 0;
|
||||
export const isWindows = platform.indexOf('Win') >= 0;
|
||||
export const isLinux = platform.indexOf('Linux') >= 0;
|
||||
export const isIOS = /iPad|iPhone|iPod/.test(userAgent);
|
||||
@@ -3,8 +3,8 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter, Event } from './event';
|
||||
import { Disposable, IDisposable } from './lifecycle';
|
||||
import { Emitter, IEvent } from 'common/Event';
|
||||
import { Disposable, IDisposable } from 'common/Lifecycle';
|
||||
|
||||
export const enum ScrollbarVisibility {
|
||||
Auto = 1,
|
||||
@@ -223,7 +223,7 @@ export class Scrollable extends Disposable {
|
||||
private _smoothScrolling: SmoothScrollingOperation | null;
|
||||
|
||||
private _onScroll = this._register(new Emitter<ScrollEvent>());
|
||||
public readonly onScroll: Event<ScrollEvent> = this._onScroll.event;
|
||||
public readonly onScroll: IEvent<ScrollEvent> = this._onScroll.event;
|
||||
|
||||
constructor(options: IScrollableOptions) {
|
||||
super();
|
||||
|
||||
@@ -12,10 +12,10 @@ import { HorizontalScrollbar } from './horizontalScrollbar';
|
||||
import { ScrollableElementChangeOptions, ScrollableElementCreationOptions, ScrollableElementResolvedOptions } from './scrollableElementOptions';
|
||||
import { VerticalScrollbar } from './verticalScrollbar';
|
||||
import { Widget } from './widget';
|
||||
import { TimeoutTimer } from './async';
|
||||
import { Emitter, Event } from './event';
|
||||
import { IDisposable, dispose } from './lifecycle';
|
||||
import * as platform from './platform';
|
||||
import { TimeoutTimer } from 'common/Async';
|
||||
import { Emitter, IEvent } from 'common/Event';
|
||||
import { IDisposable, dispose } from 'common/Lifecycle';
|
||||
import * as platform from 'common/Platform';
|
||||
import { INewScrollDimensions, INewScrollPosition, IScrollDimensions, IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from './scrollable';
|
||||
// import 'vs/css!./media/scrollbars';
|
||||
|
||||
@@ -180,10 +180,10 @@ export abstract class AbstractScrollableElement extends Widget {
|
||||
private _revealOnScroll: boolean;
|
||||
|
||||
private readonly _onScroll = this._register(new Emitter<ScrollEvent>());
|
||||
public readonly onScroll: Event<ScrollEvent> = this._onScroll.event;
|
||||
public readonly onScroll: IEvent<ScrollEvent> = this._onScroll.event;
|
||||
|
||||
private readonly _onWillScroll = this._register(new Emitter<ScrollEvent>());
|
||||
public readonly onWillScroll: Event<ScrollEvent> = this._onWillScroll.event;
|
||||
public readonly onWillScroll: IEvent<ScrollEvent> = this._onWillScroll.event;
|
||||
|
||||
public get options(): Readonly<ScrollableElementResolvedOptions> {
|
||||
return this._options;
|
||||
@@ -281,7 +281,7 @@ export abstract class AbstractScrollableElement extends Widget {
|
||||
|
||||
public updateClassName(newClassName: string): void {
|
||||
this._options.className = newClassName;
|
||||
if (platform.isMacintosh) {
|
||||
if (platform.isMac) {
|
||||
this._options.className += ' mac';
|
||||
}
|
||||
this._domNode.className = 'xterm-scrollable-element ' + this._options.className;
|
||||
@@ -382,7 +382,7 @@ export abstract class AbstractScrollableElement extends Widget {
|
||||
[deltaY, deltaX] = [deltaX, deltaY];
|
||||
}
|
||||
|
||||
const shiftConvert = !platform.isMacintosh && e.browserEvent && e.browserEvent.shiftKey;
|
||||
const shiftConvert = !platform.isMac && e.browserEvent && e.browserEvent.shiftKey;
|
||||
if ((this._options.scrollYToX || shiftConvert) && !deltaX) {
|
||||
deltaX = deltaY;
|
||||
deltaY = 0;
|
||||
@@ -575,54 +575,6 @@ export class SmoothScrollableElement extends AbstractScrollableElement {
|
||||
|
||||
}
|
||||
|
||||
export class DomScrollableElement extends AbstractScrollableElement {
|
||||
|
||||
private _element: HTMLElement;
|
||||
|
||||
constructor(element: HTMLElement, options: ScrollableElementCreationOptions) {
|
||||
options = options || {};
|
||||
options.mouseWheelSmoothScroll = false;
|
||||
const scrollable = new Scrollable({
|
||||
forceIntegerValues: false,
|
||||
smoothScrollDuration: 0,
|
||||
scheduleAtNextAnimationFrame: (callback) => dom.scheduleAtNextAnimationFrame(dom.getWindow(element), callback)
|
||||
});
|
||||
super(element, options, scrollable);
|
||||
this._register(scrollable);
|
||||
this._element = element;
|
||||
this._register(this.onScroll((e) => {
|
||||
if (e.scrollTopChanged) {
|
||||
this._element.scrollTop = e.scrollTop;
|
||||
}
|
||||
if (e.scrollLeftChanged) {
|
||||
this._element.scrollLeft = e.scrollLeft;
|
||||
}
|
||||
}));
|
||||
this.scanDomNode();
|
||||
}
|
||||
|
||||
public setScrollPosition(update: INewScrollPosition): void {
|
||||
this._scrollable.setScrollPositionNow(update);
|
||||
}
|
||||
|
||||
public getScrollPosition(): IScrollPosition {
|
||||
return this._scrollable.getCurrentScrollPosition();
|
||||
}
|
||||
|
||||
public scanDomNode(): void {
|
||||
this.setScrollDimensions({
|
||||
width: this._element.clientWidth,
|
||||
scrollWidth: this._element.scrollWidth,
|
||||
height: this._element.clientHeight,
|
||||
scrollHeight: this._element.scrollHeight
|
||||
});
|
||||
this.setScrollPosition({
|
||||
scrollLeft: this._element.scrollLeft,
|
||||
scrollTop: this._element.scrollTop,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function resolveOptions(opts: ScrollableElementCreationOptions): ScrollableElementResolvedOptions {
|
||||
const result: ScrollableElementResolvedOptions = {
|
||||
lazyRender: (typeof opts.lazyRender !== 'undefined' ? opts.lazyRender : false),
|
||||
@@ -657,7 +609,7 @@ function resolveOptions(opts: ScrollableElementCreationOptions): ScrollableEleme
|
||||
result.horizontalSliderSize = (typeof opts.horizontalSliderSize !== 'undefined' ? opts.horizontalSliderSize : result.horizontalScrollbarSize);
|
||||
result.verticalSliderSize = (typeof opts.verticalSliderSize !== 'undefined' ? opts.verticalSliderSize : result.verticalScrollbarSize);
|
||||
|
||||
if (platform.isMacintosh) {
|
||||
if (platform.isMac) {
|
||||
result.className += ' mac';
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user