Skip to content

Commit

Permalink
Merge branch 'master' into fix/memory-leak
Browse files Browse the repository at this point in the history
  • Loading branch information
Tyriar committed Apr 21, 2024
2 parents 819254e + 6be1c3f commit af8a663
Show file tree
Hide file tree
Showing 63 changed files with 512 additions and 154 deletions.
8 changes: 5 additions & 3 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
{
"name": "xterm.js",
"image": "mcr.microsoft.com/devcontainers/typescript-node:0-18-buster",
"image": "mcr.microsoft.com/devcontainers/typescript-node:18-bookworm",
"features": {
"ghcr.io/devcontainers/features/node:1": {} // yarn
"ghcr.io/devcontainers/features/node:1": {
"version": 18
} // yarn
},
"forwardPorts": [
3000
],
"postCreateCommand": "yarn install",
"postCreateCommand": "yarn install && yarn setup",
"customizations": {
"vscode": {
"extensions": [
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16
18
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"runtimeExecutable": "npm",
"runtimeArgs": ["start"],
"stopOnEntry": true,
"runtimeVersion": "16",
"runtimeVersion": "18",
"serverReadyAction": {
"action": "openExternally",
"pattern": "App listening to (http://.*?:[0-9]+)"
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

```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`.
Expand All @@ -30,8 +30,8 @@ To start using xterm.js on your browser, add the `xterm.js` and `xterm.css` to t
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="node_modules/xterm/css/xterm.css" />
<script src="node_modules/xterm/lib/xterm.js"></script>
<link rel="stylesheet" href="node_modules/@xterm/xterm/css/xterm.css" />
<script src="node_modules/@xterm/xterm/lib/xterm.js"></script>
</head>
<body>
<div id="terminal"></div>
Expand Down Expand Up @@ -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:

```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.
Expand Down Expand Up @@ -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.
- [**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
- [**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)

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.
Expand Down
2 changes: 1 addition & 1 deletion addons/addon-attach/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-attach",
"version": "0.9.0",
"version": "0.11.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
Expand Down
4 changes: 3 additions & 1 deletion addons/addon-attach/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ module.exports = {
filename: mainFile,
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd'
libraryTarget: 'umd',
// Force usage of globalThis instead of global / self. (This is cross-env compatible)
globalObject: 'globalThis',
},
mode: 'production'
};
2 changes: 1 addition & 1 deletion addons/addon-canvas/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-canvas",
"version": "0.5.0",
"version": "0.7.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
Expand Down
16 changes: 14 additions & 2 deletions addons/addon-canvas/src/BaseRenderLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { CellColorResolver } from 'browser/renderer/shared/CellColorResolver';
import { acquireTextureAtlas } from 'browser/renderer/shared/CharAtlasCache';
import { TEXT_BASELINE } from 'browser/renderer/shared/Constants';
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 { IRasterizedGlyph, IRenderDimensions, ISelectionRenderModel, ITextureAtlas } from 'browser/renderer/shared/Types';
import { ICoreBrowserService, IThemeService } from 'browser/services/Services';
Expand Down Expand Up @@ -365,6 +365,8 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
*/
protected _drawChars(cell: ICellData, x: number, y: number): void {
const chars = cell.getChars();
const code = cell.getCode();
const width = cell.getWidth();
this._cellColorResolver.resolve(cell, x, this._bufferService.buffer.ydisp + y, this._deviceCellWidth);

if (!this._charAtlas) {
Expand Down Expand Up @@ -400,6 +402,16 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
this._bitmapGenerator[glyph.texturePage]!.refresh();
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._bitmapGenerator[glyph.texturePage]?.bitmap || this._charAtlas!.pages[glyph.texturePage].canvas,
glyph.texturePosition.x,
Expand All @@ -408,7 +420,7 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
glyph.size.y,
x * this._deviceCellWidth + this._deviceCharLeft - glyph.offset.x,
y * this._deviceCellHeight + this._deviceCharTop - glyph.offset.y,
glyph.size.x,
renderWidth,
glyph.size.y
);
this._ctx.restore();
Expand Down
4 changes: 3 additions & 1 deletion addons/addon-canvas/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ module.exports = {
filename: mainFile,
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd'
libraryTarget: 'umd',
// Force usage of globalThis instead of global / self. (This is cross-env compatible)
globalObject: 'globalThis',
},
mode: 'production'
};
2 changes: 1 addition & 1 deletion addons/addon-fit/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-fit",
"version": "0.8.0",
"version": "0.10.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
Expand Down
4 changes: 3 additions & 1 deletion addons/addon-fit/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ module.exports = {
filename: mainFile,
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd'
libraryTarget: 'umd',
// Force usage of globalThis instead of global / self. (This is cross-env compatible)
globalObject: 'globalThis',
},
mode: 'production'
};
2 changes: 1 addition & 1 deletion addons/addon-image/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-image",
"version": "0.6.0",
"version": "0.8.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
Expand Down
4 changes: 3 additions & 1 deletion addons/addon-image/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ const addon = {
filename: mainFile,
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd'
libraryTarget: 'umd',
// Force usage of globalThis instead of global / self. (This is cross-env compatible)
globalObject: 'globalThis',
},
mode: 'production'
};
Expand Down
2 changes: 1 addition & 1 deletion addons/addon-ligatures/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-ligatures",
"version": "0.7.0",
"version": "0.9.0",
"description": "Add support for programming ligatures to xterm.js",
"author": {
"name": "The xterm.js authors",
Expand Down
4 changes: 3 additions & 1 deletion addons/addon-ligatures/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ module.exports = {
filename: mainFile,
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd'
libraryTarget: 'umd',
// Force usage of globalThis instead of global / self. (This is cross-env compatible)
globalObject: 'globalThis',
},
mode: 'production',
externals: {
Expand Down
6 changes: 3 additions & 3 deletions addons/addon-ligatures/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ fd-slicer@~1.1.0:
pend "~1.2.0"

follow-redirects@^1.15.0:
version "1.15.3"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a"
integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==
version "1.15.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==

font-finder@^1.0.3:
version "1.0.4"
Expand Down
2 changes: 1 addition & 1 deletion addons/addon-search/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-search",
"version": "0.13.0",
"version": "0.15.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
Expand Down
21 changes: 8 additions & 13 deletions addons/addon-search/src/SearchAddon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import type { Terminal, IDisposable, ITerminalAddon, IDecoration } from '@xterm/xterm';
import type { SearchAddon as ISearchApi } from '@xterm/addon-search';
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 {
regex?: boolean;
Expand Down Expand Up @@ -78,8 +78,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
*/
private _linesCache: LineCacheEntry[] | undefined;
private _linesCacheTimeoutId = 0;
private _cursorMoveListener: IDisposable | undefined;
private _resizeListener: IDisposable | undefined;
private _linesCacheDisposables = new MutableDisposable();

private readonly _onDidChangeResults = this.register(new EventEmitter<{ resultIndex: number, resultCount: number }>());
public readonly onDidChangeResults = this._onDidChangeResults.event;
Expand Down Expand Up @@ -427,8 +426,11 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA
const terminal = this._terminal!;
if (!this._linesCache) {
this._linesCache = new Array(terminal.buffer.active.length);
this._cursorMoveListener = terminal.onCursorMove(() => this._destroyLinesCache());
this._resizeListener = terminal.onResize(() => this._destroyLinesCache());
this._linesCacheDisposables.value = getDisposeArrayDisposable([
terminal.onLineFeed(() => this._destroyLinesCache()),
terminal.onCursorMove(() => this._destroyLinesCache()),
terminal.onResize(() => this._destroyLinesCache())
]);
}

window.clearTimeout(this._linesCacheTimeoutId);
Expand All @@ -437,14 +439,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon , ISearchA

private _destroyLinesCache(): void {
this._linesCache = undefined;
if (this._cursorMoveListener) {
this._cursorMoveListener.dispose();
this._cursorMoveListener = undefined;
}
if (this._resizeListener) {
this._resizeListener.dispose();
this._resizeListener = undefined;
}
this._linesCacheDisposables.clear();
if (this._linesCacheTimeoutId) {
window.clearTimeout(this._linesCacheTimeoutId);
this._linesCacheTimeoutId = 0;
Expand Down
4 changes: 3 additions & 1 deletion addons/addon-search/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ module.exports = {
filename: mainFile,
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd'
libraryTarget: 'umd',
// Force usage of globalThis instead of global / self. (This is cross-env compatible)
globalObject: 'globalThis',
},
mode: 'production'
};
2 changes: 1 addition & 1 deletion addons/addon-serialize/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-serialize",
"version": "0.11.0",
"version": "0.13.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
Expand Down
3 changes: 2 additions & 1 deletion addons/addon-serialize/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ module.exports = {
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd',
globalObject: 'this'
// Force usage of globalThis instead of global / self. (This is cross-env compatible)
globalObject: 'globalThis',
},
mode: 'production'
};
2 changes: 1 addition & 1 deletion addons/addon-unicode-graphemes/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-unicode-graphemes",
"version": "0.1.0",
"version": "0.3.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
Expand Down
4 changes: 3 additions & 1 deletion addons/addon-unicode-graphemes/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ module.exports = {
filename: mainFile,
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd'
libraryTarget: 'umd',
// Force usage of globalThis instead of global / self. (This is cross-env compatible)
globalObject: 'globalThis',
},
mode: 'production'
};
2 changes: 1 addition & 1 deletion addons/addon-unicode11/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-unicode11",
"version": "0.6.0",
"version": "0.8.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
Expand Down
3 changes: 2 additions & 1 deletion addons/addon-unicode11/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ module.exports = {
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd',
globalObject: 'this'
// Force usage of globalThis instead of global / self. (This is cross-env compatible)
globalObject: 'globalThis',
},
mode: 'production'
};
2 changes: 1 addition & 1 deletion addons/addon-web-links/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-web-links",
"version": "0.9.0",
"version": "0.11.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
Expand Down
29 changes: 15 additions & 14 deletions addons/addon-web-links/src/WebLinkProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ export class WebLinkProvider implements ILinkProvider {
}
}

function isUrl(urlString: string): boolean {
try {
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;
}
}

export class LinkComputer {
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');
Expand All @@ -55,20 +69,7 @@ export class LinkComputer {
const text = match[0];

// check via URL if the matched text would form a proper url
// NOTE: This outsources the ugly url parsing to the browser.
// To avoid surprising auto expansion from URL we additionally
// check afterwards if the provided string resembles the parsed
// one close enough:
// - decodeURI decode path segement back to byte repr
// to detect unicode auto conversion correctly
// - append / also match domain urls w'o any path notion
try {
const url = new URL(text);
const urlText = decodeURI(url.toString());
if (text !== urlText && text + '/' !== urlText) {
continue;
}
} catch (e) {
if (!isUrl(text)) {
continue;
}

Expand Down

0 comments on commit af8a663

Please sign in to comment.