Merge remote-tracking branch 'upstream/master' into scoped_package

This commit is contained in:
Daniel Imms
2023-11-01 06:46:14 -07:00
21 changed files with 287 additions and 160 deletions
+1 -1
View File
@@ -88,7 +88,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
this._updateCursorBlink();
this.register(_optionsService.onOptionChange(() => this._handleOptionsChanged()));
this._canvas = document.createElement('canvas');
this._canvas = this._coreBrowserService.mainDocument.createElement('canvas');
const contextAttributes = {
antialias: false,
@@ -38,7 +38,7 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
protected readonly _themeService: IThemeService
) {
super();
this._canvas = document.createElement('canvas');
this._canvas = this._coreBrowserService.mainDocument.createElement('canvas');
this._canvas.classList.add(`xterm-${id}-layer`);
this._canvas.style.zIndex = zIndex.toString();
this._initCanvas();
@@ -59,7 +59,7 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
) {
super();
this._cellColorResolver = new CellColorResolver(this._terminal, this._selectionModel, this._decorationService, this._coreBrowserService, this._themeService);
this._canvas = document.createElement('canvas');
this._canvas = this._coreBrowserService.mainDocument.createElement('canvas');
this._canvas.classList.add(`xterm-${id}-layer`);
this._canvas.style.zIndex = zIndex.toString();
this._initCanvas();
+20 -2
View File
@@ -134,9 +134,10 @@ export class SearchAddon extends Disposable implements ITerminalAddon {
if (!this._terminal) {
throw new Error('Cannot use addon until it has been loaded');
}
const didOptionsChanged = this._lastSearchOptions ? this._didOptionsChange(this._lastSearchOptions, searchOptions) : true;
this._lastSearchOptions = searchOptions;
if (searchOptions?.decorations) {
if (this._cachedSearchTerm === undefined || term !== this._cachedSearchTerm) {
if (this._cachedSearchTerm === undefined || term !== this._cachedSearchTerm || didOptionsChanged) {
this._highlightAllMatches(term, searchOptions);
}
}
@@ -302,9 +303,10 @@ export class SearchAddon extends Disposable implements ITerminalAddon {
if (!this._terminal) {
throw new Error('Cannot use addon until it has been loaded');
}
const didOptionsChanged = this._lastSearchOptions ? this._didOptionsChange(this._lastSearchOptions, searchOptions) : true;
this._lastSearchOptions = searchOptions;
if (searchOptions?.decorations) {
if (this._cachedSearchTerm === undefined || term !== this._cachedSearchTerm) {
if (this._cachedSearchTerm === undefined || term !== this._cachedSearchTerm || didOptionsChanged) {
this._highlightAllMatches(term, searchOptions);
}
}
@@ -316,6 +318,22 @@ export class SearchAddon extends Disposable implements ITerminalAddon {
return found;
}
private _didOptionsChange(lastSearchOptions: ISearchOptions, searchOptions?: ISearchOptions): boolean {
if (!searchOptions) {
return false;
}
if (lastSearchOptions.caseSensitive !== searchOptions.caseSensitive) {
return true;
}
if (lastSearchOptions.regex !== searchOptions.regex) {
return true;
}
if (lastSearchOptions.wholeWord !== searchOptions.wholeWord) {
return true;
}
return false;
}
private _fireResults(searchOptions?: ISearchOptions): void {
if (searchOptions?.decorations) {
let resultIndex = -1;
@@ -8,9 +8,7 @@ The file `src/UnicodeProperties.ts` is generated and depends on the Unicode vers
### Install
```bash
npm install --save xterm-addon-unicode-graphemes
```
This addon is not yet published to npm
### Usage
+9 -16
View File
@@ -7,10 +7,9 @@ import * as Strings from 'browser/LocalizableStrings';
import { ITerminal, IRenderDebouncer } from 'browser/Types';
import { TimeBasedDebouncer } from 'browser/TimeBasedDebouncer';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { ScreenDprMonitor } from 'browser/ScreenDprMonitor';
import { IRenderService } from 'browser/services/Services';
import { addDisposableDomListener } from 'browser/Lifecycle';
import { ICoreBrowserService, IRenderService } from 'browser/services/Services';
import { IBuffer } from 'common/buffer/Types';
import { IInstantiationService } from 'common/services/Services';
const MAX_ROWS_TO_READ = 20;
@@ -29,8 +28,6 @@ export class AccessibilityManager extends Disposable {
private _liveRegionLineCount: number = 0;
private _liveRegionDebouncer: IRenderDebouncer;
private _screenDprMonitor: ScreenDprMonitor;
private _topBoundaryFocusListener: (e: FocusEvent) => void;
private _bottomBoundaryFocusListener: (e: FocusEvent) => void;
@@ -49,13 +46,15 @@ export class AccessibilityManager extends Disposable {
constructor(
private readonly _terminal: ITerminal,
@IInstantiationService instantiationService: IInstantiationService,
@ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService,
@IRenderService private readonly _renderService: IRenderService
) {
super();
this._accessibilityContainer = document.createElement('div');
this._accessibilityContainer = this._coreBrowserService.mainDocument.createElement('div');
this._accessibilityContainer.classList.add('xterm-accessibility');
this._rowContainer = document.createElement('div');
this._rowContainer = this._coreBrowserService.mainDocument.createElement('div');
this._rowContainer.setAttribute('role', 'list');
this._rowContainer.classList.add('xterm-accessibility-tree');
this._rowElements = [];
@@ -72,7 +71,7 @@ export class AccessibilityManager extends Disposable {
this._refreshRowsDimensions();
this._accessibilityContainer.appendChild(this._rowContainer);
this._liveRegion = document.createElement('div');
this._liveRegion = this._coreBrowserService.mainDocument.createElement('div');
this._liveRegion.classList.add('live-region');
this._liveRegion.setAttribute('aria-live', 'assertive');
this._accessibilityContainer.appendChild(this._liveRegion);
@@ -93,13 +92,7 @@ export class AccessibilityManager extends Disposable {
this.register(this._terminal.onKey(e => this._handleKey(e.key)));
this.register(this._terminal.onBlur(() => this._clearLiveRegion()));
this.register(this._renderService.onDimensionsChange(() => this._refreshRowsDimensions()));
this._screenDprMonitor = new ScreenDprMonitor(window);
this.register(this._screenDprMonitor);
this._screenDprMonitor.setListener(() => this._refreshRowsDimensions());
// This shouldn't be needed on modern browsers but is present in case the
// media query that drives the ScreenDprMonitor isn't supported
this.register(addDisposableDomListener(window, 'resize', () => this._refreshRowsDimensions()));
this.register(this._coreBrowserService.onDprChange(() => this._refreshRowsDimensions()));
this._refreshRows();
this.register(toDisposable(() => {
@@ -261,7 +254,7 @@ export class AccessibilityManager extends Disposable {
}
private _createAccessibilityTreeNode(): HTMLElement {
const element = document.createElement('div');
const element = this._coreBrowserService.mainDocument.createElement('div');
element.setAttribute('role', 'listitem');
element.tabIndex = -1;
this._refreshRowDimensions(element);
-72
View File
@@ -1,72 +0,0 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { Disposable, toDisposable } from 'common/Lifecycle';
export type ScreenDprListener = (newDevicePixelRatio?: number, oldDevicePixelRatio?: number) => void;
/**
* The screen device pixel ratio monitor allows listening for when the
* window.devicePixelRatio value changes. This is done not with polling but with
* the use of window.matchMedia to watch media queries. When the event fires,
* the listener will be reattached using a different media query to ensure that
* any further changes will register.
*
* The listener should fire on both window zoom changes and switching to a
* monitor with a different DPI.
*/
export class ScreenDprMonitor extends Disposable {
private _currentDevicePixelRatio: number;
private _outerListener: ((this: MediaQueryList, ev: MediaQueryListEvent) => any) | undefined;
private _listener: ScreenDprListener | undefined;
private _resolutionMediaMatchList: MediaQueryList | undefined;
constructor(private _parentWindow: Window) {
super();
this._currentDevicePixelRatio = this._parentWindow.devicePixelRatio;
this.register(toDisposable(() => {
this.clearListener();
}));
}
public setListener(listener: ScreenDprListener): void {
if (this._listener) {
this.clearListener();
}
this._listener = listener;
this._outerListener = () => {
if (!this._listener) {
return;
}
this._listener(this._parentWindow.devicePixelRatio, this._currentDevicePixelRatio);
this._updateDpr();
};
this._updateDpr();
}
private _updateDpr(): void {
if (!this._outerListener) {
return;
}
// Clear listeners for old DPR
this._resolutionMediaMatchList?.removeListener(this._outerListener);
// Add listeners for new DPR
this._currentDevicePixelRatio = this._parentWindow.devicePixelRatio;
this._resolutionMediaMatchList = this._parentWindow.matchMedia(`screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)`);
this._resolutionMediaMatchList.addListener(this._outerListener);
}
public clearListener(): void {
if (!this._resolutionMediaMatchList || !this._listener || !this._outerListener) {
return;
}
this._resolutionMediaMatchList.removeListener(this._outerListener);
this._resolutionMediaMatchList = undefined;
this._listener = undefined;
this._outerListener = undefined;
}
}
+23 -12
View File
@@ -58,9 +58,6 @@ import { IDecoration, IDecorationOptions, IDisposable, ILinkProvider, IMarker }
import { WindowsOptionsReportType } from '../common/InputHandler';
import { AccessibilityManager } from './AccessibilityManager';
// Let it work inside Node.js for automated testing purposes.
const document: Document = (typeof window !== 'undefined') ? window.document : null as any;
export class Terminal extends CoreTerminal implements ITerminal {
public textarea: HTMLTextAreaElement | undefined;
public element: HTMLElement | undefined;
@@ -397,7 +394,16 @@ export class Terminal extends CoreTerminal implements ITerminal {
this._logService.debug('Terminal.open was called on an element that was not attached to the DOM');
}
this._document = parent.ownerDocument!;
// If the terminal is already opened
if (this.element?.ownerDocument.defaultView && this._coreBrowserService) {
// Adjust the window if needed
if (this.element.ownerDocument.defaultView !== this._coreBrowserService.window) {
this._coreBrowserService.window = this.element.ownerDocument.defaultView;
}
return;
}
this._document = parent.ownerDocument;
if (this.options.documentOverride && this.options.documentOverride instanceof Document) {
this._document = this.optionsService.rawOptions.documentOverride as Document;
}
@@ -411,25 +417,25 @@ export class Terminal extends CoreTerminal implements ITerminal {
// Performance: Use a document fragment to build the terminal
// viewport and helper elements detached from the DOM
const fragment = document.createDocumentFragment();
this._viewportElement = document.createElement('div');
const fragment = this._document.createDocumentFragment();
this._viewportElement = this._document.createElement('div');
this._viewportElement.classList.add('xterm-viewport');
fragment.appendChild(this._viewportElement);
this._viewportScrollArea = document.createElement('div');
this._viewportScrollArea = this._document.createElement('div');
this._viewportScrollArea.classList.add('xterm-scroll-area');
this._viewportElement.appendChild(this._viewportScrollArea);
this.screenElement = document.createElement('div');
this.screenElement = this._document.createElement('div');
this.screenElement.classList.add('xterm-screen');
// Create the container that will hold helpers like the textarea for
// capturing DOM Events. Then produce the helpers.
this._helperContainer = document.createElement('div');
this._helperContainer = this._document.createElement('div');
this._helperContainer.classList.add('xterm-helpers');
this.screenElement.appendChild(this._helperContainer);
fragment.appendChild(this.screenElement);
this.textarea = document.createElement('textarea');
this.textarea = this._document.createElement('textarea');
this.textarea.classList.add('xterm-helper-textarea');
this.textarea.setAttribute('aria-label', Strings.promptLabel);
if (!Browser.isChromeOS) {
@@ -444,7 +450,12 @@ export class Terminal extends CoreTerminal implements ITerminal {
// Register the core browser service before the generic textarea handlers are registered so it
// handles them first. Otherwise the renderers may use the wrong focus state.
this._coreBrowserService = this._instantiationService.createInstance(CoreBrowserService, this.textarea, this._document.defaultView ?? window);
this._coreBrowserService = this.register(this._instantiationService.createInstance(CoreBrowserService,
this.textarea,
parent.ownerDocument.defaultView ?? window,
// Force unsafe null in node.js environment for tests
this._document ?? (typeof window !== 'undefined') ? window.document : null as any
));
this._instantiationService.setService(ICoreBrowserService, this._coreBrowserService);
this.register(addDisposableDomListener(this.textarea, 'focus', (ev: KeyboardEvent) => this._handleTextAreaFocus(ev)));
@@ -466,7 +477,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
this.register(this._renderService.onRenderedViewportChange(e => this._onRender.fire(e)));
this.onResize(e => this._renderService!.resize(e.cols, e.rows));
this._compositionView = document.createElement('div');
this._compositionView = this._document.createElement('div');
this._compositionView.classList.add('composition-view');
this._compositionHelper = this._instantiationService.createInstance(CompositionHelper, this.textarea, this._compositionView);
this._helperContainer.appendChild(this._compositionView);
+5
View File
@@ -350,11 +350,16 @@ export class MockCompositionHelper implements ICompositionHelper {
}
export class MockCoreBrowserService implements ICoreBrowserService {
public onDprChange = new EventEmitter<number>().event;
public onWindowChange = new EventEmitter<Window & typeof globalThis, void>().event;
public serviceBrand: undefined;
public isFocused: boolean = true;
public get window(): Window & typeof globalThis {
throw Error('Window object not available in tests');
}
public get mainDocument(): Document {
throw Error('Document object not available in tests');
}
public dpr: number = 1;
}
@@ -3,8 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { addDisposableDomListener } from 'browser/Lifecycle';
import { IRenderService } from 'browser/services/Services';
import { ICoreBrowserService, IRenderService } from 'browser/services/Services';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { IBufferService, IDecorationService, IInternalDecoration } from 'common/services/Services';
@@ -19,6 +18,7 @@ export class BufferDecorationRenderer extends Disposable {
constructor(
private readonly _screenElement: HTMLElement,
@IBufferService private readonly _bufferService: IBufferService,
@ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService,
@IDecorationService private readonly _decorationService: IDecorationService,
@IRenderService private readonly _renderService: IRenderService
) {
@@ -33,7 +33,7 @@ export class BufferDecorationRenderer extends Disposable {
this._dimensionsChanged = true;
this._queueRefresh();
}));
this.register(addDisposableDomListener(window, 'resize', () => this._queueRefresh()));
this.register(this._coreBrowserService.onDprChange(() => this._queueRefresh()));
this.register(this._bufferService.buffers.onBufferActivate(() => {
this._altBufferIsActive = this._bufferService.buffer === this._bufferService.buffers.alt;
}));
@@ -70,7 +70,7 @@ export class BufferDecorationRenderer extends Disposable {
}
private _createElement(decoration: IInternalDecoration): HTMLElement {
const element = document.createElement('div');
const element = this._coreBrowserService.mainDocument.createElement('div');
element.classList.add('xterm-decoration');
element.classList.toggle('xterm-decoration-top-layer', decoration?.options?.layer === 'top');
element.style.width = `${Math.round((decoration.options.width || 1) * this._renderService.dimensions.css.cell.width)}px`;
@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { ColorZoneStore, IColorZone, IColorZoneStore } from 'browser/decorations/ColorZoneStore';
import { addDisposableDomListener } from 'browser/Lifecycle';
import { ICoreBrowserService, IRenderService } from 'browser/services/Services';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
@@ -52,10 +51,10 @@ export class OverviewRulerRenderer extends Disposable {
@IDecorationService private readonly _decorationService: IDecorationService,
@IRenderService private readonly _renderService: IRenderService,
@IOptionsService private readonly _optionsService: IOptionsService,
@ICoreBrowserService private readonly _coreBrowseService: ICoreBrowserService
@ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService
) {
super();
this._canvas = document.createElement('canvas');
this._canvas = this._coreBrowserService.mainDocument.createElement('canvas');
this._canvas.classList.add('xterm-decoration-overview-ruler');
this._refreshCanvasDimensions();
this._viewportElement.parentElement?.insertBefore(this._canvas, this._viewportElement);
@@ -112,7 +111,7 @@ export class OverviewRulerRenderer extends Disposable {
// overview ruler width changed
this.register(this._optionsService.onSpecificOptionChange('overviewRulerWidth', () => this._queueRefresh(true)));
// device pixel ratio changed
this.register(addDisposableDomListener(this._coreBrowseService.window, 'resize', () => this._queueRefresh(true)));
this.register(this._coreBrowserService.onDprChange(() => this._queueRefresh(true)));
// set the canvas dimensions
this._queueRefresh(true);
}
@@ -135,11 +134,11 @@ export class OverviewRulerRenderer extends Disposable {
}
private _refreshDrawHeightConstants(): void {
drawHeight.full = Math.round(2 * this._coreBrowseService.dpr);
drawHeight.full = Math.round(2 * this._coreBrowserService.dpr);
// Calculate actual pixels per line
const pixelsPerLine = this._canvas.height / this._bufferService.buffer.lines.length;
// Clamp actual pixels within a range
const nonFullHeight = Math.round(Math.max(Math.min(pixelsPerLine, 12), 6) * this._coreBrowseService.dpr);
const nonFullHeight = Math.round(Math.max(Math.min(pixelsPerLine, 12), 6) * this._coreBrowserService.dpr);
drawHeight.left = nonFullHeight;
drawHeight.center = nonFullHeight;
drawHeight.right = nonFullHeight;
@@ -157,9 +156,9 @@ export class OverviewRulerRenderer extends Disposable {
private _refreshCanvasDimensions(): void {
this._canvas.style.width = `${this._width}px`;
this._canvas.width = Math.round(this._width * this._coreBrowseService.dpr);
this._canvas.width = Math.round(this._width * this._coreBrowserService.dpr);
this._canvas.style.height = `${this._screenElement.clientHeight}px`;
this._canvas.height = Math.round(this._screenElement.clientHeight * this._coreBrowseService.dpr);
this._canvas.height = Math.round(this._screenElement.clientHeight * this._coreBrowserService.dpr);
this._refreshDrawConstants();
this._refreshColorZonePadding();
}
@@ -211,7 +210,7 @@ export class OverviewRulerRenderer extends Disposable {
if (this._animationFrame !== undefined) {
return;
}
this._animationFrame = this._coreBrowseService.window.requestAnimationFrame(() => {
this._animationFrame = this._coreBrowserService.window.requestAnimationFrame(() => {
this._refreshDecorations();
this._animationFrame = undefined;
});
+1 -1
View File
@@ -474,7 +474,7 @@ function drawPatternChar(
if (!pattern) {
const width = charDefinition[0].length;
const height = charDefinition.length;
const tmpCanvas = document.createElement('canvas');
const tmpCanvas = ctx.canvas.ownerDocument.createElement('canvas');
tmpCanvas.width = width;
tmpCanvas.height = height;
const tmpCtx = throwIfFalsy(tmpCanvas.getContext('2d'));
+106 -2
View File
@@ -3,22 +3,49 @@
* @license MIT
*/
import { Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle';
import { ICoreBrowserService } from './Services';
import { EventEmitter, forwardEvent } from 'common/EventEmitter';
import { addDisposableDomListener } from 'browser/Lifecycle';
export class CoreBrowserService implements ICoreBrowserService {
export class CoreBrowserService extends Disposable implements ICoreBrowserService {
public serviceBrand: undefined;
private _isFocused = false;
private _cachedIsFocused: boolean | undefined = undefined;
private _screenDprMonitor = new ScreenDprMonitor(this._window);
private readonly _onDprChange = this.register(new EventEmitter<number>());
public readonly onDprChange = this._onDprChange.event;
private readonly _onWindowChange = this.register(new EventEmitter<Window & typeof globalThis>());
public readonly onWindowChange = this._onWindowChange.event;
constructor(
private _textarea: HTMLTextAreaElement,
public readonly window: Window & typeof globalThis
private _window: Window & typeof globalThis,
public readonly mainDocument: Document
) {
super();
// Monitor device pixel ratio
this.register(this.onWindowChange(w => this._screenDprMonitor.setWindow(w)));
this.register(forwardEvent(this._screenDprMonitor.onDprChange, this._onDprChange));
this._textarea.addEventListener('focus', () => this._isFocused = true);
this._textarea.addEventListener('blur', () => this._isFocused = false);
}
public get window(): Window & typeof globalThis {
return this._window;
}
public set window(value: Window & typeof globalThis) {
if (this._window !== value) {
this._window = value;
this._onWindowChange.fire(this._window);
}
}
public get dpr(): number {
return this.window.devicePixelRatio;
}
@@ -31,3 +58,80 @@ export class CoreBrowserService implements ICoreBrowserService {
return this._cachedIsFocused;
}
}
/**
* The screen device pixel ratio monitor allows listening for when the
* window.devicePixelRatio value changes. This is done not with polling but with
* the use of window.matchMedia to watch media queries. When the event fires,
* the listener will be reattached using a different media query to ensure that
* any further changes will register.
*
* The listener should fire on both window zoom changes and switching to a
* monitor with a different DPI.
*/
class ScreenDprMonitor extends Disposable {
private _currentDevicePixelRatio: number;
private _outerListener: ((this: MediaQueryList, ev: MediaQueryListEvent) => any) | undefined;
private _resolutionMediaMatchList: MediaQueryList | undefined;
private _windowResizeListener = this.register(new MutableDisposable());
private readonly _onDprChange = this.register(new EventEmitter<number>());
public readonly onDprChange = this._onDprChange.event;
constructor(private _parentWindow: Window) {
super();
// Initialize listener and dpr value
this._outerListener = () => this._setDprAndFireIfDiffers();
this._currentDevicePixelRatio = this._parentWindow.devicePixelRatio;
this._updateDpr();
// Monitor active window resize
this._setWindowResizeListener();
// Setup additional disposables
this.register(toDisposable(() => this.clearListener()));
}
public setWindow(parentWindow: Window): void {
this._parentWindow = parentWindow;
this._setWindowResizeListener();
this._setDprAndFireIfDiffers();
}
private _setWindowResizeListener(): void {
this._windowResizeListener.value = addDisposableDomListener(this._parentWindow, 'resize', () => this._setDprAndFireIfDiffers());
}
private _setDprAndFireIfDiffers(): void {
if (this._parentWindow.devicePixelRatio !== this._currentDevicePixelRatio) {
this._onDprChange.fire(this._parentWindow.devicePixelRatio);
}
this._updateDpr();
}
private _updateDpr(): void {
if (!this._outerListener) {
return;
}
// Clear listeners for old DPR
this._resolutionMediaMatchList?.removeListener(this._outerListener);
// Add listeners for new DPR
this._currentDevicePixelRatio = this._parentWindow.devicePixelRatio;
this._resolutionMediaMatchList = this._parentWindow.matchMedia(`screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)`);
this._resolutionMediaMatchList.addListener(this._outerListener);
}
public clearListener(): void {
if (!this._resolutionMediaMatchList || !this._outerListener) {
return;
}
this._resolutionMediaMatchList.removeListener(this._outerListener);
this._resolutionMediaMatchList = undefined;
this._outerListener = undefined;
}
}
+3 -11
View File
@@ -3,16 +3,14 @@
* @license MIT
*/
import { addDisposableDomListener } from 'browser/Lifecycle';
import { RenderDebouncer } from 'browser/RenderDebouncer';
import { ScreenDprMonitor } from 'browser/ScreenDprMonitor';
import { IRenderDebouncerWithCallback } from 'browser/Types';
import { IRenderDimensions, IRenderer } from 'browser/renderer/shared/Types';
import { ICharSizeService, ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services';
import { EventEmitter } from 'common/EventEmitter';
import { Disposable, MutableDisposable } from 'common/Lifecycle';
import { DebouncedIdleTask } from 'common/TaskQueue';
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
import { IBufferService, IDecorationService, IInstantiationService, IOptionsService } from 'common/services/Services';
interface ISelectionState {
start: [number, number] | undefined;
@@ -25,7 +23,6 @@ export class RenderService extends Disposable implements IRenderService {
private _renderer: MutableDisposable<IRenderer> = this.register(new MutableDisposable());
private _renderDebouncer: IRenderDebouncerWithCallback;
private _screenDprMonitor: ScreenDprMonitor;
private _pausedResizeTask = new DebouncedIdleTask();
private _isPaused: boolean = false;
@@ -59,6 +56,7 @@ export class RenderService extends Disposable implements IRenderService {
@IDecorationService decorationService: IDecorationService,
@IBufferService bufferService: IBufferService,
@ICoreBrowserService coreBrowserService: ICoreBrowserService,
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService
) {
super();
@@ -66,9 +64,7 @@ export class RenderService extends Disposable implements IRenderService {
this._renderDebouncer = new RenderDebouncer(coreBrowserService.window, (start, end) => this._renderRows(start, end));
this.register(this._renderDebouncer);
this._screenDprMonitor = new ScreenDprMonitor(coreBrowserService.window);
this._screenDprMonitor.setListener(() => this.handleDevicePixelRatioChange());
this.register(this._screenDprMonitor);
this.register(coreBrowserService.onDprChange(() => this.handleDevicePixelRatioChange()));
this.register(bufferService.onResize(() => this._fullRefresh()));
this.register(bufferService.buffers.onBufferActivate(() => this._renderer.value?.clear()));
@@ -104,10 +100,6 @@ export class RenderService extends Disposable implements IRenderService {
'cursorStyle'
], () => this.refreshRows(bufferService.buffer.y, bufferService.buffer.y, true)));
// dprchange should handle this case, we need this as well for browsers that don't support the
// matchMedia query.
this.register(addDisposableDomListener(coreBrowserService.window, 'resize', () => this.handleDevicePixelRatioChange()));
this.register(themeService.onChangeColors(() => this._fullRefresh()));
// Detect whether IntersectionObserver is detected and enable renderer pause
+13 -4
View File
@@ -28,12 +28,21 @@ export interface ICoreBrowserService {
serviceBrand: undefined;
readonly isFocused: boolean;
readonly onDprChange: IEvent<number>;
readonly onWindowChange: IEvent<Window & typeof globalThis>;
/**
* Parent window that the terminal is rendered into. DOM and rendering APIs
* (e.g. requestAnimationFrame) should be invoked in the context of this
* window.
* Gets or sets the parent window that the terminal is rendered into. DOM and rendering APIs (e.g.
* requestAnimationFrame) should be invoked in the context of this window. This should be set when
* the window hosting the xterm.js instance changes.
*/
readonly window: Window & typeof globalThis;
window: Window & typeof globalThis;
/**
* The document of the primary window to be used to create elements when working with multiple
* windows. This is defined by the documentOverride setting.
*/
readonly mainDocument: Document;
/**
* Helper for getting the devicePixelRatio of the parent window.
*/
+1
View File
@@ -113,6 +113,7 @@ export namespace css {
let $ctx: CanvasRenderingContext2D | undefined;
let $litmusColor: CanvasGradient | undefined;
if (!isNode) {
// This is guaranteed to run in the first window, so document should be correct
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
+5
View File
@@ -71,3 +71,8 @@ export class EventEmitter<T, U = void> implements IEventEmitter<T, U> {
export function forwardEvent<T>(from: IEvent<T>, to: IEventEmitter<T>): IDisposable {
return from(e => to.fire(e));
}
export function runAndSubscribe<T>(event: IEvent<T>, handler: (e: T | undefined) => any): IDisposable {
handler(undefined);
return event(e => handler(e));
}
+2 -1
View File
@@ -12,8 +12,9 @@ interface INavigator {
// We're declaring a navigator global here as we expect it in all runtimes (node and browser), but
// we want this module to live in common.
declare const navigator: INavigator;
declare const process: unknown;
export const isNode = (typeof navigator === 'undefined') ? true : false;
export const isNode = (typeof process !== 'undefined') ? true : false;
const userAgent = (isNode) ? 'node' : navigator.userAgent;
const platform = (isNode) ? 'node' : navigator.platform;
+2 -1
View File
@@ -973,7 +973,8 @@ declare module 'xterm' {
resize(columns: number, rows: number): void;
/**
* Opens the terminal within an element.
* Opens the terminal within an element. This should also be called if the
* xterm.js element ever changes browser window.
* @param parent The element to create the terminal within. This element
* must be visible (have dimensions) when `open` is called as several DOM-
* based measurements need to be performed when this function is called.
+4 -2
View File
@@ -39,8 +39,10 @@ const config = {
output: {
filename: 'xterm.js',
path: path.resolve('./lib'),
libraryTarget: 'umd'
libraryTarget: 'umd',
// Force usage of globalThis instead of global / self. (This is cross-env compatible)
globalObject: 'globalThis',
},
mode: 'production'
mode: 'production',
};
module.exports = config;

Some files were not shown because too many files have changed in this diff Show More