Compare commits

..
31 Commits
Author SHA1 Message Date
Daniel Imms 9ba6c00a19 Merge pull request #5021 from Tyriar/tyriar5_5
v5.5
2024-04-05 07:00:05 -07:00
Daniel Imms 78297e52aa v5.5 2024-04-05 06:50:30 -07:00
Daniel Imms 53bc9f8442 Merge pull request #5013 from Tyriar/tyriar/ascii
Don't rescale ascii
2024-03-20 10:09:19 -07:00
Daniel Imms 4c90009a0e Don't rescale ascii
See microsoft/vscode#208102
2024-03-20 10:02:53 -07:00
Daniel Imms bee4fd0914 Merge pull request #5012 from Tyriar/tyriar/208102
Only scale when over 50% of following cell
2024-03-19 09:03:36 -07:00
Daniel Imms f8ae7edaa0 Only scale when over 50% of following cell
See microsoft/vscode#208102
2024-03-19 08:56:13 -07:00
Daniel Imms 9ec9dca5f8 Merge pull request #5009 from Tyriar/tyriar/4987
Fix dom cursor blink animation and improve readability
2024-03-16 11:12:19 -07:00
Daniel Imms a4f1299f42 Special case cursor block blink to not use important
Fixes #4987
2024-03-16 11:07:05 -07:00
Daniel Imms 7b76ca7e49 Make dom rendere animation classes more readable 2024-03-16 09:57:23 -07:00
Daniel Imms 18147b2134 Fix bar blink animation 2024-03-16 09:55:20 -07:00
Daniel Imms c78af2b448 Fix dom cursor blink animation
Fixes #4987
Doesn't seem to regress #4773 which caused this issue
2024-03-16 09:49:36 -07:00
Daniel Imms e2dc01cf6e Merge pull request #5008 from Tyriar/tyriar/4994
Fix search not destroying cache on linefeed
2024-03-16 09:38:54 -07:00
Daniel Imms 14fbdd3e9c Adopt MutableDisposable in SearchAddon 2024-03-16 09:32:49 -07:00
Daniel Imms 3e5d0015af Fix search not destroying cache on linefeed
Fixes #4994
2024-03-16 09:30:25 -07:00
Daniel Imms b4c1007075 Merge pull request #5007 from Tyriar/5005
Don't rescale unless it exceeds 25% of following cell
2024-03-16 09:24:35 -07:00
Daniel Imms e0533db4d9 Merge pull request #5006 from Tyriar/tyriar/4995
Set up shared context on browser even if process exists
2024-03-16 09:18:02 -07:00
Daniel Imms 4071f41f52 Don't rescale unless it exceeds 25% of following cell
Fixes #5005
2024-03-16 09:16:31 -07:00
Daniel Imms 37efeeb044 Make process node check stricter
Fixes #4995
2024-03-16 09:08:54 -07:00
Daniel Imms 47409f39f6 Set up shared context on browser even if process exists
Fixes #4995
2024-03-16 09:05:45 -07:00
Daniel Imms b7b9d27627 Merge pull request #5001 from Tyriar/powerline_nf
Don't rescale powerline or nerd fonts
2024-03-15 08:36:58 -07:00
Daniel Imms 6b3d485d77 Note new excluded glyphs in API 2024-03-15 08:30:55 -07:00
Daniel Imms 48c6e96a78 Don't rescale powerline or nerd fonts
Part of #4969
2024-03-15 08:18:26 -07:00
Daniel Imms 44feecfc9a Merge pull request #4997 from Tyriar/4969
Introduce opt-in glyph scaling to achieve GB18030 compliance
2024-03-14 09:50:13 -07:00
Daniel Imms df559e3444 Rescale overlapping in canvas 2024-03-14 07:26:25 -07:00
Daniel Imms 33a7a9b6a2 Implement rescaleOverlappingGlyphs in webgl
Part of #4969
2024-03-14 07:14:13 -07:00
Daniel Imms 0658719d23 Merge pull request #4993 from Tyriar/tyriar/4992
Add default to api d.ts
2024-03-07 05:30:09 -08:00
Daniel Imms c32313a471 Add default to api d.ts
Fixes #4992
2024-03-07 05:21:59 -08:00
jerch 1da0db435f Merge pull request #4977 from dstein64/master
Add @xterm scope to packages
2024-03-03 12:57:24 +01:00
Daniel Steinberg 17fd7389c4 Add @xterm scope to packages 2024-03-02 03:46:10 +00:00
Daniel Imms 9da5f1401f Merge pull request #4976 from Tyriar/tyriar/readme
Update script/css import in readme
2024-03-01 09:24:49 -08:00
Daniel Imms da3aad4497 Update script/css import in readme
Part of #4859
2024-03-01 09:18:29 -08:00
27 changed files with 164 additions and 52 deletions
+4 -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:
```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`.
@@ -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>
@@ -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.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-attach",
"version": "0.10.0",
"version": "0.11.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-canvas",
"version": "0.6.0",
"version": "0.7.0",
"author": {
"name": "The xterm.js authors",
"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 { 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';
@@ -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) {
@@ -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,
@@ -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();
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-fit",
"version": "0.9.0",
"version": "0.10.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-image",
"version": "0.7.0",
"version": "0.8.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-ligatures",
"version": "0.8.0",
"version": "0.9.0",
"description": "Add support for programming ligatures to xterm.js",
"author": {
"name": "The xterm.js authors",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-search",
"version": "0.14.0",
"version": "0.15.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
+8 -13
View File
@@ -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;
@@ -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;
@@ -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);
@@ -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;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-serialize",
"version": "0.12.0",
"version": "0.13.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-unicode-graphemes",
"version": "0.2.0",
"version": "0.3.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-unicode11",
"version": "0.7.0",
"version": "0.8.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-web-links",
"version": "0.10.0",
"version": "0.11.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@xterm/addon-webgl",
"version": "0.17.0",
"version": "0.18.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
+15 -5
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
import { allowRescaling, throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
import { TextureAtlas } from 'browser/renderer/shared/TextureAtlas';
import { IRasterizedGlyph, IRenderDimensions, ITextureAtlas } from 'browser/renderer/shared/Types';
import { NULL_CELL_CODE } from 'common/buffer/Constants';
@@ -11,6 +11,7 @@ import { Disposable, toDisposable } from 'common/Lifecycle';
import { Terminal } from '@xterm/xterm';
import { IRenderModel, IWebGL2RenderingContext, IWebGLVertexArrayObject } from './Types';
import { createProgram, GLTexture, PROJECTION_MATRIX } from './WebglUtils';
import type { IOptionsService } from 'common/services/Services';
interface IVertices {
attributes: Float32Array;
@@ -111,7 +112,8 @@ export class GlyphRenderer extends Disposable {
constructor(
private readonly _terminal: Terminal,
private readonly _gl: IWebGL2RenderingContext,
private _dimensions: IRenderDimensions
private _dimensions: IRenderDimensions,
private readonly _optionsService: IOptionsService
) {
super();
@@ -212,15 +214,15 @@ export class GlyphRenderer extends Disposable {
return this._atlas ? this._atlas.beginFrame() : true;
}
public updateCell(x: number, y: number, code: number, bg: number, fg: number, ext: number, chars: string, lastBg: number): void {
public updateCell(x: number, y: number, code: number, bg: number, fg: number, ext: number, chars: string, width: number, lastBg: number): void {
// Since this function is called for every cell (`rows*cols`), it must be very optimized. It
// should not instantiate any variables unless a new glyph is drawn to the cache where the
// slight slowdown is acceptable for the developer ergonomics provided as it's a once of for
// each glyph.
this._updateCell(this._vertices.attributes, x, y, code, bg, fg, ext, chars, lastBg);
this._updateCell(this._vertices.attributes, x, y, code, bg, fg, ext, chars, width, lastBg);
}
private _updateCell(array: Float32Array, x: number, y: number, code: number | undefined, bg: number, fg: number, ext: number, chars: string, lastBg: number): void {
private _updateCell(array: Float32Array, x: number, y: number, code: number | undefined, bg: number, fg: number, ext: number, chars: string, width: number, lastBg: number): void {
$i = (y * this._terminal.cols + x) * INDICES_PER_CELL;
// Exit early if this is a null character, allow space character to continue as it may have
@@ -275,6 +277,14 @@ export class GlyphRenderer extends Disposable {
array[$i + 8] = $glyph.sizeClipSpace.y;
}
// a_cellpos only changes on resize
// Reduce scale horizontally for wide glyphs printed in cells that would overlap with the
// following cell (ie. the width is not 2).
if (this._optionsService.rawOptions.rescaleOverlappingGlyphs) {
if (allowRescaling(code, width, $glyph.size.x, this._dimensions.device.cell.width)) {
array[$i + 2] = (this._dimensions.device.cell.width - 1) / this._dimensions.device.canvas.width; // - 1 to improve readability
}
}
}
public clear(): void {
+7 -4
View File
@@ -36,7 +36,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
private _observerDisposable = this.register(new MutableDisposable());
private _model: RenderModel = new RenderModel();
private _workCell: CellData = new CellData();
private _workCell: ICellData = new CellData();
private _workCell2: ICellData = new CellData();
private _cellColorResolver: CellColorResolver;
private _canvas: HTMLCanvasElement;
@@ -245,7 +246,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
*/
private _initializeWebGLState(): [RectangleRenderer, GlyphRenderer] {
this._rectangleRenderer.value = new RectangleRenderer(this._terminal, this._gl, this.dimensions, this._themeService);
this._glyphRenderer.value = new GlyphRenderer(this._terminal, this._gl, this.dimensions);
this._glyphRenderer.value = new GlyphRenderer(this._terminal, this._gl, this.dimensions, this._optionsService);
// Update dimensions and acquire char atlas
this.handleCharSizeChanged();
@@ -388,6 +389,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
let range: [number, number];
let chars: string;
let code: number;
let width: number;
let i: number;
let x: number;
let j: number;
@@ -500,7 +502,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
this._model.cells[i + RENDER_MODEL_FG_OFFSET] = this._cellColorResolver.result.fg;
this._model.cells[i + RENDER_MODEL_EXT_OFFSET] = this._cellColorResolver.result.ext;
this._glyphRenderer.value!.updateCell(x, y, code, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext, chars, lastBg);
width = cell.getWidth();
this._glyphRenderer.value!.updateCell(x, y, code, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext, chars, width, lastBg);
if (isJoined) {
// Restore work cell
@@ -509,7 +512,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
// Null out non-first cells
for (x++; x < lastCharX; x++) {
j = ((y * terminal.cols) + x) * RENDER_MODEL_INDICIES_PER_CELL;
this._glyphRenderer.value!.updateCell(x, y, NULL_CELL_CODE, 0, 0, 0, NULL_CELL_CHAR, 0);
this._glyphRenderer.value!.updateCell(x, y, NULL_CELL_CODE, 0, 0, 0, NULL_CELL_CHAR, 0, 0);
this._model.cells[j] = NULL_CELL_CODE;
this._model.cells[j + RENDER_MODEL_BG_OFFSET] = this._cellColorResolver.result.bg;
this._model.cells[j + RENDER_MODEL_FG_OFFSET] = this._cellColorResolver.result.fg;
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@xterm/xterm",
"description": "Full xterm terminal, in your browser",
"version": "5.4.0",
"version": "5.5.0",
"main": "lib/xterm.js",
"style": "css/xterm.css",
"types": "typings/xterm.d.ts",
+24 -5
View File
@@ -183,14 +183,23 @@ export class DomRenderer extends Disposable implements IRenderer {
` font-style: italic;` +
`}`;
// Blink animation
const blinkAnimationUnderlineId = `blink_underline_${this._terminalClass}`;
const blinkAnimationBarId = `blink_bar_${this._terminalClass}`;
const blinkAnimationBlockId = `blink_block_${this._terminalClass}`;
styles +=
`@keyframes blink_box_shadow` + `_` + this._terminalClass + ` {` +
`@keyframes ${blinkAnimationUnderlineId} {` +
` 50% {` +
` border-bottom-style: hidden;` +
` }` +
`}`;
styles +=
`@keyframes blink_block` + `_` + this._terminalClass + ` {` +
`@keyframes ${blinkAnimationBarId} {` +
` 50% {` +
` box-shadow: none;` +
` }` +
`}`;
styles +=
`@keyframes ${blinkAnimationBlockId} {` +
` 0% {` +
` background-color: ${colors.cursor.css};` +
` color: ${colors.cursorAccent.css};` +
@@ -202,13 +211,23 @@ export class DomRenderer extends Disposable implements IRenderer {
`}`;
// Cursor
styles +=
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}:not(.${RowCss.CURSOR_STYLE_BLOCK_CLASS}) {` +
` animation: blink_box_shadow` + `_` + this._terminalClass + ` 1s step-end infinite;` +
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_UNDERLINE_CLASS} {` +
` animation: ${blinkAnimationUnderlineId} 1s step-end infinite;` +
`}` +
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_BAR_CLASS} {` +
` animation: ${blinkAnimationBarId} 1s step-end infinite;` +
`}` +
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` +
` animation: blink_block` + `_` + this._terminalClass + ` 1s step-end infinite;` +
` animation: ${blinkAnimationBlockId} 1s step-end infinite;` +
`}` +
// !important helps fix an issue where the cursor will not render on top of the selection,
// however it's very hard to fix this issue and retain the blink animation without the use of
// !important. So this edge case fails when cursor blink is on.
`${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` +
` background-color: ${colors.cursor.css};` +
` color: ${colors.cursorAccent.css};` +
`}` +
`${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS}:not(.${RowCss.CURSOR_BLINK_CLASS}) {` +
` background-color: ${colors.cursor.css} !important;` +
` color: ${colors.cursorAccent.css} !important;` +
`}` +
@@ -23,10 +23,43 @@ export function isRestrictedPowerlineGlyph(codepoint: number): boolean {
return 0xE0B0 <= codepoint && codepoint <= 0xE0B7;
}
function isNerdFontGlyph(codepoint: number): boolean {
return 0xE000 <= codepoint && codepoint <= 0xF8FF;
}
function isBoxOrBlockGlyph(codepoint: number): boolean {
return 0x2500 <= codepoint && codepoint <= 0x259F;
}
export function isEmoji(codepoint: number): boolean {
return (
codepoint >= 0x1F600 && codepoint <= 0x1F64F || // Emoticons
codepoint >= 0x1F300 && codepoint <= 0x1F5FF || // Misc Symbols and Pictographs
codepoint >= 0x1F680 && codepoint <= 0x1F6FF || // Transport and Map
codepoint >= 0x2600 && codepoint <= 0x26FF || // Misc symbols
codepoint >= 0x2700 && codepoint <= 0x27BF || // Dingbats
codepoint >= 0xFE00 && codepoint <= 0xFE0F || // Variation Selectors
codepoint >= 0x1F900 && codepoint <= 0x1F9FF || // Supplemental Symbols and Pictographs
codepoint >= 0x1F1E6 && codepoint <= 0x1F1FF
);
}
export function allowRescaling(codepoint: number | undefined, width: number, glyphSizeX: number, deviceCellWidth: number): boolean {
return (
// Is single cell width
width === 1 &&
// Glyph exceeds cell bounds, add 50% to avoid hurting readability by rescaling glyphs that
// barely overlap
glyphSizeX > Math.ceil(deviceCellWidth * 1.5) &&
// Never rescale ascii
codepoint !== undefined && codepoint > 0xFF &&
// Never rescale emoji
!isEmoji(codepoint) &&
// Never rescale powerline or nerd fonts
!isPowerlineGlyph(codepoint) && !isNerdFontGlyph(codepoint)
);
}
export function treatGlyphAsBackgroundColor(codepoint: number): boolean {
return isPowerlineGlyph(codepoint) || isBoxOrBlockGlyph(codepoint);
}
+2 -1
View File
@@ -87,7 +87,8 @@ export class RenderService extends Disposable implements IRenderService {
'fontSize',
'fontWeight',
'fontWeightBold',
'minimumContrastRatio'
'minimumContrastRatio',
'rescaleOverlappingGlyphs'
], () => {
this.clear();
this.handleResize(bufferService.cols, bufferService.rows);
+5 -2
View File
@@ -3,7 +3,6 @@
* @license MIT
*/
import { isNode } from 'common/Platform';
import { IColor, IColorRGB } from 'common/Types';
let $r = 0;
@@ -117,9 +116,10 @@ export namespace color {
* '#rrggbbaa').
*/
export namespace css {
// Attempt to set get the shared canvas context
let $ctx: CanvasRenderingContext2D | undefined;
let $litmusColor: CanvasGradient | undefined;
if (!isNode) {
try {
// This is guaranteed to run in the first window, so document should be correct
const canvas = document.createElement('canvas');
canvas.width = 1;
@@ -133,6 +133,9 @@ export namespace css {
$litmusColor = $ctx.createLinearGradient(0, 0, 1, 1);
}
}
catch {
// noop
}
/**
* Converts a css string to an IColor, this should handle all valid CSS color strings and will
+1 -1
View File
@@ -14,7 +14,7 @@ interface INavigator {
declare const navigator: INavigator;
declare const process: unknown;
export const isNode = (typeof process !== 'undefined') ? true : false;
export const isNode = (typeof process !== 'undefined' && 'title' in (process as any)) ? true : false;
const userAgent = (isNode) ? 'node' : navigator.userAgent;
const platform = (isNode) ? 'node' : navigator.platform;
+1
View File
@@ -44,6 +44,7 @@ export const DEFAULT_OPTIONS: Readonly<Required<ITerminalOptions>> = {
allowTransparency: false,
tabStopWidth: 8,
theme: {},
rescaleOverlappingGlyphs: false,
rightClickSelectsWord: isMac,
windowOptions: {},
windowsMode: false,
+1
View File
@@ -234,6 +234,7 @@ export interface ITerminalOptions {
macOptionIsMeta?: boolean;
macOptionClickForcesSelection?: boolean;
minimumContrastRatio?: number;
rescaleOverlappingGlyphs?: boolean;
rightClickSelectsWord?: boolean;
rows?: number;
screenReaderMode?: boolean;
+1 -1
View File
@@ -6,7 +6,7 @@
import { IImage32, decodePng } from '@lunapaint/png-codec';
import { LocatorScreenshotOptions, test } from '@playwright/test';
import { ITheme } from '@xterm/xterm';
import { ITestContext, MaybeAsync, openTerminal, pollFor, pollForApproximate, timeout } from './TestUtils';
import { ITestContext, MaybeAsync, openTerminal, pollFor, pollForApproximate } from './TestUtils';
export interface ISharedRendererTestContext {
value: ITestContext;
+18 -1
View File
@@ -140,6 +140,23 @@ declare module '@xterm/headless' {
*/
minimumContrastRatio?: number;
/**
* Whether to rescale glyphs horizontally that are a single cell wide but
* have glyphs that would overlap following cell(s). This typically happens
* for ambiguous width characters (eg. the roman numeral characters U+2160+)
* which aren't featured in monospace fonts. This is an important feature
* for achieving GB18030 compliance.
*
* The following glyphs will never be rescaled:
*
* - Emoji glyphs
* - Powerline glyphs
* - Nerd font glyphs
*
* Note that this doesn't work with the DOM renderer. The default is false.
*/
rescaleOverlappingGlyphs?: boolean;
/**
* Whether to select the word under the cursor on right click, this is
* standard behavior in a lot of macOS applications.
@@ -156,7 +173,7 @@ declare module '@xterm/headless' {
/**
* The amount of scrollback in the terminal. Scrollback is the amount of
* rows that are retained when lines are scrolled beyond the initial
* viewport.
* viewport. Defaults to 1000.
*/
scrollback?: number;
+18 -1
View File
@@ -209,6 +209,23 @@ declare module '@xterm/xterm' {
*/
minimumContrastRatio?: number;
/**
* Whether to rescale glyphs horizontally that are a single cell wide but
* have glyphs that would overlap following cell(s). This typically happens
* for ambiguous width characters (eg. the roman numeral characters U+2160+)
* which aren't featured in monospace fonts. This is an important feature
* for achieving GB18030 compliance.
*
* The following glyphs will never be rescaled:
*
* - Emoji glyphs
* - Powerline glyphs
* - Nerd font glyphs
*
* Note that this doesn't work with the DOM renderer. The default is false.
*/
rescaleOverlappingGlyphs?: boolean;
/**
* Whether to select the word under the cursor on right click, this is
* standard behavior in a lot of macOS applications.
@@ -225,7 +242,7 @@ declare module '@xterm/xterm' {
/**
* The amount of scrollback in the terminal. Scrollback is the amount of
* rows that are retained when lines are scrolled beyond the initial
* viewport.
* viewport. Defaults to 1000.
*/
scrollback?: number;