Fixes https://github.com/xtermjs/xterm.js/issues/5896 TypeScript path mappings for common/*, browser/*, and headless/* were not rewritten in emitted JavaScript, which forced webpack resolve aliases and NODE_PATH workarounds so runtime could resolve modules. That added build complexity and broke tooling such as ESLint import/no-cycle. Changes: - Convert ~750 imports across src/, addons/, and test/ to relative paths - Remove common/browser/headless paths and src catch-all mappings from tsconfigs (keep @xterm/addon-* demo and addon typings paths) - Remove webpack resolve.alias for common, browser, headless, and vs - Drop NODE_PATH from unit tests, benchmarks, and VS Code launch config - Fix addon-image IIPImageStorage to import ./Types after removing catch-all * Verified: npm run build, esbuild, package, package-headless Co-authored-by: Cursor <cursoragent@cursor.com>
143 lines
4.8 KiB
TypeScript
143 lines
4.8 KiB
TypeScript
/**
|
|
* Copyright (c) 2023 The xterm.js authors. All rights reserved.
|
|
* @license MIT
|
|
*/
|
|
|
|
import * as assert from 'assert';
|
|
import { IWidthCacheFontVariantCanvas, WidthCache, WidthCacheSettings } from './WidthCache';
|
|
|
|
|
|
class MockWidthCacheFontVariantCanvas implements IWidthCacheFontVariantCanvas {
|
|
public widths: { [key: string]: number } = {};
|
|
|
|
public setFont(_fontFamily: string, _fontSize: number, _fontWeight: unknown, _italic: boolean): void {
|
|
}
|
|
|
|
public measure(c: string): number {
|
|
return this.widths[c] ?? 5;
|
|
}
|
|
}
|
|
|
|
export class TestWidthCache extends WidthCache {
|
|
public get flat(): Float32Array {
|
|
return (this as any)._flat;
|
|
}
|
|
public get holey(): Map<string, number> | undefined {
|
|
return (this as any)._holey;
|
|
}
|
|
public get canvasElements(): MockWidthCacheFontVariantCanvas[] {
|
|
return (this as any)._canvasElements;
|
|
}
|
|
|
|
constructor() {
|
|
super(() => new MockWidthCacheFontVariantCanvas());
|
|
}
|
|
|
|
public setWidths(widths: { [key: string]: number }): void {
|
|
for (const canvas of this.canvasElements) {
|
|
canvas.widths = widths;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function castf32(v: number): number {
|
|
const buffer = new Float32Array(1);
|
|
buffer[0] = v;
|
|
return buffer[0];
|
|
}
|
|
|
|
|
|
describe('WidthCache', () => {
|
|
let wc: TestWidthCache;
|
|
beforeEach(() => {
|
|
wc = new TestWidthCache();
|
|
wc.setFont('monospace', 15, 'normal', 'bold');
|
|
});
|
|
describe('cache invalidation', () => {
|
|
beforeEach(() => {
|
|
wc.flat.fill(1.23);
|
|
wc.holey?.set('a', 2.34);
|
|
});
|
|
it('can cache values', () => {
|
|
assert.deepStrictEqual(wc.flat[0], castf32(1.23));
|
|
assert.deepStrictEqual(wc.holey?.get('a'), 2.34);
|
|
assert.deepStrictEqual(wc.holey?.size, 1);
|
|
});
|
|
it('clear resets cache entries', () => {
|
|
wc.clear();
|
|
assert.deepStrictEqual(wc.flat[0], castf32(WidthCacheSettings.FLAT_UNSET));
|
|
assert.deepStrictEqual(wc.holey?.get('a'), undefined);
|
|
assert.deepStrictEqual(wc.holey?.size, 0);
|
|
});
|
|
it('setFont with changed font name', () => {
|
|
wc.setFont('Arial', 15, 'normal', 'bold');
|
|
assert.deepStrictEqual(wc.flat[0], castf32(WidthCacheSettings.FLAT_UNSET));
|
|
assert.deepStrictEqual(wc.holey?.get('a'), undefined);
|
|
assert.deepStrictEqual(wc.holey?.size, 0);
|
|
});
|
|
it('setFont with changed font size', () => {
|
|
wc.setFont('monospace', 14, 'normal', 'bold');
|
|
assert.deepStrictEqual(wc.flat[0], castf32(WidthCacheSettings.FLAT_UNSET));
|
|
assert.deepStrictEqual(wc.holey?.get('a'), undefined);
|
|
assert.deepStrictEqual(wc.holey?.size, 0);
|
|
});
|
|
it('setFont with changed weight', () => {
|
|
wc.setFont('monospace', 15, '100', 'bold');
|
|
assert.deepStrictEqual(wc.flat[0], castf32(WidthCacheSettings.FLAT_UNSET));
|
|
assert.deepStrictEqual(wc.holey?.get('a'), undefined);
|
|
assert.deepStrictEqual(wc.holey?.size, 0);
|
|
});
|
|
it('setFont with changed weightBold', () => {
|
|
wc.setFont('monospace', 15, 'normal', '900');
|
|
assert.deepStrictEqual(wc.flat[0], castf32(WidthCacheSettings.FLAT_UNSET));
|
|
assert.deepStrictEqual(wc.holey?.get('a'), undefined);
|
|
assert.deepStrictEqual(wc.holey?.size, 0);
|
|
});
|
|
it('setFont with unchanged settings does not cache entries', () => {
|
|
wc.setFont('monospace', 15, 'normal', 'bold');
|
|
assert.deepStrictEqual(wc.flat[0], castf32(1.23));
|
|
assert.deepStrictEqual(wc.holey?.get('a'), 2.34);
|
|
assert.deepStrictEqual(wc.holey?.size, 1);
|
|
});
|
|
});
|
|
describe('get', () => {
|
|
it('store regular < WidthCacheSettings.FLAT_SIZE in flat', () => {
|
|
for (let i = 0; i < WidthCacheSettings.FLAT_SIZE + 10; ++i) {
|
|
const width = wc.get(String.fromCharCode(i), false, false);
|
|
assert.deepStrictEqual(width, 5);
|
|
if (i < WidthCacheSettings.FLAT_SIZE) {
|
|
assert.deepStrictEqual(wc.flat[i], 5);
|
|
assert.deepStrictEqual(wc.holey?.get(String.fromCharCode(i)), undefined);
|
|
} else {
|
|
assert.deepStrictEqual(wc.holey?.get(String.fromCharCode(i)), 5);
|
|
}
|
|
}
|
|
});
|
|
it('stores bold & italic in holey', () => {
|
|
// bold
|
|
let width = wc.get('b', true, false);
|
|
assert.deepStrictEqual(width, 5);
|
|
assert.deepStrictEqual(wc.holey?.get('bB'), 5);
|
|
// italic
|
|
width = wc.get('i', false, true);
|
|
assert.deepStrictEqual(width, 5);
|
|
assert.deepStrictEqual(wc.holey?.get('iI'), 5);
|
|
// bold&italic
|
|
width = wc.get('x', true, true);
|
|
assert.deepStrictEqual(width, 5);
|
|
assert.deepStrictEqual(wc.holey?.get('xBI'), 5);
|
|
});
|
|
it('can store any string', () => {
|
|
// regular
|
|
let width = wc.get('foo', false, false);
|
|
assert.deepStrictEqual(width, 5);
|
|
assert.deepStrictEqual(wc.holey?.get('foo'), 5);
|
|
// bold&italic
|
|
width = wc.get('bar&baz', true, true);
|
|
assert.deepStrictEqual(width, 5);
|
|
assert.deepStrictEqual(wc.holey?.get('bar&bazBI'), 5);
|
|
});
|
|
});
|
|
});
|