Merge branch 'master' into patch-1

This commit is contained in:
Daniel Imms
2024-04-21 07:41:48 -07:00
committed by GitHub
44 changed files with 368 additions and 104 deletions
+5 -3
View File
@@ -1,13 +1,15 @@
{ {
"name": "xterm.js", "name": "xterm.js",
"image": "mcr.microsoft.com/devcontainers/typescript-node:0-18-buster", "image": "mcr.microsoft.com/devcontainers/typescript-node:18-bookworm",
"features": { "features": {
"ghcr.io/devcontainers/features/node:1": {} // yarn "ghcr.io/devcontainers/features/node:1": {
"version": 18
} // yarn
}, },
"forwardPorts": [ "forwardPorts": [
3000 3000
], ],
"postCreateCommand": "yarn install", "postCreateCommand": "yarn install && yarn setup",
"customizations": { "customizations": {
"vscode": { "vscode": {
"extensions": [ "extensions": [
+1 -1
View File
@@ -1 +1 @@
16 18
+1 -1
View File
@@ -61,7 +61,7 @@
"runtimeExecutable": "npm", "runtimeExecutable": "npm",
"runtimeArgs": ["start"], "runtimeArgs": ["start"],
"stopOnEntry": true, "stopOnEntry": true,
"runtimeVersion": "16", "runtimeVersion": "18",
"serverReadyAction": { "serverReadyAction": {
"action": "openExternally", "action": "openExternally",
"pattern": "App listening to (http://.*?:[0-9]+)" "pattern": "App listening to (http://.*?:[0-9]+)"
+5 -4
View File
@@ -21,7 +21,7 @@ Xterm.js is a front-end component written in TypeScript that lets applications b
First, you need to install the module, we ship exclusively through [npm](https://www.npmjs.com/), so you need that installed and then add xterm.js as a dependency by running: First, you need to install the module, we ship exclusively through [npm](https://www.npmjs.com/), so you need that installed and then add xterm.js as a dependency by running:
```bash ```bash
npm install xterm npm install @xterm/xterm
``` ```
To start using xterm.js on your browser, add the `xterm.js` and `xterm.css` to the head of your HTML page. Then create a `<div id="terminal"></div>` onto which xterm can attach itself. Finally, instantiate the `Terminal` object and then call the `open` function with the DOM object of the `div`. To start using xterm.js on your browser, add the `xterm.js` and `xterm.css` to the head of your HTML page. Then create a `<div id="terminal"></div>` onto which xterm can attach itself. Finally, instantiate the `Terminal` object and then call the `open` function with the DOM object of the `div`.
@@ -30,8 +30,8 @@ To start using xterm.js on your browser, add the `xterm.js` and `xterm.css` to t
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<link rel="stylesheet" href="node_modules/xterm/css/xterm.css" /> <link rel="stylesheet" href="node_modules/@xterm/xterm/css/xterm.css" />
<script src="node_modules/xterm/lib/xterm.js"></script> <script src="node_modules/@xterm/xterm/lib/xterm.js"></script>
</head> </head>
<body> <body>
<div id="terminal"></div> <div id="terminal"></div>
@@ -113,7 +113,7 @@ All current and past releases are available on this repo's [Releases page](https
Our CI releases beta builds to npm for every change that goes into master. Install the latest beta build with: Our CI releases beta builds to npm for every change that goes into master. Install the latest beta build with:
```bash ```bash
npm install -S xterm@beta npm install -S @xterm/xterm@beta
``` ```
These should generally be stable, but some bugs may slip in. We recommend using the beta build primarily to test out new features and to verify bug fixes. These should generally be stable, but some bugs may slip in. We recommend using the beta build primarily to test out new features and to verify bug fixes.
@@ -222,6 +222,7 @@ Xterm.js is used in several world-class applications to provide great terminal e
- [**Cloudtutor.io**](https://cloudtutor.io): innovative online learning platform that offers users access to an interactive lab. - [**Cloudtutor.io**](https://cloudtutor.io): innovative online learning platform that offers users access to an interactive lab.
- [**Helix Editor Playground**](https://github.com/tomgroenwoldt/helix-editor-playground): Online playground for the terminal based helix editor. - [**Helix Editor Playground**](https://github.com/tomgroenwoldt/helix-editor-playground): Online playground for the terminal based helix editor.
- [**Coder**](https://github.com/coder/coder): Self-Hosted Remote Development Environments - [**Coder**](https://github.com/coder/coder): Self-Hosted Remote Development Environments
- [**Wave Terminal**](https://waveterm.dev): An open-source, ai-native, terminal built for seamless workflows.
- [And much more...](https://github.com/xtermjs/xterm.js/network/dependents?package_id=UGFja2FnZS0xNjYzMjc4OQ%3D%3D) - [And much more...](https://github.com/xtermjs/xterm.js/network/dependents?package_id=UGFja2FnZS0xNjYzMjc4OQ%3D%3D)
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 on 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 on our list. Note: Please add any new contributions to the end of the list only.
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xterm/addon-attach", "name": "@xterm/addon-attach",
"version": "0.9.0", "version": "0.11.0",
"author": { "author": {
"name": "The xterm.js authors", "name": "The xterm.js authors",
"url": "https://xtermjs.org/" "url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xterm/addon-canvas", "name": "@xterm/addon-canvas",
"version": "0.5.0", "version": "0.7.0",
"author": { "author": {
"name": "The xterm.js authors", "name": "The xterm.js authors",
"url": "https://xtermjs.org/" "url": "https://xtermjs.org/"
+14 -2
View File
@@ -8,7 +8,7 @@ import { CellColorResolver } from 'browser/renderer/shared/CellColorResolver';
import { acquireTextureAtlas } from 'browser/renderer/shared/CharAtlasCache'; import { acquireTextureAtlas } from 'browser/renderer/shared/CharAtlasCache';
import { TEXT_BASELINE } from 'browser/renderer/shared/Constants'; import { TEXT_BASELINE } from 'browser/renderer/shared/Constants';
import { tryDrawCustomChar } from 'browser/renderer/shared/CustomGlyphs'; import { tryDrawCustomChar } from 'browser/renderer/shared/CustomGlyphs';
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; import { allowRescaling, throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
import { createSelectionRenderModel } from 'browser/renderer/shared/SelectionRenderModel'; import { createSelectionRenderModel } from 'browser/renderer/shared/SelectionRenderModel';
import { IRasterizedGlyph, IRenderDimensions, ISelectionRenderModel, ITextureAtlas } from 'browser/renderer/shared/Types'; import { IRasterizedGlyph, IRenderDimensions, ISelectionRenderModel, ITextureAtlas } from 'browser/renderer/shared/Types';
import { ICoreBrowserService, IThemeService } from 'browser/services/Services'; import { ICoreBrowserService, IThemeService } from 'browser/services/Services';
@@ -365,6 +365,8 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
*/ */
protected _drawChars(cell: ICellData, x: number, y: number): void { protected _drawChars(cell: ICellData, x: number, y: number): void {
const chars = cell.getChars(); const chars = cell.getChars();
const code = cell.getCode();
const width = cell.getWidth();
this._cellColorResolver.resolve(cell, x, this._bufferService.buffer.ydisp + y, this._deviceCellWidth); this._cellColorResolver.resolve(cell, x, this._bufferService.buffer.ydisp + y, this._deviceCellWidth);
if (!this._charAtlas) { if (!this._charAtlas) {
@@ -400,6 +402,16 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
this._bitmapGenerator[glyph.texturePage]!.refresh(); this._bitmapGenerator[glyph.texturePage]!.refresh();
this._bitmapGenerator[glyph.texturePage]!.version = this._charAtlas.pages[glyph.texturePage].version; this._bitmapGenerator[glyph.texturePage]!.version = this._charAtlas.pages[glyph.texturePage].version;
} }
// Reduce scale horizontally for wide glyphs printed in cells that would overlap with the
// following cell (ie. the width is not 2).
let renderWidth = glyph.size.x;
if (this._optionsService.rawOptions.rescaleOverlappingGlyphs) {
if (allowRescaling(code, width, glyph.size.x, this._deviceCellWidth)) {
renderWidth = this._deviceCellWidth - 1; // - 1 to improve readability
}
}
this._ctx.drawImage( this._ctx.drawImage(
this._bitmapGenerator[glyph.texturePage]?.bitmap || this._charAtlas!.pages[glyph.texturePage].canvas, this._bitmapGenerator[glyph.texturePage]?.bitmap || this._charAtlas!.pages[glyph.texturePage].canvas,
glyph.texturePosition.x, glyph.texturePosition.x,
@@ -408,7 +420,7 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
glyph.size.y, glyph.size.y,
x * this._deviceCellWidth + this._deviceCharLeft - glyph.offset.x, x * this._deviceCellWidth + this._deviceCharLeft - glyph.offset.x,
y * this._deviceCellHeight + this._deviceCharTop - glyph.offset.y, y * this._deviceCellHeight + this._deviceCharTop - glyph.offset.y,
glyph.size.x, renderWidth,
glyph.size.y glyph.size.y
); );
this._ctx.restore(); this._ctx.restore();
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xterm/addon-fit", "name": "@xterm/addon-fit",
"version": "0.8.0", "version": "0.10.0",
"author": { "author": {
"name": "The xterm.js authors", "name": "The xterm.js authors",
"url": "https://xtermjs.org/" "url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xterm/addon-image", "name": "@xterm/addon-image",
"version": "0.6.0", "version": "0.8.0",
"author": { "author": {
"name": "The xterm.js authors", "name": "The xterm.js authors",
"url": "https://xtermjs.org/" "url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xterm/addon-ligatures", "name": "@xterm/addon-ligatures",
"version": "0.7.0", "version": "0.9.0",
"description": "Add support for programming ligatures to xterm.js", "description": "Add support for programming ligatures to xterm.js",
"author": { "author": {
"name": "The xterm.js authors", "name": "The xterm.js authors",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xterm/addon-search", "name": "@xterm/addon-search",
"version": "0.13.0", "version": "0.15.0",
"author": { "author": {
"name": "The xterm.js authors", "name": "The xterm.js authors",
"url": "https://xtermjs.org/" "url": "https://xtermjs.org/"
+8 -13
View File
@@ -6,7 +6,7 @@
import type { Terminal, IDisposable, ITerminalAddon, IDecoration } from '@xterm/xterm'; import type { Terminal, IDisposable, ITerminalAddon, IDecoration } from '@xterm/xterm';
import type { SearchAddon as ISearchApi } from '@xterm/addon-search'; import type { SearchAddon as ISearchApi } from '@xterm/addon-search';
import { EventEmitter } from 'common/EventEmitter'; import { EventEmitter } from 'common/EventEmitter';
import { Disposable, toDisposable, disposeArray, MutableDisposable } from 'common/Lifecycle'; import { Disposable, toDisposable, disposeArray, MutableDisposable, getDisposeArrayDisposable } from 'common/Lifecycle';
export interface ISearchOptions { export interface ISearchOptions {
regex?: boolean; regex?: boolean;
@@ -78,8 +78,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
*/ */
private _linesCache: LineCacheEntry[] | undefined; private _linesCache: LineCacheEntry[] | undefined;
private _linesCacheTimeoutId = 0; private _linesCacheTimeoutId = 0;
private _cursorMoveListener: IDisposable | undefined; private _linesCacheDisposables = new MutableDisposable();
private _resizeListener: IDisposable | undefined;
private readonly _onDidChangeResults = this.register(new EventEmitter<{ resultIndex: number, resultCount: number }>()); private readonly _onDidChangeResults = this.register(new EventEmitter<{ resultIndex: number, resultCount: number }>());
public readonly onDidChangeResults = this._onDidChangeResults.event; public readonly onDidChangeResults = this._onDidChangeResults.event;
@@ -427,8 +426,11 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
const terminal = this._terminal!; const terminal = this._terminal!;
if (!this._linesCache) { if (!this._linesCache) {
this._linesCache = new Array(terminal.buffer.active.length); this._linesCache = new Array(terminal.buffer.active.length);
this._cursorMoveListener = terminal.onCursorMove(() => this._destroyLinesCache()); this._linesCacheDisposables.value = getDisposeArrayDisposable([
this._resizeListener = terminal.onResize(() => this._destroyLinesCache()); terminal.onLineFeed(() => this._destroyLinesCache()),
terminal.onCursorMove(() => this._destroyLinesCache()),
terminal.onResize(() => this._destroyLinesCache())
]);
} }
window.clearTimeout(this._linesCacheTimeoutId); window.clearTimeout(this._linesCacheTimeoutId);
@@ -437,14 +439,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
private _destroyLinesCache(): void { private _destroyLinesCache(): void {
this._linesCache = undefined; this._linesCache = undefined;
if (this._cursorMoveListener) { this._linesCacheDisposables.clear();
this._cursorMoveListener.dispose();
this._cursorMoveListener = undefined;
}
if (this._resizeListener) {
this._resizeListener.dispose();
this._resizeListener = undefined;
}
if (this._linesCacheTimeoutId) { if (this._linesCacheTimeoutId) {
window.clearTimeout(this._linesCacheTimeoutId); window.clearTimeout(this._linesCacheTimeoutId);
this._linesCacheTimeoutId = 0; this._linesCacheTimeoutId = 0;
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xterm/addon-serialize", "name": "@xterm/addon-serialize",
"version": "0.11.0", "version": "0.13.0",
"author": { "author": {
"name": "The xterm.js authors", "name": "The xterm.js authors",
"url": "https://xtermjs.org/" "url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xterm/addon-unicode-graphemes", "name": "@xterm/addon-unicode-graphemes",
"version": "0.1.0", "version": "0.3.0",
"author": { "author": {
"name": "The xterm.js authors", "name": "The xterm.js authors",
"url": "https://xtermjs.org/" "url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xterm/addon-unicode11", "name": "@xterm/addon-unicode11",
"version": "0.6.0", "version": "0.8.0",
"author": { "author": {
"name": "The xterm.js authors", "name": "The xterm.js authors",
"url": "https://xtermjs.org/" "url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xterm/addon-web-links", "name": "@xterm/addon-web-links",
"version": "0.9.0", "version": "0.11.0",
"author": { "author": {
"name": "The xterm.js authors", "name": "The xterm.js authors",
"url": "https://xtermjs.org/" "url": "https://xtermjs.org/"
+12 -18
View File
@@ -41,16 +41,18 @@ export class WebLinkProvider implements ILinkProvider {
} }
} }
function baseUrlString(url: URL): string { function isUrl(urlString: string): boolean {
if (url.password && url.username) { try {
return `${url.protocol}//${url.username}:${url.password}@${url.host}`; const url = new URL(urlString);
const parsedBase = url.password && url.username
? `${url.protocol}//${url.username}:${url.password}@${url.host}`
: url.username
? `${url.protocol}//${url.username}@${url.host}`
: `${url.protocol}//${url.host}`;
return urlString.toLocaleLowerCase().startsWith(parsedBase.toLocaleLowerCase());
} catch (e) {
return false;
} }
if (url.username) {
return `${url.protocol}//${url.username}@${url.host}`;
}
return `${url.protocol}//${url.host}`;
} }
export class LinkComputer { export class LinkComputer {
@@ -67,15 +69,7 @@ export class LinkComputer {
const text = match[0]; const text = match[0];
// check via URL if the matched text would form a proper url // check via URL if the matched text would form a proper url
// NOTE: This outsources the ugly url parsing to the browser. if (!isUrl(text)) {
// we check if the provided string resembles the URL-parsed one
// up to the end of the domain name (ignoring path and params)
try {
const url = new URL(text);
if (!text.startsWith(baseUrlString(url))) {
continue;
}
} catch (e) {
continue; continue;
} }
+1 -1
View File
@@ -18,7 +18,7 @@ import { ILinkProviderOptions, WebLinkProvider } from './WebLinkProvider';
// - final interpunction like ,.!? // - final interpunction like ,.!?
// - any sort of brackets <>()[]{} (not spec conform, but often used to enclose urls) // - any sort of brackets <>()[]{} (not spec conform, but often used to enclose urls)
// - unsafe chars from rfc1738: {}|\^~[]` // - unsafe chars from rfc1738: {}|\^~[]`
const strictUrlRegex = /https?:[/]{2}[^\s"'!*(){}|\\\^<>`]*[^\s"':,.!?{}|\\\^~\[\]`()<>]/; const strictUrlRegex = /(https?|HTTPS?):[/]{2}[^\s"'!*(){}|\\\^<>`]*[^\s"':,.!?{}|\\\^~\[\]`()<>]/;
function handleLink(event: MouseEvent, uri: string): void { function handleLink(event: MouseEvent, uri: string): void {
@@ -123,6 +123,21 @@ describe('WebLinksAddon', () => {
await evalLinkStateData('http://test:password@example.com/some_path?param=1%202%3', { start: { x: 12, y: 1 }, end: { x: 27, y: 2 } }); await evalLinkStateData('http://test:password@example.com/some_path?param=1%202%3', { start: { x: 12, y: 1 }, end: { x: 27, y: 2 } });
}); });
}); });
// issue #4964
it('uppercase in protocol and host, default ports', async () => {
const data = ` HTTP://EXAMPLE.COM \\r\\n` +
` HTTPS://Example.com \\r\\n` +
` HTTP://Example.com:80 \\r\\n` +
` HTTP://Example.com:80/staysUpper \\r\\n` +
` HTTP://Ab:xY@abc.com:80/staysUpper \\r\\n`;
await writeSync(page, data);
await pollForLinkAtCell(3, 0, `HTTP://EXAMPLE.COM`);
await pollForLinkAtCell(3, 1, `HTTPS://Example.com`);
await pollForLinkAtCell(3, 2, `HTTP://Example.com:80`);
await pollForLinkAtCell(3, 3, `HTTP://Example.com:80/staysUpper`);
await pollForLinkAtCell(3, 4, `HTTP://Ab:xY@abc.com:80/staysUpper`);
});
}); });
async function testHostName(hostname: string): Promise<void> { async function testHostName(hostname: string): Promise<void> {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xterm/addon-webgl", "name": "@xterm/addon-webgl",
"version": "0.16.0", "version": "0.18.0",
"author": { "author": {
"name": "The xterm.js authors", "name": "The xterm.js authors",
"url": "https://xtermjs.org/" "url": "https://xtermjs.org/"

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