mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Move ColorManager ownership to Terminal
This commit is contained in:
+15
-10
@@ -53,6 +53,7 @@ import { clone } from './common/Clone';
|
||||
import { EventEmitter2, IEvent } from './common/EventEmitter2';
|
||||
import { Attributes, DEFAULT_ATTR_DATA } from './core/buffer/BufferLine';
|
||||
import { applyWindowsMode } from './WindowsMode';
|
||||
import { ColorManager } from './ui/ColorManager';
|
||||
|
||||
// Let it work inside Node.js for automated testing purposes.
|
||||
const document = (typeof window !== 'undefined') ? window.document : null;
|
||||
@@ -109,7 +110,7 @@ const DEFAULT_OPTIONS: ITerminalOptions = {
|
||||
useFlowControl: false,
|
||||
allowTransparency: false,
|
||||
tabStopWidth: 8,
|
||||
theme: null,
|
||||
theme: undefined,
|
||||
rightClickSelectsWord: Browser.isMac,
|
||||
rendererType: 'canvas',
|
||||
windowsMode: false
|
||||
@@ -212,6 +213,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
|
||||
private _mouseZoneManager: IMouseZoneManager;
|
||||
public mouseHelper: MouseHelper;
|
||||
private _accessibilityManager: AccessibilityManager;
|
||||
private _colorManager: ColorManager;
|
||||
private _screenDprMonitor: ScreenDprMonitor;
|
||||
private _theme: ITheme;
|
||||
private _windowsMode: IDisposable | undefined;
|
||||
@@ -528,9 +530,6 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
|
||||
}
|
||||
this._setupRenderer();
|
||||
this.renderer.onCharSizeChanged();
|
||||
if (this._theme) {
|
||||
this.renderer.setTheme(this._theme);
|
||||
}
|
||||
this.mouseHelper.setRenderer(this.renderer);
|
||||
break;
|
||||
case 'scrollback':
|
||||
@@ -765,11 +764,14 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
|
||||
// Performance: Add viewport and helper elements from the fragment
|
||||
this.element.appendChild(fragment);
|
||||
|
||||
this._setupRenderer();
|
||||
this._theme = this.options.theme;
|
||||
this.options.theme = null;
|
||||
this._colorManager = new ColorManager(document, this.options.allowTransparency);
|
||||
this._colorManager.setTheme(this._theme);
|
||||
this._setupRenderer();
|
||||
|
||||
this.viewport = new Viewport(this, this._viewportElement, this._viewportScrollArea, this.charMeasure);
|
||||
this.viewport.onThemeChanged(this.renderer.colorManager.colors);
|
||||
this.viewport.onThemeChange(this._colorManager.colors);
|
||||
this.register(this.viewport);
|
||||
|
||||
this.register(this.onCursorMove(() => this.renderer.onCursorMove()));
|
||||
@@ -833,8 +835,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
|
||||
|
||||
private _setupRenderer(): void {
|
||||
switch (this.options.rendererType) {
|
||||
case 'canvas': this.renderer = new Renderer(this, this.options.theme); break;
|
||||
case 'dom': this.renderer = new DomRenderer(this, this.options.theme); break;
|
||||
case 'canvas': this.renderer = new Renderer(this, this._colorManager.colors); break;
|
||||
case 'dom': this.renderer = new DomRenderer(this, this._colorManager.colors); break;
|
||||
default: throw new Error(`Unrecognized rendererType "${this.options.rendererType}"`);
|
||||
}
|
||||
this.renderer.onRender(e => this._onRender.fire(e));
|
||||
@@ -847,9 +849,12 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
|
||||
*/
|
||||
private _setTheme(theme: ITheme): void {
|
||||
this._theme = theme;
|
||||
const colors = this.renderer.setTheme(theme);
|
||||
this._colorManager.setTheme(theme);
|
||||
if (this.renderer) {
|
||||
this.renderer.onThemeChange(this._colorManager.colors);
|
||||
}
|
||||
if (this.viewport) {
|
||||
this.viewport.onThemeChanged(colors);
|
||||
this.viewport.onThemeChange(this._colorManager.colors);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { IBufferLine, ICellData, IAttributeData } from './core/Types';
|
||||
import { ICircularList, XtermListener } from './common/Types';
|
||||
import { Buffer } from './Buffer';
|
||||
import * as Browser from './common/Platform';
|
||||
import { ITheme, IDisposable, IMarker, IEvent, ISelectionPosition } from 'xterm';
|
||||
import { IDisposable, IMarker, IEvent, ISelectionPosition } from 'xterm';
|
||||
import { Terminal } from './Terminal';
|
||||
import { AttributeData } from './core/buffer/BufferLine';
|
||||
import { IColorManager, IColorSet } from './ui/Types';
|
||||
@@ -384,7 +384,9 @@ export class MockRenderer implements IRenderer {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
dimensions: IRenderDimensions;
|
||||
setTheme(theme: ITheme): IColorSet { return <IColorSet>{}; }
|
||||
onThemeChange(colors: IColorSet): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
onResize(cols: number, rows: number): void {}
|
||||
onCharSizeChanged(): void {}
|
||||
onBlur(): void {}
|
||||
@@ -404,7 +406,7 @@ export class MockViewport implements IViewport {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
scrollBarWidth: number = 0;
|
||||
onThemeChanged(colors: IColorSet): void {
|
||||
onThemeChange(colors: IColorSet): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
onWheel(ev: WheelEvent): void {
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ export interface IViewport extends IDisposable {
|
||||
onWheel(ev: WheelEvent): void;
|
||||
onTouchStart(ev: TouchEvent): void;
|
||||
onTouchMove(ev: TouchEvent): void;
|
||||
onThemeChanged(colors: IColorSet): void;
|
||||
onThemeChange(colors: IColorSet): void;
|
||||
}
|
||||
|
||||
export interface ICompositionHelper {
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ export class Viewport extends Disposable implements IViewport {
|
||||
setTimeout(() => this.syncScrollArea(), 0);
|
||||
}
|
||||
|
||||
public onThemeChanged(colors: IColorSet): void {
|
||||
public onThemeChange(colors: IColorSet): void {
|
||||
this._viewportElement.style.backgroundColor = colors.background.css;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
public onGridChanged(terminal: ITerminal, startRow: number, endRow: number): void {}
|
||||
public onSelectionChanged(terminal: ITerminal, start: [number, number], end: [number, number], columnSelectMode: boolean = false): void {}
|
||||
|
||||
public onThemeChanged(terminal: ITerminal, colorSet: IColorSet): void {
|
||||
public onThemeChange(terminal: ITerminal, colorSet: IColorSet): void {
|
||||
this._refreshCharAtlas(terminal, colorSet);
|
||||
}
|
||||
|
||||
|
||||
+10
-19
@@ -6,13 +6,11 @@
|
||||
import { TextRenderLayer } from './TextRenderLayer';
|
||||
import { SelectionRenderLayer } from './SelectionRenderLayer';
|
||||
import { CursorRenderLayer } from './CursorRenderLayer';
|
||||
import { ColorManager } from '../ui/ColorManager';
|
||||
import { IRenderLayer, IRenderer, IRenderDimensions, ICharacterJoinerRegistry } from './Types';
|
||||
import { ITerminal, CharacterJoinerHandler } from '../Types';
|
||||
import { LinkRenderLayer } from './LinkRenderLayer';
|
||||
import { RenderDebouncer } from '../ui/RenderDebouncer';
|
||||
import { ScreenDprMonitor } from '../ui/ScreenDprMonitor';
|
||||
import { ITheme } from 'xterm';
|
||||
import { CharacterJoinerRegistry } from '../renderer/CharacterJoinerRegistry';
|
||||
import { EventEmitter2, IEvent } from '../common/EventEmitter2';
|
||||
import { Disposable } from '../common/Lifecycle';
|
||||
@@ -28,7 +26,6 @@ export class Renderer extends Disposable implements IRenderer {
|
||||
private _needsFullRefresh: boolean = false;
|
||||
private _characterJoinerRegistry: ICharacterJoinerRegistry;
|
||||
|
||||
public colorManager: ColorManager;
|
||||
public dimensions: IRenderDimensions;
|
||||
|
||||
private _onCanvasResize = new EventEmitter2<{ width: number, height: number }>();
|
||||
@@ -36,20 +33,19 @@ export class Renderer extends Disposable implements IRenderer {
|
||||
private _onRender = new EventEmitter2<{ start: number, end: number }>();
|
||||
public get onRender(): IEvent<{ start: number, end: number }> { return this._onRender.event; }
|
||||
|
||||
constructor(private _terminal: ITerminal, theme: ITheme) {
|
||||
constructor(
|
||||
private _terminal: ITerminal,
|
||||
private _colors: IColorSet
|
||||
) {
|
||||
super();
|
||||
const allowTransparency = this._terminal.options.allowTransparency;
|
||||
this.colorManager = new ColorManager(document, allowTransparency);
|
||||
this._characterJoinerRegistry = new CharacterJoinerRegistry(_terminal);
|
||||
if (theme) {
|
||||
this.colorManager.setTheme(theme);
|
||||
}
|
||||
|
||||
this._renderLayers = [
|
||||
new TextRenderLayer(this._terminal.screenElement, 0, this.colorManager.colors, this._characterJoinerRegistry, allowTransparency),
|
||||
new SelectionRenderLayer(this._terminal.screenElement, 1, this.colorManager.colors),
|
||||
new LinkRenderLayer(this._terminal.screenElement, 2, this.colorManager.colors, this._terminal),
|
||||
new CursorRenderLayer(this._terminal.screenElement, 3, this.colorManager.colors)
|
||||
new TextRenderLayer(this._terminal.screenElement, 0, this._colors, this._characterJoinerRegistry, allowTransparency),
|
||||
new SelectionRenderLayer(this._terminal.screenElement, 1, this._colors),
|
||||
new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._terminal),
|
||||
new CursorRenderLayer(this._terminal.screenElement, 3, this._colors)
|
||||
];
|
||||
this.dimensions = {
|
||||
scaledCharWidth: null,
|
||||
@@ -105,12 +101,10 @@ export class Renderer extends Disposable implements IRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
public setTheme(theme: ITheme): IColorSet {
|
||||
this.colorManager.setTheme(theme);
|
||||
|
||||
public onThemeChange(colors: IColorSet): void {
|
||||
// Clear layers and force a full render
|
||||
this._renderLayers.forEach(l => {
|
||||
l.onThemeChanged(this._terminal, this.colorManager.colors);
|
||||
l.onThemeChange(this._terminal, this._colors);
|
||||
l.reset(this._terminal);
|
||||
});
|
||||
|
||||
@@ -119,8 +113,6 @@ export class Renderer extends Disposable implements IRenderer {
|
||||
} else {
|
||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||
}
|
||||
|
||||
return this.colorManager.colors;
|
||||
}
|
||||
|
||||
public onResize(cols: number, rows: number): void {
|
||||
@@ -168,7 +160,6 @@ export class Renderer extends Disposable implements IRenderer {
|
||||
}
|
||||
|
||||
public onOptionsChanged(): void {
|
||||
this.colorManager.allowTransparency = this._terminal.options.allowTransparency;
|
||||
this._runOperation(l => l.onOptionsChanged(this._terminal));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
*/
|
||||
|
||||
import { ITerminal, CharacterJoinerHandler } from '../Types';
|
||||
import { ITheme, IDisposable } from 'xterm';
|
||||
import { IDisposable } from 'xterm';
|
||||
import { IEvent } from '../common/EventEmitter2';
|
||||
import { IColorManager, IColorSet } from '../ui/Types';
|
||||
import { IColorSet } from '../ui/Types';
|
||||
|
||||
/**
|
||||
* Flags used to render terminal text properly.
|
||||
@@ -27,13 +27,12 @@ export const enum FLAGS {
|
||||
*/
|
||||
export interface IRenderer extends IDisposable {
|
||||
dimensions: IRenderDimensions;
|
||||
colorManager: IColorManager;
|
||||
|
||||
onCanvasResize: IEvent<{ width: number, height: number }>;
|
||||
onRender: IEvent<{ start: number, end: number }>;
|
||||
|
||||
dispose(): void;
|
||||
setTheme(theme: ITheme): IColorSet;
|
||||
onThemeChange(colors: IColorSet): void;
|
||||
onWindowResize(devicePixelRatio: number): void;
|
||||
onResize(cols: number, rows: number): void;
|
||||
onCharSizeChanged(): void;
|
||||
@@ -87,7 +86,7 @@ export interface IRenderLayer extends IDisposable {
|
||||
/**
|
||||
* Called when the theme changes.
|
||||
*/
|
||||
onThemeChanged(terminal: ITerminal, colorSet: IColorSet): void;
|
||||
onThemeChange(terminal: ITerminal, colorSet: IColorSet): void;
|
||||
|
||||
/**
|
||||
* Called when the data in the grid has changed (or needs to be rendered
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
import { IRenderer, IRenderDimensions } from '../Types';
|
||||
import { ILinkifierEvent, ITerminal, CharacterJoinerHandler } from '../../Types';
|
||||
import { ITheme } from 'xterm';
|
||||
import { ColorManager } from '../../ui/ColorManager';
|
||||
import { RenderDebouncer } from '../../ui/RenderDebouncer';
|
||||
import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from './DomRendererRowFactory';
|
||||
import { INVERTED_DEFAULT_COLOR } from '../atlas/Types';
|
||||
@@ -43,18 +41,17 @@ export class DomRenderer extends Disposable implements IRenderer {
|
||||
private _selectionContainer: HTMLElement;
|
||||
|
||||
public dimensions: IRenderDimensions;
|
||||
public colorManager: ColorManager;
|
||||
|
||||
private _onCanvasResize = new EventEmitter2<{ width: number, height: number }>();
|
||||
public get onCanvasResize(): IEvent<{ width: number, height: number }> { return this._onCanvasResize.event; }
|
||||
private _onRender = new EventEmitter2<{ start: number, end: number }>();
|
||||
public get onRender(): IEvent<{ start: number, end: number }> { return this._onRender.event; }
|
||||
|
||||
constructor(private _terminal: ITerminal, theme: ITheme | undefined) {
|
||||
constructor(
|
||||
private _terminal: ITerminal,
|
||||
private _colors: IColorSet
|
||||
) {
|
||||
super();
|
||||
const allowTransparency = this._terminal.options.allowTransparency;
|
||||
this.colorManager = new ColorManager(document, allowTransparency);
|
||||
this.setTheme(theme);
|
||||
|
||||
this._rowContainer = document.createElement('div');
|
||||
this._rowContainer.classList.add(ROW_CONTAINER_CLASS);
|
||||
@@ -143,11 +140,12 @@ export class DomRenderer extends Disposable implements IRenderer {
|
||||
this._terminal.screenElement.style.height = `${this.dimensions.canvasHeight}px`;
|
||||
}
|
||||
|
||||
public setTheme(theme: ITheme | undefined): IColorSet {
|
||||
if (theme) {
|
||||
this.colorManager.setTheme(theme);
|
||||
}
|
||||
public onThemeChange(colors: IColorSet): void {
|
||||
this._colors = colors;
|
||||
this._injectCss();
|
||||
}
|
||||
|
||||
private _injectCss(): void {
|
||||
if (!this._themeStyleElement) {
|
||||
this._themeStyleElement = document.createElement('style');
|
||||
this._terminal.screenElement.appendChild(this._themeStyleElement);
|
||||
@@ -156,8 +154,8 @@ export class DomRenderer extends Disposable implements IRenderer {
|
||||
// Base CSS
|
||||
let styles =
|
||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS} {` +
|
||||
` color: ${this.colorManager.colors.foreground.css};` +
|
||||
` background-color: ${this.colorManager.colors.background.css};` +
|
||||
` color: ${this._colors.foreground.css};` +
|
||||
` background-color: ${this._colors.background.css};` +
|
||||
` font-family: ${this._terminal.options.fontFamily};` +
|
||||
` font-size: ${this._terminal.options.fontSize}px;` +
|
||||
`}`;
|
||||
@@ -182,21 +180,21 @@ export class DomRenderer extends Disposable implements IRenderer {
|
||||
// Cursor
|
||||
styles +=
|
||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}:not(.${FOCUS_CLASS}) .${CURSOR_CLASS} {` +
|
||||
` outline: 1px solid ${this.colorManager.colors.cursor.css};` +
|
||||
` outline: 1px solid ${this._colors.cursor.css};` +
|
||||
` outline-offset: -1px;` +
|
||||
`}` +
|
||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_BLINK_CLASS} {` +
|
||||
` animation: blink 1s step-end infinite;` +
|
||||
`}` +
|
||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_BLOCK_CLASS} {` +
|
||||
` background-color: ${this.colorManager.colors.cursor.css};` +
|
||||
` color: ${this.colorManager.colors.cursorAccent.css};` +
|
||||
` background-color: ${this._colors.cursor.css};` +
|
||||
` color: ${this._colors.cursorAccent.css};` +
|
||||
`}` +
|
||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_BAR_CLASS} {` +
|
||||
` box-shadow: 1px 0 0 ${this.colorManager.colors.cursor.css} inset;` +
|
||||
` box-shadow: 1px 0 0 ${this._colors.cursor.css} inset;` +
|
||||
`}` +
|
||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_UNDERLINE_CLASS} {` +
|
||||
` box-shadow: 0 -1px 0 ${this.colorManager.colors.cursor.css} inset;` +
|
||||
` box-shadow: 0 -1px 0 ${this._colors.cursor.css} inset;` +
|
||||
`}`;
|
||||
// Selection
|
||||
styles +=
|
||||
@@ -209,20 +207,19 @@ export class DomRenderer extends Disposable implements IRenderer {
|
||||
`}` +
|
||||
`${this._terminalSelector} .${SELECTION_CLASS} div {` +
|
||||
` position: absolute;` +
|
||||
` background-color: ${this.colorManager.colors.selection.css};` +
|
||||
` background-color: ${this._colors.selection.css};` +
|
||||
`}`;
|
||||
// Colors
|
||||
this.colorManager.colors.ansi.forEach((c, i) => {
|
||||
this._colors.ansi.forEach((c, i) => {
|
||||
styles +=
|
||||
`${this._terminalSelector} .${FG_CLASS_PREFIX}${i} { color: ${c.css}; }` +
|
||||
`${this._terminalSelector} .${BG_CLASS_PREFIX}${i} { background-color: ${c.css}; }`;
|
||||
});
|
||||
styles +=
|
||||
`${this._terminalSelector} .${FG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { color: ${this.colorManager.colors.background.css}; }` +
|
||||
`${this._terminalSelector} .${BG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { background-color: ${this.colorManager.colors.foreground.css}; }`;
|
||||
`${this._terminalSelector} .${FG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { color: ${this._colors.background.css}; }` +
|
||||
`${this._terminalSelector} .${BG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { background-color: ${this._colors.foreground.css}; }`;
|
||||
|
||||
this._themeStyleElement.innerHTML = styles;
|
||||
return this.colorManager.colors;
|
||||
}
|
||||
|
||||
public onWindowResize(devicePixelRatio: number): void {
|
||||
@@ -332,7 +329,7 @@ export class DomRenderer extends Disposable implements IRenderer {
|
||||
public onOptionsChanged(): void {
|
||||
// Force a refresh
|
||||
this._updateDimensions();
|
||||
this.setTheme(undefined);
|
||||
this._injectCss();
|
||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ export class ColorManager implements IColorManager {
|
||||
* @param theme The theme to use. If a partial theme is provided then default
|
||||
* colors will be used where colors are not defined.
|
||||
*/
|
||||
public setTheme(theme: ITheme): void {
|
||||
public setTheme(theme: ITheme = {}): void {
|
||||
this.colors.foreground = this._parseColor(theme.foreground, DEFAULT_FOREGROUND);
|
||||
this.colors.background = this._parseColor(theme.background, DEFAULT_BACKGROUND);
|
||||
this.colors.cursor = this._parseColor(theme.cursor, DEFAULT_CURSOR, true);
|
||||
|
||||
Reference in New Issue
Block a user