Merge pull request #3949 from Tyriar/v5_canvas
Move the canvas renderer into an addon
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
"test/benchmark/tsconfig.json",
|
||||
"addons/xterm-addon-attach/src/tsconfig.json",
|
||||
"addons/xterm-addon-attach/test/tsconfig.json",
|
||||
"addons/xterm-addon-canvas/src/tsconfig.json",
|
||||
"addons/xterm-addon-fit/src/tsconfig.json",
|
||||
"addons/xterm-addon-fit/test/tsconfig.json",
|
||||
"addons/xterm-addon-ligatures/src/tsconfig.json",
|
||||
|
||||
@@ -28,7 +28,7 @@ describe('AttachAddon', () => {
|
||||
beforeEach(async () => await page.goto(APP));
|
||||
|
||||
it('string', async function(): Promise<any> {
|
||||
await openTerminal(page, { rendererType: 'dom' });
|
||||
await openTerminal(page);
|
||||
const port = 8080;
|
||||
const server = new WebSocket.Server({ port });
|
||||
server.on('connection', socket => socket.send('foo'));
|
||||
@@ -38,7 +38,7 @@ describe('AttachAddon', () => {
|
||||
});
|
||||
|
||||
it('utf8', async function(): Promise<any> {
|
||||
await openTerminal(page, { rendererType: 'dom' });
|
||||
await openTerminal(page);
|
||||
const port = 8080;
|
||||
const server = new WebSocket.Server({ port });
|
||||
const data = new Uint8Array([102, 111, 111]);
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
lib
|
||||
node_modules
|
||||
@@ -0,0 +1,29 @@
|
||||
# Blacklist - exclude everything except npm defaults such as LICENSE, etc
|
||||
*
|
||||
!*/
|
||||
|
||||
# Whitelist - lib/
|
||||
!lib/**/*.d.ts
|
||||
|
||||
!lib/**/*.js
|
||||
!lib/**/*.js.map
|
||||
|
||||
!lib/**/*.css
|
||||
|
||||
# Whitelist - src/
|
||||
!src/**/*.ts
|
||||
!src/**/*.d.ts
|
||||
|
||||
!src/**/*.js
|
||||
!src/**/*.js.map
|
||||
|
||||
!src/**/*.css
|
||||
|
||||
# Blacklist - src/ test files
|
||||
src/**/*.test.ts
|
||||
src/**/*.test.d.ts
|
||||
src/**/*.test.js
|
||||
src/**/*.test.js.map
|
||||
|
||||
# Whitelist - typings/
|
||||
!typings/*.d.ts
|
||||
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,23 @@
|
||||
## xterm-addon-canvas
|
||||
|
||||
An addon for [xterm.js](https://github.com/xtermjs/xterm.js) that enables a canvas-based renderer using a 2d context to draw. This addon requires xterm.js v5+.
|
||||
|
||||
|
||||
### Install
|
||||
|
||||
```bash
|
||||
npm install --save xterm-addon-canvas
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```ts
|
||||
import { Terminal } from 'xterm';
|
||||
import { CanvasAddon } from 'xterm-addon-canvas';
|
||||
|
||||
const terminal = new Terminal();
|
||||
terminal.open(element);
|
||||
terminal.loadAddon(new CanvasAddon());
|
||||
```
|
||||
|
||||
See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/xterm-addon-canvas/typings/xterm-addon-canvas.d.ts) for more advanced usage.
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "xterm-addon-canvas",
|
||||
"version": "0.12.0",
|
||||
"author": {
|
||||
"name": "The xterm.js authors",
|
||||
"url": "https://xtermjs.org/"
|
||||
},
|
||||
"main": "lib/xterm-addon-canvas.js",
|
||||
"types": "typings/xterm-addon-canvas.d.ts",
|
||||
"repository": "https://github.com/xtermjs/xterm.js",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"terminal",
|
||||
"canvas",
|
||||
"xterm",
|
||||
"xterm.js"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "../../node_modules/.bin/tsc -p .",
|
||||
"prepackage": "npm run build",
|
||||
"package": "../../node_modules/.bin/webpack",
|
||||
"prepublishOnly": "npm run package"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"xterm": "^4.0.0"
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -3,13 +3,14 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { IRenderDimensions, IRenderLayer } from 'browser/renderer/Types';
|
||||
import { IRenderDimensions } from 'browser/renderer/Types';
|
||||
import { IRenderLayer } from './Types';
|
||||
import { ICellData, IColor } from 'common/Types';
|
||||
import { DEFAULT_COLOR, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE, Attributes } from 'common/buffer/Constants';
|
||||
import { IGlyphIdentifier } from 'browser/renderer/atlas/Types';
|
||||
import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, TEXT_BASELINE } from 'browser/renderer/atlas/Constants';
|
||||
import { BaseCharAtlas } from 'browser/renderer/atlas/BaseCharAtlas';
|
||||
import { acquireCharAtlas } from 'browser/renderer/atlas/CharAtlasCache';
|
||||
import { IGlyphIdentifier } from './atlas/Types';
|
||||
import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, TEXT_BASELINE } from 'browser/renderer/Constants';
|
||||
import { BaseCharAtlas } from './atlas/BaseCharAtlas';
|
||||
import { acquireCharAtlas } from './atlas/CharAtlasCache';
|
||||
import { AttributeData } from 'common/buffer/AttributeData';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
import { CellData } from 'common/buffer/CellData';
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2022 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { IRenderService } from 'browser/services/Services';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
import { CanvasRenderer } from './CanvasRenderer';
|
||||
import { IBufferService, IInstantiationService } from 'common/services/Services';
|
||||
import { ITerminalAddon, Terminal } from 'xterm';
|
||||
|
||||
export class CanvasAddon implements ITerminalAddon {
|
||||
private _terminal?: Terminal;
|
||||
private _renderer?: CanvasRenderer;
|
||||
|
||||
public activate(terminal: Terminal): void {
|
||||
if (!terminal.element) {
|
||||
throw new Error('Cannot activate CanvasAddon before Terminal.open');
|
||||
}
|
||||
this._terminal = terminal;
|
||||
const instantiationService: IInstantiationService = (terminal as any)._core._instantiationService;
|
||||
const bufferService: IBufferService = (terminal as any)._core._renderService;
|
||||
const renderService: IRenderService = (terminal as any)._core._renderService;
|
||||
const colors: IColorSet = (terminal as any)._core._colorManager.colors;
|
||||
const screenElement: HTMLElement = (terminal as any)._core.screenElement;
|
||||
const linkifier = (terminal as any)._core.linkifier2;
|
||||
this._renderer = instantiationService.createInstance(CanvasRenderer, colors, screenElement, linkifier);
|
||||
renderService.setRenderer(this._renderer);
|
||||
renderService.onResize(bufferService.cols, bufferService.rows);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (!this._terminal) {
|
||||
throw new Error('Cannot dispose CanvasAddon because it is activated');
|
||||
}
|
||||
const renderService: IRenderService = (this._terminal as any)._core._renderService;
|
||||
renderService.setRenderer((this._terminal as any)._core._createRenderer());
|
||||
renderService.onResize(this._terminal.cols, this._terminal.rows);
|
||||
this._renderer?.dispose();
|
||||
this._renderer = undefined;
|
||||
}
|
||||
}
|
||||
@@ -3,21 +3,22 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { TextRenderLayer } from 'browser/renderer/TextRenderLayer';
|
||||
import { SelectionRenderLayer } from 'browser/renderer/SelectionRenderLayer';
|
||||
import { CursorRenderLayer } from 'browser/renderer/CursorRenderLayer';
|
||||
import { IRenderLayer, IRenderer, IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/Types';
|
||||
import { LinkRenderLayer } from 'browser/renderer/LinkRenderLayer';
|
||||
import { TextRenderLayer } from './TextRenderLayer';
|
||||
import { SelectionRenderLayer } from './SelectionRenderLayer';
|
||||
import { CursorRenderLayer } from './CursorRenderLayer';
|
||||
import { IRenderer, IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/Types';
|
||||
import { IRenderLayer } from './Types';
|
||||
import { LinkRenderLayer } from './LinkRenderLayer';
|
||||
import { Disposable } from 'common/Lifecycle';
|
||||
import { IColorSet, ILinkifier2 } from 'browser/Types';
|
||||
import { ICharSizeService } from 'browser/services/Services';
|
||||
import { IBufferService, IOptionsService, IInstantiationService } from 'common/services/Services';
|
||||
import { removeTerminalFromCache } from 'browser/renderer/atlas/CharAtlasCache';
|
||||
import { removeTerminalFromCache } from './atlas/CharAtlasCache';
|
||||
import { EventEmitter, IEvent } from 'common/EventEmitter';
|
||||
|
||||
let nextRendererId = 1;
|
||||
|
||||
export class Renderer extends Disposable implements IRenderer {
|
||||
export class CanvasRenderer extends Disposable implements IRenderer {
|
||||
private _id = nextRendererId++;
|
||||
|
||||
private _renderLayers: IRenderLayer[];
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/Types';
|
||||
import { BaseRenderLayer } from 'browser/renderer/BaseRenderLayer';
|
||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||
import { ICellData } from 'common/Types';
|
||||
import { CellData } from 'common/buffer/CellData';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { assert } from 'chai';
|
||||
import { GridCache } from 'browser/renderer/GridCache';
|
||||
import { GridCache } from './GridCache';
|
||||
|
||||
describe('GridCache', () => {
|
||||
let grid: GridCache<number>;
|
||||
+2
-2
@@ -5,8 +5,8 @@
|
||||
|
||||
import { IRenderDimensions } from 'browser/renderer/Types';
|
||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
|
||||
import { is256Color } from 'browser/renderer/atlas/CharAtlasUtils';
|
||||
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/Constants';
|
||||
import { is256Color } from './atlas/CharAtlasUtils';
|
||||
import { IColorSet, ILinkifierEvent, ILinkifier2 } from 'browser/Types';
|
||||
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { IRenderDimensions } from 'browser/renderer/Types';
|
||||
import { BaseRenderLayer } from 'browser/renderer/BaseRenderLayer';
|
||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@
|
||||
|
||||
import { IRenderDimensions } from 'browser/renderer/Types';
|
||||
import { CharData, ICellData } from 'common/Types';
|
||||
import { GridCache } from 'browser/renderer/GridCache';
|
||||
import { BaseRenderLayer } from 'browser/renderer/BaseRenderLayer';
|
||||
import { GridCache } from './GridCache';
|
||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||
import { AttributeData } from 'common/buffer/AttributeData';
|
||||
import { NULL_CELL_CODE, Content } from 'common/buffer/Constants';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { IDisposable } from 'common/Types';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
import { IEvent } from 'common/EventEmitter';
|
||||
|
||||
// TODO: Use core interfaces
|
||||
export interface IRenderDimensions {
|
||||
scaledCharWidth: number;
|
||||
scaledCharHeight: number;
|
||||
scaledCellWidth: number;
|
||||
scaledCellHeight: number;
|
||||
scaledCharLeft: number;
|
||||
scaledCharTop: number;
|
||||
scaledCanvasWidth: number;
|
||||
scaledCanvasHeight: number;
|
||||
canvasWidth: number;
|
||||
canvasHeight: number;
|
||||
actualCellWidth: number;
|
||||
actualCellHeight: number;
|
||||
}
|
||||
|
||||
export interface IRequestRedrawEvent {
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that IRenderer implementations should emit the refresh event after
|
||||
* rendering rows to the screen.
|
||||
*/
|
||||
export interface IRenderer extends IDisposable {
|
||||
readonly dimensions: IRenderDimensions;
|
||||
|
||||
/**
|
||||
* Fires when the renderer is requesting to be redrawn on the next animation
|
||||
* frame but is _not_ a result of content changing (eg. selection changes).
|
||||
*/
|
||||
readonly onRequestRedraw: IEvent<IRequestRedrawEvent>;
|
||||
|
||||
dispose(): void;
|
||||
setColors(colors: IColorSet): void;
|
||||
onDevicePixelRatioChange(): void;
|
||||
onResize(cols: number, rows: number): void;
|
||||
onCharSizeChanged(): void;
|
||||
onBlur(): void;
|
||||
onFocus(): void;
|
||||
onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void;
|
||||
onCursorMove(): void;
|
||||
onOptionsChanged(): void;
|
||||
clear(): void;
|
||||
renderRows(start: number, end: number): void;
|
||||
clearTextureAtlas?(): void;
|
||||
}
|
||||
|
||||
export interface IRenderLayer extends IDisposable {
|
||||
/**
|
||||
* Called when the terminal loses focus.
|
||||
*/
|
||||
onBlur(): void;
|
||||
|
||||
/**
|
||||
* * Called when the terminal gets focus.
|
||||
*/
|
||||
onFocus(): void;
|
||||
|
||||
/**
|
||||
* Called when the cursor is moved.
|
||||
*/
|
||||
onCursorMove(): void;
|
||||
|
||||
/**
|
||||
* Called when options change.
|
||||
*/
|
||||
onOptionsChanged(): void;
|
||||
|
||||
/**
|
||||
* Called when the theme changes.
|
||||
*/
|
||||
setColors(colorSet: IColorSet): void;
|
||||
|
||||
/**
|
||||
* Called when the data in the grid has changed (or needs to be rendered
|
||||
* again).
|
||||
*/
|
||||
onGridChanged(startRow: number, endRow: number): void;
|
||||
|
||||
/**
|
||||
* Calls when the selection changes.
|
||||
*/
|
||||
onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void;
|
||||
|
||||
/**
|
||||
* Resize the render layer.
|
||||
*/
|
||||
resize(dim: IRenderDimensions): void;
|
||||
|
||||
/**
|
||||
* Clear the state of the render layer.
|
||||
*/
|
||||
reset(): void;
|
||||
|
||||
/**
|
||||
* Clears the texture atlas.
|
||||
*/
|
||||
clearTextureAtlas(): void;
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { IGlyphIdentifier } from 'browser/renderer/atlas/Types';
|
||||
import { IGlyphIdentifier } from './Types';
|
||||
import { IDisposable } from 'common/Types';
|
||||
|
||||
export abstract class BaseCharAtlas implements IDisposable {
|
||||
+4
-4
@@ -3,10 +3,10 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { generateConfig, configEquals } from 'browser/renderer/atlas/CharAtlasUtils';
|
||||
import { BaseCharAtlas } from 'browser/renderer/atlas/BaseCharAtlas';
|
||||
import { DynamicCharAtlas } from 'browser/renderer/atlas/DynamicCharAtlas';
|
||||
import { ICharAtlasConfig } from 'browser/renderer/atlas/Types';
|
||||
import { generateConfig, configEquals } from './CharAtlasUtils';
|
||||
import { BaseCharAtlas } from './BaseCharAtlas';
|
||||
import { DynamicCharAtlas } from './DynamicCharAtlas';
|
||||
import { ICharAtlasConfig } from './Types';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
import { ITerminalOptions } from 'common/services/Services';
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { ICharAtlasConfig } from 'browser/renderer/atlas/Types';
|
||||
import { ICharAtlasConfig } from './Types';
|
||||
import { DEFAULT_COLOR } from 'common/buffer/Constants';
|
||||
import { IColorSet, IPartialColorSet } from 'browser/Types';
|
||||
import { ITerminalOptions } from 'common/services/Services';
|
||||
+4
-4
@@ -3,11 +3,11 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, TEXT_BASELINE } from 'browser/renderer/atlas/Constants';
|
||||
import { IGlyphIdentifier, ICharAtlasConfig } from 'browser/renderer/atlas/Types';
|
||||
import { BaseCharAtlas } from 'browser/renderer/atlas/BaseCharAtlas';
|
||||
import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, TEXT_BASELINE } from 'browser/renderer/Constants';
|
||||
import { IGlyphIdentifier, ICharAtlasConfig } from './Types';
|
||||
import { BaseCharAtlas } from './BaseCharAtlas';
|
||||
import { DEFAULT_ANSI_COLORS } from 'browser/ColorManager';
|
||||
import { LRUMap } from 'browser/renderer/atlas/LRUMap';
|
||||
import { LRUMap } from './LRUMap';
|
||||
import { isFirefox, isSafari } from 'common/Platform';
|
||||
import { IColor } from 'common/Types';
|
||||
import { throwIfFalsy } from 'browser/renderer/RendererUtils';
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { assert } from 'chai';
|
||||
import { LRUMap } from 'browser/renderer/atlas/LRUMap';
|
||||
import { LRUMap } from './LRUMap';
|
||||
|
||||
describe('LRUMap', () => {
|
||||
it('can be used to store and retrieve values', () => {
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"es6"
|
||||
],
|
||||
"rootDir": ".",
|
||||
"outDir": "../out",
|
||||
"sourceMap": true,
|
||||
"removeComments": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"common/*": [
|
||||
"../../../src/common/*"
|
||||
],
|
||||
"browser/*": [
|
||||
"../../../src/browser/*"
|
||||
]
|
||||
},
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"types": [
|
||||
"../../../node_modules/@types/mocha"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"./**/*",
|
||||
"../../../typings/xterm.d.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../src/common"
|
||||
},
|
||||
{
|
||||
"path": "../../../src/browser"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{ "path": "./src" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { Terminal, ITerminalAddon, IEvent } from 'xterm';
|
||||
|
||||
declare module 'xterm-addon-canvas' {
|
||||
/**
|
||||
* An xterm.js addon that provides search functionality.
|
||||
*/
|
||||
export class CanvasAddon implements ITerminalAddon {
|
||||
public textureAtlas?: HTMLCanvasElement;
|
||||
|
||||
constructor();
|
||||
|
||||
/**
|
||||
* Activates the addon.
|
||||
* @param terminal The terminal the addon is being loaded in.
|
||||
*/
|
||||
public activate(terminal: Terminal): void;
|
||||
|
||||
/**
|
||||
* Disposes the addon.
|
||||
*/
|
||||
public dispose(): void;
|
||||
|
||||
/**
|
||||
* Clears the terminal's texture atlas and triggers a redraw.
|
||||
*/
|
||||
public clearTextureAtlas(): void;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
|
||||
const addonName = 'CanvasAddon';
|
||||
const mainFile = 'xterm-addon-canvas.js';
|
||||
|
||||
module.exports = {
|
||||
entry: `./out/${addonName}.js`,
|
||||
devtool: 'source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: ["source-map-loader"],
|
||||
enforce: "pre",
|
||||
exclude: /node_modules/
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
modules: ['./node_modules'],
|
||||
extensions: [ '.js' ],
|
||||
alias: {
|
||||
common: path.resolve('../../out/common'),
|
||||
browser: path.resolve('../../out/browser')
|
||||
}
|
||||
},
|
||||
output: {
|
||||
filename: mainFile,
|
||||
path: path.resolve('./lib'),
|
||||
library: addonName,
|
||||
libraryTarget: 'umd'
|
||||
},
|
||||
mode: 'production'
|
||||
};
|
||||
@@ -48,7 +48,8 @@ describe('FitAddon', () => {
|
||||
it('default', async function(): Promise<any> {
|
||||
await loadFit();
|
||||
const dimensions: {cols: number, rows: number} = await page.evaluate(`window.fit.proposeDimensions()`);
|
||||
assert.equal(dimensions.cols, 87);
|
||||
assert.isAbove(dimensions.cols, 85);
|
||||
assert.isBelow(dimensions.cols, 88);
|
||||
assert.isAbove(dimensions.rows, 24);
|
||||
assert.isBelow(dimensions.rows, 29);
|
||||
});
|
||||
@@ -56,7 +57,8 @@ describe('FitAddon', () => {
|
||||
it('width', async function(): Promise<any> {
|
||||
await loadFit(1008);
|
||||
const dimensions: {cols: number, rows: number} = await page.evaluate(`window.fit.proposeDimensions()`);
|
||||
assert.equal(dimensions.cols, 110);
|
||||
assert.isAbove(dimensions.cols, 108);
|
||||
assert.isBelow(dimensions.cols, 111);
|
||||
assert.isAbove(dimensions.rows, 24);
|
||||
assert.isBelow(dimensions.rows, 29);
|
||||
});
|
||||
@@ -89,7 +91,8 @@ describe('FitAddon', () => {
|
||||
await page.evaluate(`window.fit.fit()`);
|
||||
const cols: number = await page.evaluate(`window.term.cols`);
|
||||
const rows: number = await page.evaluate(`window.term.rows`);
|
||||
assert.equal(cols, 87);
|
||||
assert.isAbove(cols, 85);
|
||||
assert.isBelow(cols, 88);
|
||||
assert.isAbove(rows, 24);
|
||||
assert.isBelow(rows, 29);
|
||||
});
|
||||
@@ -99,7 +102,8 @@ describe('FitAddon', () => {
|
||||
await page.evaluate(`window.fit.fit()`);
|
||||
const cols: number = await page.evaluate(`window.term.cols`);
|
||||
const rows: number = await page.evaluate(`window.term.rows`);
|
||||
assert.equal(cols, 110);
|
||||
assert.isAbove(cols, 108);
|
||||
assert.isBelow(cols, 111);
|
||||
assert.isAbove(rows, 24);
|
||||
assert.isBelow(rows, 29);
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ describe('SerializeAddon', () => {
|
||||
page = await (await browser.newContext()).newPage();
|
||||
await page.setViewportSize({ width, height });
|
||||
await page.goto(APP);
|
||||
await openTerminal(page, { rows: 10, cols: 10, rendererType: 'dom' });
|
||||
await openTerminal(page, { rows: 10, cols: 10 });
|
||||
await page.evaluate(`
|
||||
window.serializeAddon = new SerializeAddon();
|
||||
window.term.loadAddon(window.serializeAddon);
|
||||
|
||||
@@ -38,7 +38,7 @@ describe('WebLinksAddon', () => {
|
||||
});
|
||||
|
||||
async function testHostName(hostname: string): Promise<void> {
|
||||
await openTerminal(page, { rendererType: 'dom', cols: 40 });
|
||||
await openTerminal(page, { cols: 40 });
|
||||
await page.evaluate(`window.term.loadAddon(new window.WebLinksAddon())`);
|
||||
const data = ` http://${hostname} \\r\\n` +
|
||||
` http://${hostname}/a~b#c~d?e~f \\r\\n` +
|
||||
|
||||
@@ -16,6 +16,7 @@ import { Terminal } from 'xterm';
|
||||
import { WebglAddon } from 'xterm-addon-webgl';
|
||||
|
||||
const terminal = new Terminal();
|
||||
terminal.open(element);
|
||||
terminal.loadAddon(new WebglAddon());
|
||||
```
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
*/
|
||||
|
||||
import { ICharAtlasConfig } from './Types';
|
||||
import { DIM_OPACITY, TEXT_BASELINE } from 'browser/renderer/atlas/Constants';
|
||||
import { DIM_OPACITY, TEXT_BASELINE } from 'browser/renderer/Constants';
|
||||
import { IRasterizedGlyph, IBoundingBox, IRasterizedGlyphSet } from '../Types';
|
||||
import { DEFAULT_COLOR, Attributes } from 'common/buffer/Constants';
|
||||
import { throwIfFalsy } from '../WebglUtils';
|
||||
import { IColor } from 'common/Types';
|
||||
import { IDisposable } from 'xterm';
|
||||
import { AttributeData } from 'common/buffer/AttributeData';
|
||||
import { channels, color, rgba } from 'common/Color';
|
||||
import { color, rgba } from 'common/Color';
|
||||
import { tryDrawCustomChar } from 'browser/renderer/CustomGlyphs';
|
||||
import { excludeFromContrastRatioDemands, isPowerlineGlyph } from 'browser/renderer/RendererUtils';
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { IRenderLayer } from './Types';
|
||||
import { acquireCharAtlas } from '../atlas/CharAtlasCache';
|
||||
import { Terminal } from 'xterm';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
import { TEXT_BASELINE } from 'browser/renderer/atlas/Constants';
|
||||
import { TEXT_BASELINE } from 'browser/renderer/Constants';
|
||||
import { IRenderDimensions } from 'browser/renderer/Types';
|
||||
import { CellData } from 'common/buffer/CellData';
|
||||
import { WebglCharAtlas } from 'atlas/WebglCharAtlas';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { Terminal } from 'xterm';
|
||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
|
||||
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/Constants';
|
||||
import { is256Color } from '../atlas/CharAtlasUtils';
|
||||
import { ITerminal, IColorSet, ILinkifierEvent } from 'browser/Types';
|
||||
import { IRenderDimensions } from 'browser/renderer/Types';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"es6",
|
||||
"es6"
|
||||
],
|
||||
"rootDir": ".",
|
||||
"outDir": "../out",
|
||||
|
||||
@@ -860,7 +860,7 @@ describe('WebGL Renderer Integration Tests', async () => {
|
||||
|
||||
describe('allowTransparency', async () => {
|
||||
if (areTestsEnabled) {
|
||||
before(async () => setupBrowser({ rendererType: 'dom', allowTransparency: true }));
|
||||
before(async () => setupBrowser({ allowTransparency: true }));
|
||||
after(async () => browser.close());
|
||||
beforeEach(async () => page.evaluate(`window.term.reset()`));
|
||||
}
|
||||
@@ -879,7 +879,7 @@ describe('WebGL Renderer Integration Tests', async () => {
|
||||
|
||||
describe('selectionForeground', () => {
|
||||
if (areTestsEnabled) {
|
||||
before(async () => setupBrowser({ rendererType: 'dom' }));
|
||||
before(async () => setupBrowser());
|
||||
after(async () => browser.close());
|
||||
beforeEach(async () => page.evaluate(`window.term.reset()`));
|
||||
}
|
||||
@@ -898,7 +898,7 @@ describe('WebGL Renderer Integration Tests', async () => {
|
||||
|
||||
describe('decoration color overrides', async () => {
|
||||
if (areTestsEnabled) {
|
||||
before(async () => setupBrowser({ rendererType: 'dom' }));
|
||||
before(async () => setupBrowser());
|
||||
after(async () => browser.close());
|
||||
beforeEach(async () => page.evaluate(`window.term.reset()`));
|
||||
}
|
||||
@@ -1014,7 +1014,7 @@ async function getCellPixels(col: number, row: number): Promise<number[]> {
|
||||
return await page.evaluate(`Array.from(window.result)`);
|
||||
}
|
||||
|
||||
async function setupBrowser(options: ITerminalOptions = { rendererType: 'dom' }): Promise<void> {
|
||||
async function setupBrowser(options: ITerminalOptions = {}): Promise<void> {
|
||||
browser = await launchBrowser();
|
||||
page = await (await browser.newContext()).newPage();
|
||||
await page.setViewportSize({ width, height });
|
||||
|
||||
+8
-4
@@ -10,6 +10,7 @@
|
||||
// Use tsc version (yarn watch)
|
||||
import { Terminal } from '../out/browser/public/Terminal';
|
||||
import { AttachAddon } from '../addons/xterm-addon-attach/out/AttachAddon';
|
||||
import { CanvasAddon } from '../addons/xterm-addon-canvas/out/CanvasAddon';
|
||||
import { FitAddon } from '../addons/xterm-addon-fit/out/FitAddon';
|
||||
import { SearchAddon, ISearchOptions } from '../addons/xterm-addon-search/out/SearchAddon';
|
||||
import { SerializeAddon } from '../addons/xterm-addon-serialize/out/SerializeAddon';
|
||||
@@ -53,13 +54,14 @@ let socketURL;
|
||||
let socket;
|
||||
let pid;
|
||||
|
||||
type AddonType = 'attach' | 'fit' | 'search' | 'serialize' | 'unicode11' | 'web-links' | 'webgl' | 'ligatures';
|
||||
type AddonType = 'attach' | 'canvas' | 'fit' | 'search' | 'serialize' | 'unicode11' | 'web-links' | 'webgl' | 'ligatures';
|
||||
|
||||
interface IDemoAddon<T extends AddonType> {
|
||||
name: T;
|
||||
canChange: boolean;
|
||||
ctor:
|
||||
T extends 'attach' ? typeof AttachAddon :
|
||||
T extends 'canvas' ? typeof CanvasAddon :
|
||||
T extends 'fit' ? typeof FitAddon :
|
||||
T extends 'search' ? typeof SearchAddon :
|
||||
T extends 'serialize' ? typeof SerializeAddon :
|
||||
@@ -69,6 +71,7 @@ interface IDemoAddon<T extends AddonType> {
|
||||
typeof WebglAddon;
|
||||
instance?:
|
||||
T extends 'attach' ? AttachAddon :
|
||||
T extends 'canvas' ? CanvasAddon :
|
||||
T extends 'fit' ? FitAddon :
|
||||
T extends 'search' ? SearchAddon :
|
||||
T extends 'serialize' ? SerializeAddon :
|
||||
@@ -81,6 +84,7 @@ interface IDemoAddon<T extends AddonType> {
|
||||
|
||||
const addons: { [T in AddonType]: IDemoAddon<T>} = {
|
||||
attach: { name: 'attach', ctor: AttachAddon, canChange: false },
|
||||
canvas: { name: 'canvas', ctor: CanvasAddon, canChange: true },
|
||||
fit: { name: 'fit', ctor: FitAddon, canChange: false },
|
||||
search: { name: 'search', ctor: SearchAddon, canChange: true },
|
||||
serialize: { name: 'serialize', ctor: SerializeAddon, canChange: true },
|
||||
@@ -150,6 +154,7 @@ const disposeRecreateButtonHandler = () => {
|
||||
window.term = null;
|
||||
socket = null;
|
||||
addons.attach.instance = undefined;
|
||||
addons.canvas.instance = undefined;
|
||||
addons.fit.instance = undefined;
|
||||
addons.search.instance = undefined;
|
||||
addons.serialize.instance = undefined;
|
||||
@@ -331,7 +336,6 @@ function initOptions(term: TerminalType): void {
|
||||
fontWeight: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
|
||||
fontWeightBold: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
|
||||
logLevel: ['debug', 'info', 'warn', 'error', 'off'],
|
||||
rendererType: ['dom', 'canvas'],
|
||||
theme: ['default', 'xtermjs', 'sapphire', 'light'],
|
||||
wordSeparator: null
|
||||
};
|
||||
@@ -628,7 +632,7 @@ function writeCustomGlyphHandler() {
|
||||
}
|
||||
|
||||
function loadTest() {
|
||||
const isWebglEnabled = !!addons.webgl.instance;
|
||||
const rendererName = addons.webgl.instance ? 'webgl' : !!addons.canvas.instance ? 'canvas' : 'dom';
|
||||
const testData = [];
|
||||
let byteCount = 0;
|
||||
for (let i = 0; i < 50; i++) {
|
||||
@@ -654,7 +658,7 @@ function loadTest() {
|
||||
term.write('', () => {
|
||||
const time = Math.round(performance.now() - start);
|
||||
const mbs = ((byteCount / 1024) * (1 / (time / 1000))).toFixed(2);
|
||||
term.write(`\n\r\nWrote ${byteCount}kB in ${time}ms (${mbs}MB/s) using the (${isWebglEnabled ? 'webgl' : 'canvas'} renderer)`);
|
||||
term.write(`\n\r\nWrote ${byteCount}kB in ${time}ms (${mbs}MB/s) using the (${rendererName} renderer)`);
|
||||
// Send ^C to get a new prompt
|
||||
term._core._onData.fire('\x03');
|
||||
});
|
||||
|
||||
+1
-12
@@ -28,7 +28,6 @@ import { Viewport } from 'browser/Viewport';
|
||||
import { rightClickHandler, moveTextAreaUnderMouseCursor, handlePasteEvent, copyHandler, paste } from 'browser/Clipboard';
|
||||
import { C0, C1_ESCAPED } from 'common/data/EscapeSequences';
|
||||
import { WindowsOptionsReportType } from '../common/InputHandler';
|
||||
import { Renderer } from 'browser/renderer/Renderer';
|
||||
import { SelectionService } from 'browser/services/SelectionService';
|
||||
import * as Browser from 'common/Platform';
|
||||
import { addDisposableDomListener } from 'browser/Lifecycle';
|
||||
@@ -296,12 +295,6 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
||||
this.refresh(0, this.rows - 1);
|
||||
}
|
||||
break;
|
||||
case 'rendererType':
|
||||
if (this._renderService) {
|
||||
this._renderService.setRenderer(this._createRenderer());
|
||||
this._renderService.onResize(this.cols, this.rows);
|
||||
}
|
||||
break;
|
||||
case 'scrollback':
|
||||
this.viewport?.syncScrollArea();
|
||||
break;
|
||||
@@ -615,11 +608,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
||||
}
|
||||
|
||||
private _createRenderer(): IRenderer {
|
||||
switch (this.options.rendererType) {
|
||||
case 'canvas': return this._instantiationService.createInstance(Renderer, this._colorManager!.colors, this.screenElement!, this.linkifier2);
|
||||
case 'dom': return this._instantiationService.createInstance(DomRenderer, this._colorManager!.colors, this.element!, this.screenElement!, this._viewportElement!, this.linkifier2);
|
||||
default: throw new Error(`Unrecognized rendererType "${this.options.rendererType}"`);
|
||||
}
|
||||
return this._instantiationService.createInstance(DomRenderer, this._colorManager!.colors, this.element!, this.screenElement!, this._viewportElement!, this.linkifier2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
import { isFirefox, isLegacyEdge } from 'common/Platform';
|
||||
|
||||
export const INVERTED_DEFAULT_COLOR = 257;
|
||||
|
||||
export const DIM_OPACITY = 0.5;
|
||||
// The text baseline is set conditionally by browser. Using 'ideographic' for Firefox or Legacy Edge would
|
||||
// result in truncated text (Issue 3353). Using 'bottom' for Chrome would result in slightly
|
||||
// unaligned Powerline fonts (PR 3356#issuecomment-850928179).
|
||||
export const TEXT_BASELINE: CanvasTextBaseline = isFirefox || isLegacyEdge ? 'bottom' : 'ideographic';
|
||||
|
||||
export const CHAR_ATLAS_CELL_SPACING = 1;
|
||||
Vendored
-53
@@ -54,56 +54,3 @@ export interface IRenderer extends IDisposable {
|
||||
renderRows(start: number, end: number): void;
|
||||
clearTextureAtlas?(): void;
|
||||
}
|
||||
|
||||
export interface IRenderLayer extends IDisposable {
|
||||
/**
|
||||
* Called when the terminal loses focus.
|
||||
*/
|
||||
onBlur(): void;
|
||||
|
||||
/**
|
||||
* * Called when the terminal gets focus.
|
||||
*/
|
||||
onFocus(): void;
|
||||
|
||||
/**
|
||||
* Called when the cursor is moved.
|
||||
*/
|
||||
onCursorMove(): void;
|
||||
|
||||
/**
|
||||
* Called when options change.
|
||||
*/
|
||||
onOptionsChanged(): void;
|
||||
|
||||
/**
|
||||
* Called when the theme changes.
|
||||
*/
|
||||
setColors(colorSet: IColorSet): void;
|
||||
|
||||
/**
|
||||
* Called when the data in the grid has changed (or needs to be rendered
|
||||
* again).
|
||||
*/
|
||||
onGridChanged(startRow: number, endRow: number): void;
|
||||
|
||||
/**
|
||||
* Calls when the selection changes.
|
||||
*/
|
||||
onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void;
|
||||
|
||||
/**
|
||||
* Resize the render layer.
|
||||
*/
|
||||
resize(dim: IRenderDimensions): void;
|
||||
|
||||
/**
|
||||
* Clear the state of the render layer.
|
||||
*/
|
||||
reset(): void;
|
||||
|
||||
/**
|
||||
* Clears the texture atlas.
|
||||
*/
|
||||
clearTextureAtlas(): void;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { IRenderer, IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/Types';
|
||||
import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from 'browser/renderer/dom/DomRendererRowFactory';
|
||||
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
|
||||
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/Constants';
|
||||
import { Disposable } from 'common/Lifecycle';
|
||||
import { IColorSet, ILinkifierEvent, ILinkifier2 } from 'browser/Types';
|
||||
import { ICharSizeService } from 'browser/services/Services';
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
*/
|
||||
|
||||
import { IBufferLine, ICellData, IColor } from 'common/Types';
|
||||
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
|
||||
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/Constants';
|
||||
import { NULL_CELL_CODE, WHITESPACE_CELL_CHAR, Attributes } from 'common/buffer/Constants';
|
||||
import { CellData } from 'common/buffer/CellData';
|
||||
import { IBufferService, ICoreService, IDecorationService, IOptionsService } from 'common/services/Services';
|
||||
import { ICoreService, IDecorationService, IOptionsService } from 'common/services/Services';
|
||||
import { color, rgba } from 'common/Color';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
import { ICharacterJoinerService, ISelectionService } from 'browser/services/Services';
|
||||
import { ICharacterJoinerService } from 'browser/services/Services';
|
||||
import { JoinedCellData } from 'browser/services/CharacterJoinerService';
|
||||
import { excludeFromContrastRatioDemands } from 'browser/renderer/RendererUtils';
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ export const DEFAULT_OPTIONS: Readonly<ITerminalOptions> = {
|
||||
tabStopWidth: 8,
|
||||
theme: {},
|
||||
rightClickSelectsWord: isMac,
|
||||
rendererType: 'canvas',
|
||||
windowOptions: {},
|
||||
windowsMode: false,
|
||||
wordSeparator: ' ()[]{}\',"`',
|
||||
@@ -120,7 +119,6 @@ export class OptionsService implements IOptionsService {
|
||||
}
|
||||
break;
|
||||
case 'cursorStyle':
|
||||
case 'rendererType':
|
||||
case 'wordSeparator':
|
||||
if (!value) {
|
||||
value = DEFAULT_OPTIONS[key];
|
||||
|
||||
@@ -203,8 +203,6 @@ export interface IOptionsService {
|
||||
export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | number;
|
||||
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'off';
|
||||
|
||||
export type RendererType = 'dom' | 'canvas';
|
||||
|
||||
export interface ITerminalOptions {
|
||||
allowProposedApi: boolean;
|
||||
allowTransparency: boolean;
|
||||
@@ -229,7 +227,6 @@ export interface ITerminalOptions {
|
||||
macOptionIsMeta: boolean;
|
||||
macOptionClickForcesSelection: boolean;
|
||||
minimumContrastRatio: number;
|
||||
rendererType: RendererType;
|
||||
rightClickSelectsWord: boolean;
|
||||
rows: number;
|
||||
screenReaderMode: boolean;
|
||||
|
||||
+11
-18
@@ -157,7 +157,6 @@ describe('API Integration Tests', function(): void {
|
||||
describe('options', () => {
|
||||
it('getter', async () => {
|
||||
await openTerminal(page);
|
||||
assert.equal(await page.evaluate(`window.term.options.rendererType`), 'canvas');
|
||||
assert.equal(await page.evaluate(`window.term.options.cols`), 80);
|
||||
assert.equal(await page.evaluate(`window.term.options.rows`), 24);
|
||||
});
|
||||
@@ -190,7 +189,7 @@ describe('API Integration Tests', function(): void {
|
||||
|
||||
describe('renderer', () => {
|
||||
it('foreground', async () => {
|
||||
await openTerminal(page, { rendererType: 'dom' });
|
||||
await openTerminal(page);
|
||||
await writeSync(page, '\\x1b[30m0\\x1b[31m1\\x1b[32m2\\x1b[33m3\\x1b[34m4\\x1b[35m5\\x1b[36m6\\x1b[37m7');
|
||||
await pollFor(page, `document.querySelectorAll('.xterm-rows > :nth-child(1) > *').length`, 9);
|
||||
assert.deepEqual(await page.evaluate(`
|
||||
@@ -215,7 +214,7 @@ describe('API Integration Tests', function(): void {
|
||||
});
|
||||
|
||||
it('background', async () => {
|
||||
await openTerminal(page, { rendererType: 'dom' });
|
||||
await openTerminal(page);
|
||||
await writeSync(page, '\\x1b[40m0\\x1b[41m1\\x1b[42m2\\x1b[43m3\\x1b[44m4\\x1b[45m5\\x1b[46m6\\x1b[47m7');
|
||||
await pollFor(page, `document.querySelectorAll('.xterm-rows > :nth-child(1) > *').length`, 9);
|
||||
assert.deepEqual(await page.evaluate(`
|
||||
@@ -727,9 +726,7 @@ describe('API Integration Tests', function(): void {
|
||||
describe('registerDecoration', () => {
|
||||
describe('bufferDecorations', () => {
|
||||
it('should register decorations and render them when terminal open is called', async () => {
|
||||
await page.evaluate(`window.term = new Terminal({ allowProposedApi: true })`);
|
||||
await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`);
|
||||
await page.waitForSelector('.xterm-text-layer');
|
||||
await openTerminal(page);
|
||||
await page.evaluate(`window.marker1 = window.term.registerMarker(1)`);
|
||||
await page.evaluate(`window.marker2 = window.term.registerMarker(2)`);
|
||||
await page.evaluate(`window.term.registerDecoration({ marker: window.marker1 })`);
|
||||
@@ -758,9 +755,7 @@ describe('API Integration Tests', function(): void {
|
||||
});
|
||||
describe('overviewRulerDecorations', () => {
|
||||
it('should not add an overview ruler when width is not set', async () => {
|
||||
await page.evaluate(`window.term = new Terminal({ allowProposedApi: true })`);
|
||||
await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`);
|
||||
await page.waitForSelector('.xterm-text-layer');
|
||||
await openTerminal(page);
|
||||
await page.evaluate(`window.marker1 = window.term.registerMarker(1)`);
|
||||
await page.evaluate(`window.marker2 = window.term.registerMarker(2)`);
|
||||
await page.evaluate(`window.term.registerDecoration({ marker: window.marker1, overviewRulerOptions: { color: 'red', position: 'full' } })`);
|
||||
@@ -769,9 +764,7 @@ describe('API Integration Tests', function(): void {
|
||||
await pollFor(page, `document.querySelectorAll('.xterm-decoration-overview-ruler').length`, 0);
|
||||
});
|
||||
it('should add an overview ruler when width is set', async () => {
|
||||
await page.evaluate(`window.term = new Terminal({ allowProposedApi: true, overviewRulerWidth: 15 })`);
|
||||
await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`);
|
||||
await page.waitForSelector('.xterm-text-layer');
|
||||
await openTerminal(page, { overviewRulerWidth: 15 });
|
||||
await page.evaluate(`window.marker1 = window.term.registerMarker(1)`);
|
||||
await page.evaluate(`window.marker2 = window.term.registerMarker(2)`);
|
||||
await page.evaluate(`window.term.registerDecoration({ marker: window.marker1, overviewRulerOptions: { color: 'red', position: 'full' } })`);
|
||||
@@ -784,7 +777,7 @@ describe('API Integration Tests', function(): void {
|
||||
|
||||
describe('registerLinkProvider', () => {
|
||||
it('should fire provideLinks when hovering cells', async () => {
|
||||
await openTerminal(page, { rendererType: 'dom' });
|
||||
await openTerminal(page);
|
||||
// Focus the terminal as the cursor will show and trigger a rerender, which can clear the
|
||||
// active link
|
||||
await page.evaluate('window.term.focus()');
|
||||
@@ -806,7 +799,7 @@ describe('API Integration Tests', function(): void {
|
||||
});
|
||||
|
||||
it('should fire hover and leave events on the link', async () => {
|
||||
await openTerminal(page, { rendererType: 'dom' });
|
||||
await openTerminal(page);
|
||||
// Focus the terminal as the cursor will show and trigger a rerender, which can clear the
|
||||
// active link
|
||||
await page.evaluate('window.term.focus()');
|
||||
@@ -844,7 +837,7 @@ describe('API Integration Tests', function(): void {
|
||||
});
|
||||
|
||||
it('should work fine when hover and leave callbacks are not provided', async () => {
|
||||
await openTerminal(page, { rendererType: 'dom' });
|
||||
await openTerminal(page);
|
||||
// Focus the terminal as the cursor will show and trigger a rerender, which can clear the
|
||||
// active link
|
||||
await page.evaluate('window.term.focus()');
|
||||
@@ -887,7 +880,7 @@ describe('API Integration Tests', function(): void {
|
||||
});
|
||||
|
||||
it('should fire activate events when clicking the link', async () => {
|
||||
await openTerminal(page, { rendererType: 'dom' });
|
||||
await openTerminal(page);
|
||||
// Focus the terminal as the cursor will show and trigger a rerender, which can clear the
|
||||
// active link
|
||||
await page.evaluate('window.term.focus()');
|
||||
@@ -929,7 +922,7 @@ describe('API Integration Tests', function(): void {
|
||||
});
|
||||
|
||||
it('should work when multiple links are provided on the same line', async () => {
|
||||
await openTerminal(page, { rendererType: 'dom' });
|
||||
await openTerminal(page);
|
||||
// Focus the terminal as the cursor will show and trigger a rerender, which can clear the
|
||||
// active link
|
||||
await page.evaluate('window.term.focus()');
|
||||
@@ -978,7 +971,7 @@ describe('API Integration Tests', function(): void {
|
||||
});
|
||||
|
||||
it('should dispose links when hovering away', async () => {
|
||||
await openTerminal(page, { rendererType: 'dom' });
|
||||
await openTerminal(page);
|
||||
// Focus the terminal as the cursor will show and trigger a rerender, which can clear the
|
||||
// active link
|
||||
await page.evaluate('window.term.focus()');
|
||||
|
||||
@@ -46,11 +46,7 @@ export async function timeout(ms: number): Promise<void> {
|
||||
export async function openTerminal(page: playwright.Page, options: ITerminalOptions = {}): Promise<void> {
|
||||
await page.evaluate(`window.term = new Terminal(${JSON.stringify({ allowProposedApi: true, ...options })})`);
|
||||
await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`);
|
||||
if (options.rendererType === 'dom') {
|
||||
await page.waitForSelector('.xterm-rows');
|
||||
} else {
|
||||
await page.waitForSelector('.xterm-text-layer');
|
||||
}
|
||||
await page.waitForSelector('.xterm-rows');
|
||||
}
|
||||
|
||||
export function getBrowserType(): playwright.BrowserType<playwright.WebKitBrowser> | playwright.BrowserType<playwright.ChromiumBrowser> | playwright.BrowserType<playwright.FirefoxBrowser> {
|
||||
@@ -68,7 +64,7 @@ export function getBrowserType(): playwright.BrowserType<playwright.WebKitBrowse
|
||||
return browserType;
|
||||
}
|
||||
|
||||
export function launchBrowser() {
|
||||
export function launchBrowser(): Promise<playwright.Browser> {
|
||||
const browserType = getBrowserType();
|
||||
const options: Record<string, unknown> = {
|
||||
headless: process.argv.includes('--headless')
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
{ "path": "./test/api" },
|
||||
{ "path": "./test/benchmark" },
|
||||
{ "path": "./addons/xterm-addon-attach" },
|
||||
{ "path": "./addons/xterm-addon-canvas" },
|
||||
{ "path": "./addons/xterm-addon-fit" },
|
||||
{ "path": "./addons/xterm-addon-ligatures" },
|
||||
{ "path": "./addons/xterm-addon-search" },
|
||||
|
||||
Vendored
-15
@@ -20,11 +20,6 @@ declare module 'xterm' {
|
||||
*/
|
||||
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'off';
|
||||
|
||||
/**
|
||||
* A string representing a renderer type.
|
||||
*/
|
||||
export type RendererType = 'dom' | 'canvas';
|
||||
|
||||
/**
|
||||
* An object containing start up options for the terminal.
|
||||
*/
|
||||
@@ -176,16 +171,6 @@ declare module 'xterm' {
|
||||
*/
|
||||
minimumContrastRatio?: number;
|
||||
|
||||
/**
|
||||
* The type of renderer to use, this allows using the fallback DOM renderer
|
||||
* when canvas is too slow for the environment. The following features do
|
||||
* not work when the DOM renderer is used:
|
||||
*
|
||||
* - Letter spacing
|
||||
* - Cursor blink
|
||||
*/
|
||||
rendererType?: RendererType;
|
||||
|
||||
/**
|
||||
* Whether to select the word under the cursor on right click, this is
|
||||
* standard behavior in a lot of macOS applications.
|
||||
|
||||
Reference in New Issue
Block a user