Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3504e2ebd5 | ||
|
|
6c22e3df6b | ||
|
|
33bf765b80 | ||
|
|
d960793f0c | ||
|
|
4975f389ff | ||
|
|
4649ad7e7b | ||
|
|
a425c325b7 | ||
|
|
c77025b18c | ||
|
|
c6abc85810 | ||
|
|
710223ab27 | ||
|
|
ca9df42a73 | ||
|
|
9f033cb1d2 | ||
|
|
9613f36280 | ||
|
|
41673f2c20 | ||
|
|
6c98f82ffe | ||
|
|
a90ef52bda | ||
|
|
86884d2d88 | ||
|
|
47c486e1be | ||
|
|
e07b9684bb | ||
|
|
10fb48869e | ||
|
|
9f3746a3a1 | ||
|
|
50fc84f7d7 | ||
|
|
3e0f0331b3 | ||
|
|
b918f0d34a | ||
|
|
f0e3159ece | ||
|
|
ecfc7336c5 | ||
|
|
aec8c68bf6 | ||
|
|
0fb63561fb | ||
|
|
106ea62b4c | ||
|
|
e73bf11849 | ||
|
|
8d9eda5d0a | ||
|
|
cf0b7ce2d0 | ||
|
|
60419a7cc6 | ||
|
|
1b12b2d15d | ||
|
|
b5844990c4 | ||
|
|
2652768310 | ||
|
|
1f8a6bece4 | ||
|
|
8817ddf020 | ||
|
|
5d61956aff | ||
|
|
83ece031a7 | ||
|
|
566fad4108 | ||
|
|
a4aa111eaa | ||
|
|
f6ed184d49 | ||
|
|
c1820501a8 | ||
|
|
c7f50c5c28 | ||
|
|
371c96e1da | ||
|
|
11bd8b7eb1 | ||
|
|
cb418eb8d1 | ||
|
|
f811fb937e | ||
|
|
2a6ccb8009 | ||
|
|
bf49f99810 | ||
|
|
e027a5f97b | ||
|
|
d1ecb571d8 | ||
|
|
1e3937830f | ||
|
|
38b2fcb460 | ||
|
|
c7ed42226f | ||
|
|
d0dfad4c92 | ||
|
|
c66123b91f | ||
|
|
8d912e891e | ||
|
|
23fd6b8e60 | ||
|
|
0320e6e22a | ||
|
|
9e70d8fc84 | ||
|
|
27e28eccac | ||
|
|
0cb0313fc9 | ||
|
|
94a34c3703 | ||
|
|
c04c836f12 | ||
|
|
c5a9d2c52d | ||
|
|
c0050672ab | ||
|
|
705f94518f | ||
|
|
a096217526 | ||
|
|
795768667e | ||
|
|
5e9a8c6321 | ||
|
|
03df0565bd | ||
|
|
3ef6856b36 | ||
|
|
48e9f33263 | ||
|
|
9559dd47da | ||
|
|
ad7f8c303c | ||
|
|
edb7a0edda | ||
|
|
aedcbba211 | ||
|
|
ab63b51681 | ||
|
|
63f5d0c266 | ||
|
|
349ebd3846 | ||
|
|
ce496bc389 | ||
|
|
be1af82ee0 | ||
|
|
11bfb03add | ||
|
|
b89d4b102e | ||
|
|
0abd121653 | ||
|
|
eeb095b095 | ||
|
|
266a289520 | ||
|
|
3c1d6b575a | ||
|
|
bd08862074 | ||
|
|
70e0c0385a | ||
|
|
454cf1fb26 |
@@ -1,16 +0,0 @@
|
|||||||
node_modules/
|
|
||||||
*.swp
|
|
||||||
.lock-wscript
|
|
||||||
lib/
|
|
||||||
Makefile.gyp
|
|
||||||
*.Makefile
|
|
||||||
*.target.gyp.mk
|
|
||||||
*.node
|
|
||||||
example/*.log
|
|
||||||
docs/
|
|
||||||
npm-debug.log
|
|
||||||
/.idea/
|
|
||||||
.env
|
|
||||||
build/
|
|
||||||
.vscode/
|
|
||||||
.git/
|
|
||||||
@@ -40,7 +40,6 @@
|
|||||||
"readonly": "generic"
|
"readonly": "generic"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"@typescript-eslint/class-name-casing": "warn",
|
|
||||||
"@typescript-eslint/consistent-type-definitions": "warn",
|
"@typescript-eslint/consistent-type-definitions": "warn",
|
||||||
"@typescript-eslint/explicit-function-return-type": [
|
"@typescript-eslint/explicit-function-return-type": [
|
||||||
"warn",
|
"warn",
|
||||||
@@ -61,10 +60,6 @@
|
|||||||
"warn",
|
"warn",
|
||||||
2
|
2
|
||||||
],
|
],
|
||||||
"@typescript-eslint/interface-name-prefix": [
|
|
||||||
"warn",
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"@typescript-eslint/member-delimiter-style": [
|
"@typescript-eslint/member-delimiter-style": [
|
||||||
"warn",
|
"warn",
|
||||||
{
|
{
|
||||||
|
|||||||
-19
@@ -1,19 +0,0 @@
|
|||||||
FROM node:12
|
|
||||||
MAINTAINER Paris Kasidiaris <paris@sourcelair.com>
|
|
||||||
|
|
||||||
# Set the working directory
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
|
|
||||||
# Set an entrypoint, to automatically install node modules
|
|
||||||
ENTRYPOINT ["/bin/bash", "-c", "if [[ ! -d node_modules ]]; then npm install; fi; exec \"${@:0}\";"]
|
|
||||||
CMD ["npm", "run", "start"]
|
|
||||||
|
|
||||||
# First, install dependencies to improve layer caching
|
|
||||||
COPY package.json /usr/src/app/
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# Add the code
|
|
||||||
COPY . /usr/src/app
|
|
||||||
|
|
||||||
# Run the tests and build, to make sure everything is working nicely
|
|
||||||
RUN npm run build && npm run test
|
|
||||||
@@ -165,6 +165,9 @@ Xterm.js is used in several world-class applications to provide great terminal e
|
|||||||
- [**DockerStacks**](https://docker-stacks.com/): Local LAMP/LEMP development studio
|
- [**DockerStacks**](https://docker-stacks.com/): Local LAMP/LEMP development studio
|
||||||
- [**Codecademy**](https://codecademy.com/): Uses xterm.js in its courses on Bash.
|
- [**Codecademy**](https://codecademy.com/): Uses xterm.js in its courses on Bash.
|
||||||
- [**Laravel Ssh Web Client**](https://github.com/roke22/Laravel-ssh-client): Laravel server inventory with ssh web client to connect at server using xterm.js
|
- [**Laravel Ssh Web Client**](https://github.com/roke22/Laravel-ssh-client): Laravel server inventory with ssh web client to connect at server using xterm.js
|
||||||
|
- [**Repl.it**](https://repl.it): Collaborative browser based IDE with support for 50+ different languages.
|
||||||
|
- [**TeleType**](https://github.com/akshaykmr/TeleType): cli tool that allows you to share your terminal online conveniently. Show off mad cli-fu, help a colleague, teach, or troubleshoot.
|
||||||
|
- [**Intervue**](https://www.intervue.io): Pair programming for interviews. Multiple programming languages supported, with results displayed by xterm.js.
|
||||||
[And much more...](https://github.com/xtermjs/xterm.js/network/dependents)
|
[And much more...](https://github.com/xtermjs/xterm.js/network/dependents)
|
||||||
|
|
||||||
Do you use xterm.js in your application as well? Please [open a Pull Request](https://github.com/sourcelair/xterm.js/pulls) to include it here. We would love to have it in our list. Note: Please add any new contributions to the end of the list only.
|
Do you use xterm.js in your application as well? Please [open a Pull Request](https://github.com/sourcelair/xterm.js/pulls) to include it here. We would love to have it in our list. Note: Please add any new contributions to the end of the list only.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "xterm-addon-serialize",
|
"name": "xterm-addon-serialize",
|
||||||
"version": "0.3.0",
|
"version": "0.4.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "The xterm.js authors",
|
"name": "The xterm.js authors",
|
||||||
"url": "https://xtermjs.org/"
|
"url": "https://xtermjs.org/"
|
||||||
|
|||||||
@@ -270,6 +270,35 @@ describe('SerializeAddon', () => {
|
|||||||
await writeSync(page, lines.join('\\r\\n'));
|
await writeSync(page, lines.join('\\r\\n'));
|
||||||
assert.equal(await page.evaluate(`serializeAddon.serialize();`), expected.join('\r\n'));
|
assert.equal(await page.evaluate(`serializeAddon.serialize();`), expected.join('\r\n'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('serialize CJK correctly', async () => {
|
||||||
|
const lines = [
|
||||||
|
'中文中文',
|
||||||
|
'12中文',
|
||||||
|
'中文12',
|
||||||
|
'1中文中文中' // this line is going to be wrapped at last character because it has line length of 11 (1+2*5)
|
||||||
|
];
|
||||||
|
const expected = [
|
||||||
|
'中文中文',
|
||||||
|
'12中文',
|
||||||
|
'中文12',
|
||||||
|
'1中文中文',
|
||||||
|
'中'
|
||||||
|
];
|
||||||
|
await writeSync(page, lines.join('\\r\\n'));
|
||||||
|
assert.equal(await page.evaluate(`serializeAddon.serialize();`), expected.join('\r\n'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('serialize CJK Mixed with tab correctly', async () => {
|
||||||
|
const lines = [
|
||||||
|
'中文\t12' // CJK mixed with tab
|
||||||
|
];
|
||||||
|
const expected = [
|
||||||
|
'中文\x1b[4C12'
|
||||||
|
];
|
||||||
|
await writeSync(page, lines.join('\\r\\n'));
|
||||||
|
assert.equal(await page.evaluate(`serializeAddon.serialize();`), expected.join('\r\n'));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function newArray<T>(initial: T | ((index: number) => T), count: number): T[] {
|
function newArray<T>(initial: T | ((index: number) => T), count: number): T[] {
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class StringSerializeHandler extends BaseSerializeHandler {
|
|||||||
// Count number of null cells encountered after the last non-null cell and move the cursor
|
// Count number of null cells encountered after the last non-null cell and move the cursor
|
||||||
// if a non-null cell is found (eg. \t or cursor move)
|
// if a non-null cell is found (eg. \t or cursor move)
|
||||||
if (cell.getChars() === '') {
|
if (cell.getChars() === '') {
|
||||||
this._nullCellCount++;
|
this._nullCellCount += cell.getWidth();
|
||||||
} else if (this._nullCellCount > 0) {
|
} else if (this._nullCellCount > 0) {
|
||||||
this._currentRow += `\x1b[${this._nullCellCount}C`;
|
this._currentRow += `\x1b[${this._nullCellCount}C`;
|
||||||
this._nullCellCount = 0;
|
this._nullCellCount = 0;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "xterm-addon-webgl",
|
"name": "xterm-addon-webgl",
|
||||||
"version": "0.8.0",
|
"version": "0.9.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "The xterm.js authors",
|
"name": "The xterm.js authors",
|
||||||
"url": "https://xtermjs.org/"
|
"url": "https://xtermjs.org/"
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ export class RectangleRenderer {
|
|||||||
} else {
|
} else {
|
||||||
// Draw first row
|
// Draw first row
|
||||||
const startCol = model.viewportStartRow === model.viewportCappedStartRow ? model.startCol : 0;
|
const startCol = model.viewportStartRow === model.viewportCappedStartRow ? model.startCol : 0;
|
||||||
const startRowEndCol = model.viewportCappedStartRow === model.viewportCappedEndRow ? model.endCol : terminal.cols;
|
const startRowEndCol = model.viewportCappedStartRow === model.viewportEndRow ? model.endCol : terminal.cols;
|
||||||
this._addRectangleFloat(
|
this._addRectangleFloat(
|
||||||
this._vertices.selection,
|
this._vertices.selection,
|
||||||
0,
|
0,
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ export class RenderModel implements IRenderModel {
|
|||||||
public clear(): void {
|
public clear(): void {
|
||||||
fill(this.cells, 0, 0);
|
fill(this.cells, 0, 0);
|
||||||
fill(this.lineLengths, 0, 0);
|
fill(this.lineLengths, 0, 0);
|
||||||
this.clearSelection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public clearSelection(): void {
|
public clearSelection(): void {
|
||||||
|
|||||||
@@ -40,4 +40,8 @@ export class WebglAddon implements ITerminalAddon {
|
|||||||
public get textureAtlas(): HTMLCanvasElement | undefined {
|
public get textureAtlas(): HTMLCanvasElement | undefined {
|
||||||
return this._renderer?.textureAtlas;
|
return this._renderer?.textureAtlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public clearTextureAtlas(): void {
|
||||||
|
this._renderer?.clearCharAtlas();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,14 +16,12 @@ let page: Page;
|
|||||||
const width = 800;
|
const width = 800;
|
||||||
const height = 600;
|
const height = 600;
|
||||||
|
|
||||||
let itWebgl: (expectation: string, callback?: (this: Mocha.ITestCallbackContext, done: MochaDone) => any) => Mocha.ITest | void;
|
|
||||||
|
|
||||||
describe('WebGL Renderer Integration Tests', async () => {
|
describe('WebGL Renderer Integration Tests', async () => {
|
||||||
const browserType = getBrowserType();
|
const browserType = getBrowserType();
|
||||||
const isHeadless = process.argv.indexOf('--headless') !== -1;
|
const isHeadless = process.argv.indexOf('--headless') !== -1;
|
||||||
// Firefox works only in non-headless mode https://github.com/microsoft/playwright/issues/1032
|
// Firefox works only in non-headless mode https://github.com/microsoft/playwright/issues/1032
|
||||||
const areTestsEnabled = browserType.name() === 'chromium' || (browserType.name() === 'firefox' && !isHeadless);
|
const areTestsEnabled = browserType.name() === 'chromium' || (browserType.name() === 'firefox' && !isHeadless);
|
||||||
itWebgl = areTestsEnabled ? it : it.skip;
|
const itWebgl = areTestsEnabled ? it : it.skip;
|
||||||
|
|
||||||
itWebgl('dispose removes renderer canvases', async function(): Promise<void> {
|
itWebgl('dispose removes renderer canvases', async function(): Promise<void> {
|
||||||
await setupBrowser();
|
await setupBrowser();
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
|
|
||||||
// Force a full refresh
|
// Force a full refresh
|
||||||
this._model.clear();
|
this._model.clear();
|
||||||
|
this._model.clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onDevicePixelRatioChange(): void {
|
public onDevicePixelRatioChange(): void {
|
||||||
@@ -158,6 +159,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
|
|
||||||
// Force a full refresh
|
// Force a full refresh
|
||||||
this._model.clear();
|
this._model.clear();
|
||||||
|
this._model.clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onCharSizeChanged(): void {
|
public onCharSizeChanged(): void {
|
||||||
@@ -214,6 +216,14 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
this._glyphRenderer.setAtlas(this._charAtlas);
|
this._glyphRenderer.setAtlas(this._charAtlas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public clearCharAtlas(): void {
|
||||||
|
this._charAtlas?.clearTexture();
|
||||||
|
this._model.clear();
|
||||||
|
this._updateModel(0, this._terminal.rows - 1);
|
||||||
|
this._glyphRenderer.updateSelection(this._model);
|
||||||
|
this._onRequestRedraw.fire({ start: 0, end: this._terminal.rows - 1 });
|
||||||
|
}
|
||||||
|
|
||||||
public clear(): void {
|
public clear(): void {
|
||||||
this._renderLayers.forEach(l => l.reset(this._terminal));
|
this._renderLayers.forEach(l => l.reset(this._terminal));
|
||||||
}
|
}
|
||||||
@@ -243,6 +253,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
// Tell renderer the frame is beginning
|
// Tell renderer the frame is beginning
|
||||||
if (this._glyphRenderer.beginFrame()) {
|
if (this._glyphRenderer.beginFrame()) {
|
||||||
this._model.clear();
|
this._model.clear();
|
||||||
|
this._model.clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update model to reflect what's drawn
|
// Update model to reflect what's drawn
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export class WebglCharAtlas implements IDisposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _doWarmUp(): void {
|
private _doWarmUp(): void {
|
||||||
// Pre-fill with ASCII 33-126
|
// Pre-fill with ASCII 33-126
|
||||||
for (let i = 33; i < 126; i++) {
|
for (let i = 33; i < 126; i++) {
|
||||||
const rasterizedGlyph = this._drawToCache(i, DEFAULT_COLOR, DEFAULT_COLOR);
|
const rasterizedGlyph = this._drawToCache(i, DEFAULT_COLOR, DEFAULT_COLOR);
|
||||||
@@ -115,17 +115,26 @@ export class WebglCharAtlas implements IDisposable {
|
|||||||
|
|
||||||
public beginFrame(): boolean {
|
public beginFrame(): boolean {
|
||||||
if (this._currentRowY > TEXTURE_CAPACITY) {
|
if (this._currentRowY > TEXTURE_CAPACITY) {
|
||||||
this._cacheCtx.clearRect(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
this.clearTexture();
|
||||||
this._cacheMap = {};
|
this.warmUp();
|
||||||
this._currentRowHeight = 0;
|
|
||||||
this._currentRowX = 0;
|
|
||||||
this._currentRowY = 0;
|
|
||||||
this._doWarmUp();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public clearTexture(): void {
|
||||||
|
if (this._currentRowX === 0 && this._currentRowY === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._cacheCtx.clearRect(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||||
|
this._cacheMap = {};
|
||||||
|
this._cacheMapCombined = {};
|
||||||
|
this._currentRowHeight = 0;
|
||||||
|
this._currentRowX = 0;
|
||||||
|
this._currentRowY = 0;
|
||||||
|
this._didWarmUp = false;
|
||||||
|
}
|
||||||
|
|
||||||
public getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number): IRasterizedGlyph {
|
public getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number): IRasterizedGlyph {
|
||||||
let rasterizedGlyphSet = this._cacheMapCombined[chars];
|
let rasterizedGlyphSet = this._cacheMapCombined[chars];
|
||||||
if (!rasterizedGlyphSet) {
|
if (!rasterizedGlyphSet) {
|
||||||
|
|||||||
+7
-2
@@ -3,7 +3,7 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Terminal, IDisposable, ITerminalAddon } from 'xterm';
|
import { Terminal, ITerminalAddon } from 'xterm';
|
||||||
|
|
||||||
declare module 'xterm-addon-webgl' {
|
declare module 'xterm-addon-webgl' {
|
||||||
/**
|
/**
|
||||||
@@ -15,7 +15,7 @@ declare module 'xterm-addon-webgl' {
|
|||||||
constructor(preserveDrawingBuffer?: boolean);
|
constructor(preserveDrawingBuffer?: boolean);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activates the addon
|
* Activates the addon.
|
||||||
* @param terminal The terminal the addon is being loaded in.
|
* @param terminal The terminal the addon is being loaded in.
|
||||||
*/
|
*/
|
||||||
public activate(terminal: Terminal): void;
|
public activate(terminal: Terminal): void;
|
||||||
@@ -24,5 +24,10 @@ declare module 'xterm-addon-webgl' {
|
|||||||
* Disposes the addon.
|
* Disposes the addon.
|
||||||
*/
|
*/
|
||||||
public dispose(): void;
|
public dispose(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the terminal's texture atlas and triggers a redraw.
|
||||||
|
*/
|
||||||
|
public clearTextureAtlas(): void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
version: "3"
|
|
||||||
|
|
||||||
services:
|
|
||||||
web:
|
|
||||||
image: xtermjs/xterm.js:latest
|
|
||||||
build: .
|
|
||||||
volumes:
|
|
||||||
- ./:/usr/src/app
|
|
||||||
ports:
|
|
||||||
- ${XTERMJS_PORT:-3000}:3000
|
|
||||||
command: ["npm", "start"]
|
|
||||||
|
|
||||||
watch:
|
|
||||||
build: .
|
|
||||||
volumes:
|
|
||||||
- ./:/usr/src/app
|
|
||||||
command: ["npm", "run", "watch"]
|
|
||||||
+14
-14
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "xterm",
|
"name": "xterm",
|
||||||
"description": "Full xterm terminal, in your browser",
|
"description": "Full xterm terminal, in your browser",
|
||||||
"version": "4.8.0",
|
"version": "4.9.0",
|
||||||
"main": "lib/xterm.js",
|
"main": "lib/xterm.js",
|
||||||
"style": "css/xterm.css",
|
"style": "css/xterm.css",
|
||||||
"types": "typings/xterm.d.ts",
|
"types": "typings/xterm.d.ts",
|
||||||
@@ -36,35 +36,35 @@
|
|||||||
"vtfeatures": "node bin/extract_vtfeatures.js src/**/*.ts src/*.ts"
|
"vtfeatures": "node bin/extract_vtfeatures.js src/**/*.ts src/*.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "^4.2.11",
|
"@types/chai": "^4.2.12",
|
||||||
"@types/debug": "^4.1.5",
|
"@types/debug": "^4.1.5",
|
||||||
"@types/deep-equal": "^1.0.1",
|
"@types/deep-equal": "^1.0.1",
|
||||||
"@types/glob": "^7.1.3",
|
"@types/glob": "^7.1.3",
|
||||||
"@types/jsdom": "^16.2.3",
|
"@types/jsdom": "^16.2.4",
|
||||||
"@types/mocha": "^7.0.2",
|
"@types/mocha": "^8.0.3",
|
||||||
"@types/node": "^10.17.17",
|
"@types/node": "^10.17.17",
|
||||||
"@types/utf8": "^2.1.6",
|
"@types/utf8": "^2.1.6",
|
||||||
"@types/webpack": "^4.41.21",
|
"@types/webpack": "^4.41.22",
|
||||||
"@types/ws": "^7.2.6",
|
"@types/ws": "^7.2.6",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.34.0",
|
"@typescript-eslint/eslint-plugin": "^4.0.0",
|
||||||
"@typescript-eslint/parser": "^2.34.0",
|
"@typescript-eslint/parser": "^3.10.1",
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"deep-equal": "^2.0.3",
|
"deep-equal": "^2.0.3",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^7.8.1",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-ws": "^4.0.0",
|
"express-ws": "^4.0.0",
|
||||||
"glob": "^7.0.5",
|
"glob": "^7.0.5",
|
||||||
"jsdom": "^16.3.0",
|
"jsdom": "^16.4.0",
|
||||||
"mocha": "^8.0.1",
|
"mocha": "^8.1.3",
|
||||||
"mustache": "^4.0.1",
|
"mustache": "^4.0.1",
|
||||||
"node-pty": "^0.9.0",
|
"node-pty": "^0.9.0",
|
||||||
"nyc": "^15.1.0",
|
"nyc": "^15.1.0",
|
||||||
"playwright-core": "^0.11.1",
|
"playwright-core": "^0.11.1",
|
||||||
"source-map-loader": "^1.0.1",
|
"source-map-loader": "^1.1.0",
|
||||||
"ts-loader": "^8.0.0",
|
"ts-loader": "^8.0.3",
|
||||||
"typescript": "3.9",
|
"typescript": "4.0",
|
||||||
"utf8": "^3.0.0",
|
"utf8": "^3.0.0",
|
||||||
"webpack": "^4.43.0",
|
"webpack": "^4.44.1",
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^3.3.12",
|
||||||
"ws": "^7.3.1",
|
"ws": "^7.3.1",
|
||||||
"xterm-benchmark": "^0.1.3"
|
"xterm-benchmark": "^0.1.3"
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export class AccessibilityManager extends Disposable {
|
|||||||
|
|
||||||
this._rowContainer = document.createElement('div');
|
this._rowContainer = document.createElement('div');
|
||||||
this._rowContainer.classList.add('xterm-accessibility-tree');
|
this._rowContainer.classList.add('xterm-accessibility-tree');
|
||||||
this._rowContainer.setAttribute('role', 'list');
|
this._rowContainer.setAttribute('role', 'document');
|
||||||
this._rowElements = [];
|
this._rowElements = [];
|
||||||
for (let i = 0; i < this._terminal.rows; i++) {
|
for (let i = 0; i < this._terminal.rows; i++) {
|
||||||
this._rowElements[i] = this._createAccessibilityTreeNode();
|
this._rowElements[i] = this._createAccessibilityTreeNode();
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ describe('Linkifier', () => {
|
|||||||
bufferService.buffer.lines.push(stringToRow(text));
|
bufferService.buffer.lines.push(stringToRow(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
function assertLinkifiesRow(rowText: string, linkMatcherRegex: RegExp, links: {x: number, length: number}[], done: MochaDone): void {
|
function assertLinkifiesRow(rowText: string, linkMatcherRegex: RegExp, links: {x: number, length: number}[], done: Mocha.Done): void {
|
||||||
addRow(rowText);
|
addRow(rowText);
|
||||||
linkifier.registerLinkMatcher(linkMatcherRegex, () => {});
|
linkifier.registerLinkMatcher(linkMatcherRegex, () => {});
|
||||||
linkifier.linkifyRows();
|
linkifier.linkifyRows();
|
||||||
@@ -76,7 +76,7 @@ describe('Linkifier', () => {
|
|||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function assertLinkifiesMultiLineLink(rowText: string, linkMatcherRegex: RegExp, links: {x1: number, y1: number, x2: number, y2: number}[], done: MochaDone): void {
|
function assertLinkifiesMultiLineLink(rowText: string, linkMatcherRegex: RegExp, links: {x1: number, y1: number, x2: number, y2: number}[], done: Mocha.Done): void {
|
||||||
addRow(rowText);
|
addRow(rowText);
|
||||||
linkifier.registerLinkMatcher(linkMatcherRegex, () => {});
|
linkifier.registerLinkMatcher(linkMatcherRegex, () => {});
|
||||||
linkifier.linkifyRows();
|
linkifier.linkifyRows();
|
||||||
|
|||||||
@@ -125,6 +125,13 @@ export class Linkifier2 extends Disposable implements ILinkifier2 {
|
|||||||
|
|
||||||
private _askForLink(position: IBufferCellPosition, useLineCache: boolean): void {
|
private _askForLink(position: IBufferCellPosition, useLineCache: boolean): void {
|
||||||
if (!this._activeProviderReplies || !useLineCache) {
|
if (!this._activeProviderReplies || !useLineCache) {
|
||||||
|
this._activeProviderReplies?.forEach(reply => {
|
||||||
|
reply?.forEach(linkWithState => {
|
||||||
|
if (linkWithState.link.dispose) {
|
||||||
|
linkWithState.link.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
this._activeProviderReplies = new Map();
|
this._activeProviderReplies = new Map();
|
||||||
this._activeLine = position.y;
|
this._activeLine = position.y;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1042,7 +1042,7 @@ describe('Terminal', () => {
|
|||||||
linkifier.attachToDom({} as any, mouseZoneManager);
|
linkifier.attachToDom({} as any, mouseZoneManager);
|
||||||
});
|
});
|
||||||
|
|
||||||
function assertLinkifiesInTerminal(rowText: string, linkMatcherRegex: RegExp, links: {x1: number, y1: number, x2: number, y2: number}[], done: MochaDone): void {
|
function assertLinkifiesInTerminal(rowText: string, linkMatcherRegex: RegExp, links: {x1: number, y1: number, x2: number, y2: number}[], done: Mocha.Done): void {
|
||||||
terminal.writeSync(rowText);
|
terminal.writeSync(rowText);
|
||||||
linkifier.registerLinkMatcher(linkMatcherRegex, () => {});
|
linkifier.registerLinkMatcher(linkMatcherRegex, () => {});
|
||||||
linkifier.linkifyRows();
|
linkifier.linkifyRows();
|
||||||
|
|||||||
@@ -778,7 +778,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
|||||||
if (!this.viewport!.onWheel(ev)) {
|
if (!this.viewport!.onWheel(ev)) {
|
||||||
return this.cancel(ev);
|
return this.cancel(ev);
|
||||||
}
|
}
|
||||||
}, { passive: true }));
|
}, { passive: false }));
|
||||||
|
|
||||||
this.register(addDisposableDomListener(el, 'touchstart', (ev: TouchEvent) => {
|
this.register(addDisposableDomListener(el, 'touchstart', (ev: TouchEvent) => {
|
||||||
if (this._coreMouseService.areMouseEventsActive) return;
|
if (this._coreMouseService.areMouseEventsActive) return;
|
||||||
@@ -791,7 +791,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
|||||||
if (!this.viewport!.onTouchMove(ev)) {
|
if (!this.viewport!.onTouchMove(ev)) {
|
||||||
return this.cancel(ev);
|
return this.cancel(ev);
|
||||||
}
|
}
|
||||||
}, { passive: true }));
|
}, { passive: false }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
@@ -275,6 +275,7 @@ interface ILink {
|
|||||||
activate(event: MouseEvent, text: string): void;
|
activate(event: MouseEvent, text: string): void;
|
||||||
hover?(event: MouseEvent, text: string): void;
|
hover?(event: MouseEvent, text: string): void;
|
||||||
leave?(event: MouseEvent, text: string): void;
|
leave?(event: MouseEvent, text: string): void;
|
||||||
|
dispose?(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ILinkDecorations {
|
interface ILinkDecorations {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Terminal as ITerminalApi, ITerminalOptions, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBuffer as IBufferApi, IBufferNamespace as IBufferNamespaceApi, IBufferLine as IBufferLineApi, IBufferCell as IBufferCellApi, IParser, IFunctionIdentifier, ILinkProvider, IUnicodeHandling, IUnicodeVersionProvider } from 'xterm';
|
import { Terminal as ITerminalApi, ITerminalOptions, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBuffer as IBufferApi, IBufferNamespace as IBufferNamespaceApi, IBufferLine as IBufferLineApi, IBufferCell as IBufferCellApi, IParser, IFunctionIdentifier, ILinkProvider, IUnicodeHandling, IUnicodeVersionProvider, FontWeight } from 'xterm';
|
||||||
import { ITerminal } from 'browser/Types';
|
import { ITerminal } from 'browser/Types';
|
||||||
import { IBufferLine, ICellData } from 'common/Types';
|
import { IBufferLine, ICellData } from 'common/Types';
|
||||||
import { IBuffer, IBufferSet } from 'common/buffer/Types';
|
import { IBuffer, IBufferSet } from 'common/buffer/Types';
|
||||||
@@ -169,15 +169,16 @@ export class Terminal implements ITerminalApi {
|
|||||||
public paste(data: string): void {
|
public paste(data: string): void {
|
||||||
this._core.paste(data);
|
this._core.paste(data);
|
||||||
}
|
}
|
||||||
public getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'fontWeight' | 'fontWeightBold' | 'logLevel' | 'rendererType' | 'termName' | 'wordSeparator'): string;
|
public getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'logLevel' | 'rendererType' | 'termName' | 'wordSeparator'): string;
|
||||||
public getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'visualBell'): boolean;
|
public getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'visualBell'): boolean;
|
||||||
public getOption(key: 'cols' | 'fontSize' | 'letterSpacing' | 'lineHeight' | 'rows' | 'tabStopWidth' | 'scrollback'): number;
|
public getOption(key: 'cols' | 'fontSize' | 'letterSpacing' | 'lineHeight' | 'rows' | 'tabStopWidth' | 'scrollback'): number;
|
||||||
|
public getOption(key: 'fontWeight' | 'fontWeightBold'): FontWeight;
|
||||||
public getOption(key: string): any;
|
public getOption(key: string): any;
|
||||||
public getOption(key: any): any {
|
public getOption(key: any): any {
|
||||||
return this._core.optionsService.getOption(key);
|
return this._core.optionsService.getOption(key);
|
||||||
}
|
}
|
||||||
public setOption(key: 'bellSound' | 'fontFamily' | 'termName' | 'wordSeparator', value: string): void;
|
public setOption(key: 'bellSound' | 'fontFamily' | 'termName' | 'wordSeparator', value: string): void;
|
||||||
public setOption(key: 'fontWeight' | 'fontWeightBold', value: 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'): void;
|
public setOption(key: 'fontWeight' | 'fontWeightBold', value: 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | number): void;
|
||||||
public setOption(key: 'logLevel', value: 'debug' | 'info' | 'warn' | 'error' | 'off'): void;
|
public setOption(key: 'logLevel', value: 'debug' | 'info' | 'warn' | 'error' | 'off'): void;
|
||||||
public setOption(key: 'bellStyle', value: 'none' | 'visual' | 'sound' | 'both'): void;
|
public setOption(key: 'bellStyle', value: 'none' | 'visual' | 'sound' | 'both'): void;
|
||||||
public setOption(key: 'cursorStyle', value: 'block' | 'underline' | 'bar'): void;
|
public setOption(key: 'cursorStyle', value: 'block' | 'underline' | 'bar'): void;
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ export class SelectionRenderLayer extends BaseRenderLayer {
|
|||||||
|
|
||||||
// No need to draw the selection
|
// No need to draw the selection
|
||||||
if (viewportCappedStartRow >= this._bufferService.rows || viewportCappedEndRow < 0) {
|
if (viewportCappedStartRow >= this._bufferService.rows || viewportCappedEndRow < 0) {
|
||||||
|
this._state.ydisp = this._bufferService.buffer.ydisp;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ export class SelectionRenderLayer extends BaseRenderLayer {
|
|||||||
} else {
|
} else {
|
||||||
// Draw first row
|
// Draw first row
|
||||||
const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;
|
const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;
|
||||||
const startRowEndCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : this._bufferService.cols;
|
const startRowEndCol = viewportCappedStartRow === viewportEndRow ? end[0] : this._bufferService.cols;
|
||||||
this._fillCells(startCol, viewportCappedStartRow, startRowEndCol - startCol, 1);
|
this._fillCells(startCol, viewportCappedStartRow, startRowEndCol - startCol, 1);
|
||||||
|
|
||||||
// Draw middle rows
|
// Draw middle rows
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export abstract class BaseCharAtlas implements IDisposable {
|
|||||||
* Perform any work needed to warm the cache before it can be used. Used by the default
|
* Perform any work needed to warm the cache before it can be used. Used by the default
|
||||||
* implementation of warmUp(), and will only be called once.
|
* implementation of warmUp(), and will only be called once.
|
||||||
*/
|
*/
|
||||||
protected _doWarmUp(): void { }
|
private _doWarmUp(): void { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when we start drawing a new frame.
|
* Called when we start drawing a new frame.
|
||||||
|
|||||||
@@ -306,7 +306,7 @@ export class DomRenderer extends Disposable implements IRenderer {
|
|||||||
} else {
|
} else {
|
||||||
// Draw first row
|
// Draw first row
|
||||||
const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;
|
const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;
|
||||||
const endCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : this._bufferService.cols;
|
const endCol = viewportCappedStartRow === viewportEndRow ? end[0] : this._bufferService.cols;
|
||||||
documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow, startCol, endCol));
|
documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow, startCol, endCol));
|
||||||
// Draw middle rows
|
// Draw middle rows
|
||||||
const middleRowsCount = viewportCappedEndRow - viewportCappedStartRow - 1;
|
const middleRowsCount = viewportCappedEndRow - viewportCappedStartRow - 1;
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export class RenderService extends Disposable implements IRenderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _onIntersectionChange(entry: IntersectionObserverEntry): void {
|
private _onIntersectionChange(entry: IntersectionObserverEntry): void {
|
||||||
this._isPaused = !entry.isIntersecting;
|
this._isPaused = entry.isIntersecting === undefined ? (entry.intersectionRatio === 0) : !entry.isIntersecting;
|
||||||
if (!this._isPaused && this._needsFullRefresh) {
|
if (!this._isPaused && this._needsFullRefresh) {
|
||||||
this.refreshRows(0, this._rowCount - 1);
|
this.refreshRows(0, this._rowCount - 1);
|
||||||
this._needsFullRefresh = false;
|
this._needsFullRefresh = false;
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2020 The xterm.js authors. All rights reserved.
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { assert } from 'chai';
|
||||||
|
import { OptionsService, DEFAULT_OPTIONS } from 'common/services/OptionsService';
|
||||||
|
|
||||||
|
describe('OptionsService', () => {
|
||||||
|
describe('constructor', () => {
|
||||||
|
const originalError = console.error;
|
||||||
|
beforeEach(() => {
|
||||||
|
console.error = () => {};
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
console.error = originalError;
|
||||||
|
});
|
||||||
|
it('uses default value if invalid constructor option value passed', () => {
|
||||||
|
assert.equal(new OptionsService({tabStopWidth: 0}).getOption('tabStopWidth'), DEFAULT_OPTIONS.tabStopWidth);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('setOption', () => {
|
||||||
|
let service: OptionsService;
|
||||||
|
beforeEach(() => {
|
||||||
|
service = new OptionsService({});
|
||||||
|
});
|
||||||
|
it('applies valid fontWeight option values', () => {
|
||||||
|
service.setOption('fontWeight', 'bold');
|
||||||
|
assert.equal(service.getOption('fontWeight'), 'bold', '"bold" keyword value should be applied');
|
||||||
|
|
||||||
|
service.setOption('fontWeight', 'normal');
|
||||||
|
assert.equal(service.getOption('fontWeight'), 'normal', '"normal" keyword value should be applied');
|
||||||
|
|
||||||
|
service.setOption('fontWeight', '600');
|
||||||
|
assert.equal(service.getOption('fontWeight'), '600', 'String numeric values should be applied');
|
||||||
|
|
||||||
|
service.setOption('fontWeight', 350);
|
||||||
|
assert.equal(service.getOption('fontWeight'), 350, 'Values between 1 and 1000 should be applied as is');
|
||||||
|
|
||||||
|
service.setOption('fontWeight', 1);
|
||||||
|
assert.equal(service.getOption('fontWeight'), 1, 'Range should include minimum value: 1');
|
||||||
|
|
||||||
|
service.setOption('fontWeight', 1000);
|
||||||
|
assert.equal(service.getOption('fontWeight'), 1000, 'Range should include maximum value: 1000');
|
||||||
|
});
|
||||||
|
it('normalizes invalid fontWeight option values', () => {
|
||||||
|
service.setOption('fontWeight', 350);
|
||||||
|
assert.doesNotThrow(() => service.setOption('fontWeight', 10000), 'fontWeight should be normalized instead of throwing');
|
||||||
|
assert.equal(service.getOption('fontWeight'), DEFAULT_OPTIONS.fontWeight, 'Values greater than 1000 should be reset to default');
|
||||||
|
|
||||||
|
service.setOption('fontWeight', 350);
|
||||||
|
service.setOption('fontWeight', -10);
|
||||||
|
assert.equal(service.getOption('fontWeight'), DEFAULT_OPTIONS.fontWeight, 'Values less than 1 should be reset to default');
|
||||||
|
|
||||||
|
service.setOption('fontWeight', 350);
|
||||||
|
service.setOption('fontWeight', 'bold700');
|
||||||
|
assert.equal(service.getOption('fontWeight'), DEFAULT_OPTIONS.fontWeight, 'Wrong string literals should be reset to default');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IOptionsService, ITerminalOptions, IPartialTerminalOptions } from 'common/services/Services';
|
import { IOptionsService, ITerminalOptions, IPartialTerminalOptions, FontWeight } from 'common/services/Services';
|
||||||
import { EventEmitter, IEvent } from 'common/EventEmitter';
|
import { EventEmitter, IEvent } from 'common/EventEmitter';
|
||||||
import { isMac } from 'common/Platform';
|
import { isMac } from 'common/Platform';
|
||||||
import { clone } from 'common/Clone';
|
import { clone } from 'common/Clone';
|
||||||
@@ -56,6 +56,8 @@ export const DEFAULT_OPTIONS: ITerminalOptions = Object.freeze({
|
|||||||
cancelEvents: false
|
cancelEvents: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const FONT_WEIGHT_OPTIONS: Extract<FontWeight, string>[] = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The set of options that only have an effect when set in the Terminal constructor.
|
* The set of options that only have an effect when set in the Terminal constructor.
|
||||||
*/
|
*/
|
||||||
@@ -73,8 +75,12 @@ export class OptionsService implements IOptionsService {
|
|||||||
this.options = clone(DEFAULT_OPTIONS);
|
this.options = clone(DEFAULT_OPTIONS);
|
||||||
for (const k of Object.keys(options)) {
|
for (const k of Object.keys(options)) {
|
||||||
if (k in this.options) {
|
if (k in this.options) {
|
||||||
const newValue = options[k as keyof IPartialTerminalOptions] as any;
|
try {
|
||||||
this.options[k] = newValue;
|
const newValue = options[k as keyof IPartialTerminalOptions] as any;
|
||||||
|
this.options[k] = this._sanitizeAndValidateOption(k, newValue);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,14 +111,20 @@ export class OptionsService implements IOptionsService {
|
|||||||
switch (key) {
|
switch (key) {
|
||||||
case 'bellStyle':
|
case 'bellStyle':
|
||||||
case 'cursorStyle':
|
case 'cursorStyle':
|
||||||
case 'fontWeight':
|
|
||||||
case 'fontWeightBold':
|
|
||||||
case 'rendererType':
|
case 'rendererType':
|
||||||
case 'wordSeparator':
|
case 'wordSeparator':
|
||||||
if (!value) {
|
if (!value) {
|
||||||
value = DEFAULT_OPTIONS[key];
|
value = DEFAULT_OPTIONS[key];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'fontWeight':
|
||||||
|
case 'fontWeightBold':
|
||||||
|
if (typeof value === 'number' && 1 <= value && value <= 1000) {
|
||||||
|
// already valid numeric value
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value = FONT_WEIGHT_OPTIONS.indexOf(value) !== -1 ? value : DEFAULT_OPTIONS[key];
|
||||||
|
break;
|
||||||
case 'cursorWidth':
|
case 'cursorWidth':
|
||||||
value = Math.floor(value);
|
value = Math.floor(value);
|
||||||
// Fall through for bounds check
|
// Fall through for bounds check
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ export interface IOptionsService {
|
|||||||
getOption<T>(key: string): T | undefined;
|
getOption<T>(key: string): T | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';
|
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 LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'off';
|
||||||
export type RendererType = 'dom' | 'canvas';
|
export type RendererType = 'dom' | 'canvas';
|
||||||
|
|
||||||
|
|||||||
@@ -755,6 +755,57 @@ describe('API Integration Tests', function(): void {
|
|||||||
await pollFor(page, `window.calls`, ['provide 1', 'hover 1-3', 'leave 1-3', 'hover 5-7', 'leave 5-7', 'provide 2', 'provide 1', 'hover 9-11']);
|
await pollFor(page, `window.calls`, ['provide 1', 'hover 1-3', 'leave 1-3', 'hover 5-7', 'leave 5-7', 'provide 2', 'provide 1', 'hover 9-11']);
|
||||||
await page.evaluate(`window.disposable.dispose()`);
|
await page.evaluate(`window.disposable.dispose()`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should dispose links when hovering away', async () => {
|
||||||
|
await openTerminal(page, { rendererType: 'dom' });
|
||||||
|
await writeSync(page, 'foo bar baz');
|
||||||
|
// Wait for renderer to catch up as links are cleared on render
|
||||||
|
await pollFor(page, `document.querySelector('.xterm-rows').textContent`, 'foo bar baz ');
|
||||||
|
await page.evaluate(`
|
||||||
|
window.calls = [];
|
||||||
|
window.disposable = window.term.registerLinkProvider({
|
||||||
|
provideLinks: (position, cb) => {
|
||||||
|
window.calls.push('provide ' + position);
|
||||||
|
if (position === 1) {
|
||||||
|
cb([{
|
||||||
|
range: { start: { x: 1, y: 1 }, end: { x: 3, y: 1 } },
|
||||||
|
text: '',
|
||||||
|
activate: () => window.calls.push('activate'),
|
||||||
|
dispose: () => window.calls.push('dispose 1-3'),
|
||||||
|
hover: () => window.calls.push('hover 1-3'),
|
||||||
|
leave: () => window.calls.push('leave 1-3')
|
||||||
|
}, {
|
||||||
|
range: { start: { x: 5, y: 1 }, end: { x: 7, y: 1 } },
|
||||||
|
text: '',
|
||||||
|
activate: () => window.calls.push('activate'),
|
||||||
|
dispose: () => window.calls.push('dispose 5-7'),
|
||||||
|
hover: () => window.calls.push('hover 5-7'),
|
||||||
|
leave: () => window.calls.push('leave 5-7')
|
||||||
|
}, {
|
||||||
|
range: { start: { x: 9, y: 1 }, end: { x: 11, y: 1 } },
|
||||||
|
text: '',
|
||||||
|
activate: () => window.calls.push('activate'),
|
||||||
|
dispose: () => window.calls.push('dispose 9-11'),
|
||||||
|
hover: () => window.calls.push('hover 9-11'),
|
||||||
|
leave: () => window.calls.push('leave 9-11')
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
`);
|
||||||
|
const dims = await getDimensions();
|
||||||
|
await moveMouseCell(page, dims, 2, 1);
|
||||||
|
await pollFor(page, `window.calls`, ['provide 1', 'hover 1-3']);
|
||||||
|
await moveMouseCell(page, dims, 6, 1);
|
||||||
|
await pollFor(page, `window.calls`, ['provide 1', 'hover 1-3', 'leave 1-3', 'hover 5-7']);
|
||||||
|
await moveMouseCell(page, dims, 6, 2);
|
||||||
|
await pollFor(page, `window.calls`, ['provide 1', 'hover 1-3', 'leave 1-3', 'hover 5-7', 'leave 5-7', 'dispose 1-3', 'dispose 5-7', 'dispose 9-11', 'provide 2']);
|
||||||
|
await moveMouseCell(page, dims, 10, 1);
|
||||||
|
await pollFor(page, `window.calls`, ['provide 1', 'hover 1-3', 'leave 1-3', 'hover 5-7', 'leave 5-7', 'dispose 1-3', 'dispose 5-7', 'dispose 9-11', 'provide 2', 'provide 1', 'hover 9-11']);
|
||||||
|
await moveMouseCell(page, dims, 10, 2);
|
||||||
|
await pollFor(page, `window.calls`, ['provide 1', 'hover 1-3', 'leave 1-3', 'hover 5-7', 'leave 5-7', 'dispose 1-3', 'dispose 5-7', 'dispose 9-11', 'provide 2', 'provide 1', 'hover 9-11', 'leave 9-11', 'dispose 1-3', 'dispose 5-7', 'dispose 9-11', 'provide 2']);
|
||||||
|
await page.evaluate(`window.disposable.dispose()`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Vendored
+14
-4
@@ -11,9 +11,9 @@
|
|||||||
|
|
||||||
declare module 'xterm' {
|
declare module 'xterm' {
|
||||||
/**
|
/**
|
||||||
* A string representing text font weight.
|
* A string or number representing text font weight.
|
||||||
*/
|
*/
|
||||||
export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';
|
export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A string representing log level.
|
* A string representing log level.
|
||||||
@@ -933,7 +933,7 @@ declare module 'xterm' {
|
|||||||
* Retrieves an option's value from the terminal.
|
* Retrieves an option's value from the terminal.
|
||||||
* @param key The option key.
|
* @param key The option key.
|
||||||
*/
|
*/
|
||||||
getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'fontWeight' | 'fontWeightBold' | 'logLevel' | 'rendererType' | 'termName' | 'wordSeparator'): string;
|
getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'logLevel' | 'rendererType' | 'termName' | 'wordSeparator'): string;
|
||||||
/**
|
/**
|
||||||
* Retrieves an option's value from the terminal.
|
* Retrieves an option's value from the terminal.
|
||||||
* @param key The option key.
|
* @param key The option key.
|
||||||
@@ -944,6 +944,11 @@ declare module 'xterm' {
|
|||||||
* @param key The option key.
|
* @param key The option key.
|
||||||
*/
|
*/
|
||||||
getOption(key: 'cols' | 'fontSize' | 'letterSpacing' | 'lineHeight' | 'rows' | 'tabStopWidth' | 'scrollback'): number;
|
getOption(key: 'cols' | 'fontSize' | 'letterSpacing' | 'lineHeight' | 'rows' | 'tabStopWidth' | 'scrollback'): number;
|
||||||
|
/**
|
||||||
|
* Retrieves an option's value from the terminal.
|
||||||
|
* @param key The option key.
|
||||||
|
*/
|
||||||
|
getOption(key: 'fontWeight' | 'fontWeightBold'): FontWeight;
|
||||||
/**
|
/**
|
||||||
* Retrieves an option's value from the terminal.
|
* Retrieves an option's value from the terminal.
|
||||||
* @param key The option key.
|
* @param key The option key.
|
||||||
@@ -961,7 +966,7 @@ declare module 'xterm' {
|
|||||||
* @param key The option key.
|
* @param key The option key.
|
||||||
* @param value The option value.
|
* @param value The option value.
|
||||||
*/
|
*/
|
||||||
setOption(key: 'fontWeight' | 'fontWeightBold', value: null | 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'): void;
|
setOption(key: 'fontWeight' | 'fontWeightBold', value: null | 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | number): void;
|
||||||
/**
|
/**
|
||||||
* Sets an option on the terminal.
|
* Sets an option on the terminal.
|
||||||
* @param key The option key.
|
* @param key The option key.
|
||||||
@@ -1158,6 +1163,11 @@ declare module 'xterm' {
|
|||||||
* @param text The text of the link.
|
* @param text The text of the link.
|
||||||
*/
|
*/
|
||||||
leave?(event: MouseEvent, text: string): void;
|
leave?(event: MouseEvent, text: string): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the link is released and no longer used by xterm.js.
|
||||||
|
*/
|
||||||
|
dispose?(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user