Merge branch 'master' into 682_url_selector

This commit is contained in:
Daniel Imms
2021-03-30 05:34:38 -07:00
committed by GitHub
42 changed files with 2829 additions and 1131 deletions
+1
View File
@@ -172,6 +172,7 @@ Xterm.js is used in several world-class applications to provide great terminal e
- [**Commas**](https://github.com/CyanSalt/commas): Commas is a hackable terminal and command runner.
- [**Devtron**](https://github.com/devtron-labs/devtron): Software Delivery Workflow For Kubernetes.
- [**NxShell**](https://github.com/nxshell/nxshell): An easy to use new terminal for SSH.
- [**gifcast**](https://dstein64.github.io/gifcast/): Converts an asciinema cast to an animated GIF.
[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.
+3 -1
View File
@@ -41,7 +41,9 @@ export class AttachAddon implements ITerminalAddon {
}
public dispose(): void {
this._disposables.forEach(d => d.dispose());
for (const d of this._disposables) {
d.dispose();
}
}
private _sendData(data: string): void {
@@ -18,7 +18,7 @@ describe('AttachAddon', () => {
before(async function(): Promise<any> {
const browserType = getBrowserType();
browser = await browserType.launch({
headless: process.argv.indexOf('--headless') !== -1
headless: process.argv.includes('--headless')
});
page = await (await browser.newContext()).newPage();
await page.setViewportSize({ width, height });
+3 -3
View File
@@ -18,7 +18,7 @@ describe('FitAddon', () => {
before(async function(): Promise<any> {
const browserType = getBrowserType();
browser = await browserType.launch({
headless: process.argv.indexOf('--headless') !== -1
headless: process.argv.includes('--headless')
});
page = await (await browser.newContext()).newPage();
await page.setViewportSize({ width, height });
@@ -45,7 +45,7 @@ describe('FitAddon', () => {
describe('proposeDimensions', () => {
afterEach(async () => {
return unloadFit();
return await unloadFit();
});
it('default', async function(): Promise<any> {
@@ -84,7 +84,7 @@ describe('FitAddon', () => {
describe('fit', () => {
afterEach(async () => {
return unloadFit();
return await unloadFit();
});
it('default', async function(): Promise<any> {
+3 -3
View File
@@ -68,7 +68,7 @@ function parseString(context: IParseContext, quoteChar: '\'' | '"'): string {
while (context.offset < context.input.length) {
const char = context.input[context.offset++];
if (escaped) {
if (/[0-9a-fA-F]/.test(char)) {
if (/[\dA-Fa-f]/.test(char)) {
// Unicode escape
context.offset--;
str += parseUnicode(context);
@@ -107,7 +107,7 @@ function parseIdentifier(context: IParseContext): string {
while (context.offset < context.input.length) {
const char = context.input[context.offset++];
if (escaped) {
if (/[0-9a-fA-F]/.test(char)) {
if (/[\dA-Fa-f]/.test(char)) {
// Unicode escape
context.offset--;
str += parseUnicode(context);
@@ -156,7 +156,7 @@ function parseUnicode(context: IParseContext): string {
// of the escape and is swallowed.
return unicodeToString(str);
}
if (str.length >= 6 || !/[0-9a-fA-F]/.test(char)) {
if (str.length >= 6 || !/[\dA-Fa-f]/.test(char)) {
// If the next character is not a valid hex digit or we have reached the
// maximum of 6 digits in the escape, terminate the escape.
context.offset--;
+3 -3
View File
@@ -240,8 +240,8 @@ export class SearchAddon implements ITerminalAddon {
* @param term the substring that starts at searchIndex
*/
private _isWholeWord(searchIndex: number, line: string, term: string): boolean {
return (((searchIndex === 0) || (NON_WORD_CHARACTERS.indexOf(line[searchIndex - 1]) !== -1)) &&
(((searchIndex + term.length) === line.length) || (NON_WORD_CHARACTERS.indexOf(line[searchIndex + term.length]) !== -1)));
return ((searchIndex === 0) || (NON_WORD_CHARACTERS.includes(line[searchIndex - 1]))) &&
(((searchIndex + term.length) === line.length) || (NON_WORD_CHARACTERS.includes(line[searchIndex + term.length])));
}
/**
@@ -262,7 +262,7 @@ export class SearchAddon implements ITerminalAddon {
// Ignore wrapped lines, only consider on unwrapped line (first row of command string).
const firstLine = terminal.buffer.active.getLine(row);
if (firstLine && firstLine.isWrapped) {
if (firstLine?.isWrapped) {
if (isReverseSearch) {
searchPosition.startCol += terminal.cols;
return;
@@ -20,7 +20,7 @@ describe('Search Tests', function(): void {
before(async function(): Promise<any> {
const browserType = getBrowserType();
browser = await browserType.launch({
headless: process.argv.indexOf('--headless') !== -1
headless: process.argv.includes('--headless')
});
page = await (await browser.newContext()).newPage();
await page.setViewportSize({ width, height });
@@ -34,7 +34,7 @@ describe('SerializeAddon', () => {
before(async function(): Promise<any> {
const browserType = getBrowserType();
browser = await browserType.launch({
headless: process.argv.indexOf('--headless') !== -1
headless: process.argv.includes('--headless')
});
page = await (await browser.newContext()).newPage();
await page.setViewportSize({ width, height });
@@ -18,7 +18,7 @@ describe('Unicode11Addon', () => {
before(async function(): Promise<any> {
const browserType = getBrowserType();
browser = await browserType.launch({
headless: process.argv.indexOf('--headless') !== -1
headless: process.argv.includes('--headless')
});
page = await (await browser.newContext()).newPage();
await page.setViewportSize({ width, height });
@@ -41,7 +41,7 @@ export class WebLinkProvider implements ILinkProvider {
}
export class LinkComputer {
public static computeLink(y: number, regex: RegExp, terminal: Terminal, handler: (event: MouseEvent, uri: string) => void): ILink[] {
public static computeLink(y: number, regex: RegExp, terminal: Terminal, activate: (event: MouseEvent, uri: string) => void): ILink[] {
const rex = new RegExp(regex.source, (regex.flags || '') + 'g');
const [line, startLineIndex] = LinkComputer._translateBufferLineToStringWithWrap(y - 1, false, terminal);
@@ -89,7 +89,7 @@ export class LinkComputer {
}
};
result.push({ range, text, activate: handler });
result.push({ range, text, activate });
}
return result;
@@ -18,7 +18,7 @@ describe('WebLinksAddon', () => {
before(async function(): Promise<any> {
const browserType = getBrowserType();
browser = await browserType.launch({
headless: process.argv.indexOf('--headless') !== -1
headless: process.argv.includes('--headless')
});
page = await (await browser.newContext()).newPage();
await page.setViewportSize({ width, height });
+1 -3
View File
@@ -1,8 +1,6 @@
## xterm-addon-webgl
An addon for [xterm.js](https://github.com/xtermjs/xterm.js) that enables a WebGL-based renderer. This addon requires xterm.js v4+.
⚠️ This is an experimental addon that is [missing some features and may be unstable](https://github.com/xtermjs/xterm.js/issues?q=is%3Aopen+is%3Aissue+label%3Aarea%2Faddon%2Fwebgl) ⚠️
An addon for [xterm.js](https://github.com/xtermjs/xterm.js) that enables a WebGL2-based renderer. This addon requires xterm.js v4+.
### Install
+29 -11
View File
@@ -94,7 +94,9 @@ export class WebglRenderer extends Disposable implements IRenderer {
}
public dispose(): void {
this._renderLayers.forEach(l => l.dispose());
for (const l of this._renderLayers) {
l.dispose();
}
this._core.screenElement!.removeChild(this._canvas);
super.dispose();
}
@@ -106,10 +108,10 @@ export class WebglRenderer extends Disposable implements IRenderer {
public setColors(colors: IColorSet): void {
this._colors = colors;
// Clear layers and force a full render
this._renderLayers.forEach(l => {
for (const l of this._renderLayers) {
l.setColors(this._terminal, this._colors);
l.reset(this._terminal);
});
}
this._rectangleRenderer.setColors();
this._glyphRenderer.setColors();
@@ -136,7 +138,9 @@ export class WebglRenderer extends Disposable implements IRenderer {
this._model.resize(this._terminal.cols, this._terminal.rows);
// Resize all render layers
this._renderLayers.forEach(l => l.resize(this._terminal, this.dimensions));
for (const l of this._renderLayers) {
l.resize(this._terminal, this.dimensions);
}
// Resize the canvas
this._canvas.width = this.dimensions.scaledCanvasWidth;
@@ -168,15 +172,21 @@ export class WebglRenderer extends Disposable implements IRenderer {
}
public onBlur(): void {
this._renderLayers.forEach(l => l.onBlur(this._terminal));
for (const l of this._renderLayers) {
l.onBlur(this._terminal);
}
}
public onFocus(): void {
this._renderLayers.forEach(l => l.onFocus(this._terminal));
for (const l of this._renderLayers) {
l.onFocus(this._terminal);
}
}
public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void {
this._renderLayers.forEach(l => l.onSelectionChanged(this._terminal, start, end, columnSelectMode));
for (const l of this._renderLayers) {
l.onSelectionChanged(this._terminal, start, end, columnSelectMode);
}
this._updateSelectionModel(start, end, columnSelectMode);
@@ -184,11 +194,15 @@ export class WebglRenderer extends Disposable implements IRenderer {
}
public onCursorMove(): void {
this._renderLayers.forEach(l => l.onCursorMove(this._terminal));
for (const l of this._renderLayers) {
l.onCursorMove(this._terminal);
}
}
public onOptionsChanged(): void {
this._renderLayers.forEach(l => l.onOptionsChanged(this._terminal));
for (const l of this._renderLayers) {
l.onOptionsChanged(this._terminal);
}
this._updateDimensions();
this._refreshCharAtlas();
}
@@ -222,7 +236,9 @@ export class WebglRenderer extends Disposable implements IRenderer {
}
public clear(): void {
this._renderLayers.forEach(l => l.reset(this._terminal));
for (const l of this._renderLayers) {
l.reset(this._terminal);
}
}
public registerCharacterJoiner(handler: (text: string) => [number, number][]): number {
@@ -245,7 +261,9 @@ export class WebglRenderer extends Disposable implements IRenderer {
}
// Update render layers
this._renderLayers.forEach(l => l.onGridChanged(this._terminal, start, end));
for (const l of this._renderLayers) {
l.onGridChanged(this._terminal, start, end);
}
// Tell renderer the frame is beginning
if (this._glyphRenderer.beginFrame()) {
@@ -18,7 +18,7 @@ const height = 600;
describe('WebGL Renderer Integration Tests', async () => {
const browserType = getBrowserType();
const isHeadless = process.argv.indexOf('--headless') !== -1;
const isHeadless = process.argv.includes('--headless');
// Firefox works only in non-headless mode https://github.com/microsoft/playwright/issues/1032
const areTestsEnabled = browserType.name() === 'chromium' || (browserType.name() === 'firefox' && !isHeadless);
const itWebgl = areTestsEnabled ? it : it.skip;
@@ -893,7 +893,7 @@ async function getCellColor(col: number, row: number): Promise<number[]> {
async function setupBrowser(options: ITerminalOptions = { rendererType: 'dom' }): Promise<void> {
const browserType = getBrowserType();
browser = await browserType.launch({
headless: process.argv.indexOf('--headless') !== -1
headless: process.argv.includes('--headless')
});
page = await (await browser.newContext()).newPage();
await page.setViewportSize({ width, height });
+1 -3
View File
@@ -156,9 +156,7 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager {
private _onTooltip(e: MouseEvent): void {
this._tooltipTimeout = undefined;
const zone = this._findZoneEventAt(e);
if (zone && zone.tooltipCallback) {
zone.tooltipCallback(e);
}
zone?.tooltipCallback(e);
}
private _onMouseDown(e: MouseEvent): void {
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -162,11 +162,11 @@ export class Terminal extends CoreTerminal implements ITerminal {
private _changeAnsiColor(event: IAnsiColorChangeEvent): void {
if (!this._colorManager) { return; }
event.colors.forEach(ansiColor => {
for (const ansiColor of event.colors) {
const color = rgba.toColor(ansiColor.red, ansiColor.green, ansiColor.blue);
this._colorManager!.colors.ansi[ansiColor.colorIndex] = color;
});
}
this._renderService?.setColors(this._colorManager!.colors);
this.viewport?.onThemeChange(this._colorManager!.colors);
@@ -836,7 +836,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
* Change the cursor style for different selection modes
*/
public updateCursorStyle(ev: KeyboardEvent): void {
if (this._selectionService && this._selectionService.shouldColumnSelect(ev)) {
if (this._selectionService?.shouldColumnSelect(ev)) {
this.element!.classList.add('column-select');
} else {
this.element!.classList.remove('column-select');
+1 -1
View File
@@ -74,7 +74,7 @@ describe('Escape Sequence Files', function(): void {
let content = '';
const OSC_CODE = 12345;
await new Promise(resolve => {
customHandler = term.addOscHandler(OSC_CODE, () => {
customHandler = term.registerOscHandler(OSC_CODE, () => {
// grab terminal viewport content
content = terminalToString(term);
resolve();
+7 -4
View File
@@ -21,6 +21,9 @@ export class TestTerminal extends Terminal {
public get curAttrData(): IAttributeData { return (this as any)._inputHandler._curAttrData; }
public keyDown(ev: any): boolean | undefined { return this._keyDown(ev); }
public keyPress(ev: any): boolean { return this._keyPress(ev); }
public writeP(data: string | Uint8Array): Promise<void> {
return new Promise(r => this.write(data, r));
}
}
export class MockTerminal implements ITerminal {
@@ -75,16 +78,16 @@ export class MockTerminal implements ITerminal {
public attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void {
throw new Error('Method not implemented.');
}
public addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable {
public registerCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean | Promise<boolean>): IDisposable {
throw new Error('Method not implemented.');
}
public addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable {
public registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean | Promise<boolean>): IDisposable {
throw new Error('Method not implemented.');
}
public addEscHandler(id: IFunctionIdentifier, handler: () => boolean): IDisposable {
public registerEscHandler(id: IFunctionIdentifier, handler: () => boolean | Promise<boolean>): IDisposable {
throw new Error('Method not implemented.');
}
public addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable {
public registerOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable {
throw new Error('Method not implemented.');
}
public registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => boolean | void, options?: ILinkMatcherOptions): number {
+4 -4
View File
@@ -52,10 +52,10 @@ export interface IPublicTerminal extends IDisposable {
resize(columns: number, rows: number): void;
open(parent: HTMLElement): void;
attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void;
addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable;
addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable;
addEscHandler(id: IFunctionIdentifier, callback: () => boolean): IDisposable;
addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable;
registerCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean | Promise<boolean>): IDisposable;
registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean | Promise<boolean>): IDisposable;
registerEscHandler(id: IFunctionIdentifier, callback: () => boolean | Promise<boolean>): IDisposable;
registerOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable;
registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): number;
deregisterLinkMatcher(matcherId: number): void;
registerLinkProvider(linkProvider: ILinkProvider): IDisposable;

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