Merge branch 'master' into tyriar/dim_bg

This commit is contained in:
Daniel Imms
2022-07-29 10:20:22 -07:00
committed by GitHub
31 changed files with 328 additions and 172 deletions
+5
View File
@@ -38,6 +38,11 @@ export class Linkifier2 extends Disposable implements ILinkifier2 {
this.register(getDisposeArrayDisposable(this._linkCacheDisposables));
}
public dispose(): void {
super.dispose();
this._lastMouseEvent = undefined;
}
public registerLinkProvider(linkProvider: ILinkProvider): IDisposable {
this._linkProviders.push(linkProvider);
return {
+5 -4
View File
@@ -81,6 +81,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
// browser services
private _decorationService: DecorationService;
private _charSizeService: ICharSizeService | undefined;
private _coreBrowserService: ICoreBrowserService | undefined;
private _mouseService: IMouseService | undefined;
private _renderService: IRenderService | undefined;
private _characterJoinerService: ICharacterJoinerService | undefined;
@@ -494,8 +495,8 @@ export class Terminal extends CoreTerminal implements ITerminal {
this.register(addDisposableDomListener(this.textarea, 'blur', () => this._onTextAreaBlur()));
this._helperContainer.appendChild(this.textarea);
const coreBrowserService = this._instantiationService.createInstance(CoreBrowserService, this.textarea);
this._instantiationService.setService(ICoreBrowserService, coreBrowserService);
this._coreBrowserService = this._instantiationService.createInstance(CoreBrowserService, this.textarea);
this._instantiationService.setService(ICoreBrowserService, this._coreBrowserService);
this._charSizeService = this._instantiationService.createInstance(CharSizeService, this._document, this._helperContainer);
this._instantiationService.setService(ICharSizeService, this._charSizeService);
@@ -586,11 +587,11 @@ export class Terminal extends CoreTerminal implements ITerminal {
}
if (this.options.overviewRulerWidth) {
this._overviewRulerRenderer = this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement);
this._overviewRulerRenderer = this.register(this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement));
}
this.optionsService.onOptionChange(() => {
if (!this._overviewRulerRenderer && this.options.overviewRulerWidth && this._viewportElement && this.screenElement) {
this._overviewRulerRenderer = this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement);
this._overviewRulerRenderer = this.register(this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement));
}
});
// Measure the character size
+1 -1
View File
@@ -168,7 +168,7 @@ export interface ILinkWithState {
state?: ILinkState;
}
export interface ILinkifier2 {
export interface ILinkifier2 extends IDisposable {
onShowLinkUnderline: IEvent<ILinkifierEvent>;
onHideLinkUnderline: IEvent<ILinkifierEvent>;
readonly currentLink: ILinkWithState | undefined;
+59 -1
View File
@@ -13,6 +13,12 @@ import { IRenderDimensions } from 'browser/renderer/Types';
const FALLBACK_SCROLL_BAR_WIDTH = 15;
interface ISmoothScrollState {
startTime: number;
origin: number;
target: number;
}
/**
* Represents the viewport of a terminal, the visible area within the larger buffer of output.
* Logic for the virtual scroll bar is included in this object.
@@ -36,6 +42,11 @@ export class Viewport extends Disposable implements IViewport {
private _refreshAnimationFrame: number | null = null;
private _ignoreNextScrollEvent: boolean = false;
private _smoothScrollState: ISmoothScrollState = {
startTime: 0,
origin: -1,
target: -1
};
constructor(
private readonly _scrollLines: (amount: number) => void,
@@ -168,6 +179,37 @@ export class Viewport extends Disposable implements IViewport {
this._scrollLines(diff);
}
private _smoothScroll(): void {
// Check valid state
if (this._isDisposed || this._smoothScrollState.origin === -1 || this._smoothScrollState.target === -1) {
return;
}
// Calculate position complete
const percent = this._smoothScrollPercent();
this._viewportElement.scrollTop = this._smoothScrollState.origin + Math.round(percent * (this._smoothScrollState.target - this._smoothScrollState.origin));
// Continue or finish smooth scroll
if (percent < 1) {
window.requestAnimationFrame(() => this._smoothScroll());
} else {
this._clearSmoothScrollState();
}
}
private _smoothScrollPercent(): number {
if (!this._optionsService.rawOptions.smoothScrollDuration || !this._smoothScrollState.startTime) {
return 1;
}
return Math.max(Math.min((Date.now() - this._smoothScrollState.startTime) / this._optionsService.rawOptions.smoothScrollDuration, 1), 0);
}
private _clearSmoothScrollState(): void {
this._smoothScrollState.startTime = 0;
this._smoothScrollState.origin = -1;
this._smoothScrollState.target = -1;
}
/**
* Handles bubbling of scroll event in case the viewport has reached top or bottom
* @param ev The scroll event.
@@ -196,7 +238,23 @@ export class Viewport extends Disposable implements IViewport {
if (amount === 0) {
return false;
}
this._viewportElement.scrollTop += amount;
if (!this._optionsService.rawOptions.smoothScrollDuration) {
this._viewportElement.scrollTop += amount;
} else {
this._smoothScrollState.startTime = Date.now();
if (this._smoothScrollPercent() < 1) {
this._smoothScrollState.origin = this._viewportElement.scrollTop;
if (this._smoothScrollState.target === -1) {
this._smoothScrollState.target = this._viewportElement.scrollTop + amount;
} else {
this._smoothScrollState.target += amount;
}
this._smoothScrollState.target = Math.max(Math.min(this._smoothScrollState.target, this._viewportElement.scrollHeight), 0);
this._smoothScroll();
} else {
this._clearSmoothScrollState();
}
}
return this._bubbleScroll(ev, amount);
}
@@ -0,0 +1,34 @@
/**
* Copyright (c) 2022 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { toDisposable } from 'common/Lifecycle';
import { IDisposable } from 'common/Types';
export function observeDevicePixelDimensions(element: HTMLElement, callback: (deviceWidth: number, deviceHeight: number) => void): IDisposable {
// Observe any resizes to the element and extract the actual pixel size of the element if the
// devicePixelContentBoxSize API is supported. This allows correcting rounding errors when
// converting between CSS pixels and device pixels which causes blurry rendering when device
// pixel ratio is not a round number.
let observer: ResizeObserver | undefined = new ResizeObserver((entries) => {
const entry = entries.find((entry) => entry.target === element);
if (!entry) {
return;
}
// Disconnect if devicePixelContentBoxSize isn't supported by the browser
if (!('devicePixelContentBoxSize' in entry)) {
observer?.disconnect();
observer = undefined;
return;
}
callback(
entry.devicePixelContentBoxSize[0].inlineSize,
entry.devicePixelContentBoxSize[0].blockSize
);
});
observer.observe(element, { box: ['device-pixel-content-box'] } as any);
return toDisposable(() => observer?.disconnect());
}
+2 -2
View File
@@ -200,7 +200,7 @@ export namespace rgba {
const resultA = reduceLuminance(bgRgba, fgRgba, ratio);
const resultARatio = contrastRatio(bgL, rgb.relativeLuminance(resultA >> 8));
if (resultARatio < ratio) {
const resultB = increaseLuminance(bgRgba, bgRgba, ratio);
const resultB = increaseLuminance(bgRgba, fgRgba, ratio);
const resultBRatio = contrastRatio(bgL, rgb.relativeLuminance(resultB >> 8));
return resultARatio > resultBRatio ? resultA : resultB;
}
@@ -209,7 +209,7 @@ export namespace rgba {
const resultA = increaseLuminance(bgRgba, fgRgba, ratio);
const resultARatio = contrastRatio(bgL, rgb.relativeLuminance(resultA >> 8));
if (resultARatio < ratio) {
const resultB = reduceLuminance(bgRgba, bgRgba, ratio);
const resultB = reduceLuminance(bgRgba, fgRgba, ratio);
const resultBRatio = contrastRatio(bgL, rgb.relativeLuminance(resultB >> 8));
return resultARatio > resultBRatio ? resultA : resultB;
}
+1 -4
View File
@@ -83,10 +83,7 @@ export function evaluateKeyboardEvent(
break;
case 8:
// backspace
if (ev.shiftKey) {
result.key = C0.BS; // ^H
break;
} else if (ev.altKey) {
if (ev.altKey) {
result.key = C0.ESC + C0.DEL; // \e ^?
break;
}
+1
View File
@@ -28,6 +28,7 @@ export const DEFAULT_OPTIONS: Readonly<ITerminalOptions> = {
scrollback: 1000,
scrollSensitivity: 1,
screenReaderMode: false,
smoothScrollDuration: 0,
macOptionIsMeta: false,
macOptionClickForcesSelection: false,
minimumContrastRatio: 1,
+1
View File
@@ -232,6 +232,7 @@ export interface ITerminalOptions {
screenReaderMode: boolean;
scrollback: number;
scrollSensitivity: number;
smoothScrollDuration: number;
tabStopWidth: number;
theme: ITheme;
windowsMode: boolean;