Convert a lot of top level consts to const enums

This commit is contained in:
Daniel Imms
2026-05-02 06:44:25 -07:00
parent 5c47e6dd9a
commit 80debafa11
19 changed files with 304 additions and 282 deletions
+58 -58
View File
@@ -9,25 +9,20 @@ import { CellData } from 'common/buffer/CellData';
import { Attributes, BgFlags, CHAR_DATA_ATTR_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, Content, NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, WHITESPACE_CELL_CHAR } from 'common/buffer/Constants';
import { stringFromCodePoint } from 'common/input/TextDecoder';
/**
* buffer memory layout:
*
* | uint32_t | uint32_t | uint32_t |
* | `content` | `FG` | `BG` |
* | wcwidth(2) comb(1) codepoint(21) | flags(8) R(8) G(8) B(8) | flags(8) R(8) G(8) B(8) |
*/
/** typed array slots taken by one cell */
const CELL_SIZE = 3;
const enum Constants {
/** The number of 32 bit array indices taken by one cell. */
CELL_INDICIES = 3,
/** Factor when to cleanup underlying array buffer after shrinking. */
CLEANUP_THRESHOLD = 2
}
/**
* Cell member indices.
*
* Direct access:
* `content = data[column * CELL_SIZE + Cell.CONTENT];`
* `fg = data[column * CELL_SIZE + Cell.FG];`
* `bg = data[column * CELL_SIZE + Cell.BG];`
* `content = data[column * Constants.CELL_INDICIES + Cell.CONTENT];`
* `fg = data[column * Constants.CELL_INDICIES + Cell.FG];`
* `bg = data[column * Constants.CELL_INDICIES + Cell.BG];`
*/
const enum Cell {
CONTENT = 0,
@@ -41,9 +36,6 @@ export const DEFAULT_ATTR_DATA = Object.freeze(new AttributeData());
let $startIndex = 0;
const $workCell = new CellData();
/** Factor when to cleanup underlying array buffer after shrinking. */
const CLEANUP_THRESHOLD = 2;
/**
* Typed array based bufferline implementation.
*
@@ -60,13 +52,21 @@ const CLEANUP_THRESHOLD = 2;
* memory allocs / GC pressure can be greatly reduced by reusing the CellData object.
*/
export class BufferLine implements IBufferLine {
/**
* Buffer memory layout:
*
* | uint32_t | uint32_t | uint32_t |
* |----------------------------------------|---------------------------------|---------------------------------|
* | `content` | `FG` | `BG` |
* | `wcwidth(2)` `comb(1)` `codepoint(21)` | `flags(8)` `R(8)` `G(8)` `B(8)` | `flags(8)` `R(8)` `G(8)` `B(8)` |
*/
protected _data: Uint32Array;
protected _combined: {[index: number]: string} = {};
protected _extendedAttrs: {[index: number]: IExtendedAttrs | undefined} = {};
public length: number;
constructor(cols: number, fillCellData?: ICellData, public isWrapped: boolean = false) {
this._data = new Uint32Array(cols * CELL_SIZE);
this._data = new Uint32Array(cols * Constants.CELL_INDICIES);
const cell = fillCellData ?? CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
for (let i = 0; i < cols; ++i) {
this.setCell(i, cell);
@@ -79,10 +79,10 @@ export class BufferLine implements IBufferLine {
* @deprecated
*/
public get(index: number): CharData {
const content = this._data[index * CELL_SIZE + Cell.CONTENT];
const content = this._data[index * Constants.CELL_INDICIES + Cell.CONTENT];
const cp = content & Content.CODEPOINT_MASK;
return [
this._data[index * CELL_SIZE + Cell.FG],
this._data[index * Constants.CELL_INDICIES + Cell.FG],
(content & Content.IS_COMBINED_MASK)
? this._combined[index]
: (cp) ? stringFromCodePoint(cp) : '',
@@ -98,12 +98,12 @@ export class BufferLine implements IBufferLine {
* @deprecated
*/
public set(index: number, value: CharData): void {
this._data[index * CELL_SIZE + Cell.FG] = value[CHAR_DATA_ATTR_INDEX];
this._data[index * Constants.CELL_INDICIES + Cell.FG] = value[CHAR_DATA_ATTR_INDEX];
if (value[CHAR_DATA_CHAR_INDEX].length > 1) {
this._combined[index] = value[1];
this._data[index * CELL_SIZE + Cell.CONTENT] = index | Content.IS_COMBINED_MASK | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = index | Content.IS_COMBINED_MASK | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
} else {
this._data[index * CELL_SIZE + Cell.CONTENT] = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
}
}
@@ -112,22 +112,22 @@ export class BufferLine implements IBufferLine {
* use these when only one value is needed, otherwise use `loadCell`
*/
public getWidth(index: number): number {
return this._data[index * CELL_SIZE + Cell.CONTENT] >> Content.WIDTH_SHIFT;
return this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] >> Content.WIDTH_SHIFT;
}
/** Test whether content has width. */
public hasWidth(index: number): number {
return this._data[index * CELL_SIZE + Cell.CONTENT] & Content.WIDTH_MASK;
return this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] & Content.WIDTH_MASK;
}
/** Get FG cell component. */
public getFg(index: number): number {
return this._data[index * CELL_SIZE + Cell.FG];
return this._data[index * Constants.CELL_INDICIES + Cell.FG];
}
/** Get BG cell component. */
public getBg(index: number): number {
return this._data[index * CELL_SIZE + Cell.BG];
return this._data[index * Constants.CELL_INDICIES + Cell.BG];
}
/**
@@ -136,7 +136,7 @@ export class BufferLine implements IBufferLine {
* from real empty cells.
*/
public hasContent(index: number): number {
return this._data[index * CELL_SIZE + Cell.CONTENT] & Content.HAS_CONTENT_MASK;
return this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] & Content.HAS_CONTENT_MASK;
}
/**
@@ -145,7 +145,7 @@ export class BufferLine implements IBufferLine {
* a single UTF32 codepoint or the last codepoint of a combined string.
*/
public getCodePoint(index: number): number {
const content = this._data[index * CELL_SIZE + Cell.CONTENT];
const content = this._data[index * Constants.CELL_INDICIES + Cell.CONTENT];
if (content & Content.IS_COMBINED_MASK) {
return this._combined[index].charCodeAt(this._combined[index].length - 1);
}
@@ -154,12 +154,12 @@ export class BufferLine implements IBufferLine {
/** Test whether the cell contains a combined string. */
public isCombined(index: number): number {
return this._data[index * CELL_SIZE + Cell.CONTENT] & Content.IS_COMBINED_MASK;
return this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] & Content.IS_COMBINED_MASK;
}
/** Returns the string content of the cell. */
public getString(index: number): string {
const content = this._data[index * CELL_SIZE + Cell.CONTENT];
const content = this._data[index * Constants.CELL_INDICIES + Cell.CONTENT];
if (content & Content.IS_COMBINED_MASK) {
return this._combined[index];
}
@@ -172,7 +172,7 @@ export class BufferLine implements IBufferLine {
/** Get state of protected flag. */
public isProtected(index: number): number {
return this._data[index * CELL_SIZE + Cell.BG] & BgFlags.PROTECTED;
return this._data[index * Constants.CELL_INDICIES + Cell.BG] & BgFlags.PROTECTED;
}
/**
@@ -180,7 +180,7 @@ export class BufferLine implements IBufferLine {
* to GC as it significantly reduced the amount of new objects/references needed.
*/
public loadCell(index: number, cell: ICellData): ICellData {
$startIndex = index * CELL_SIZE;
$startIndex = index * Constants.CELL_INDICIES;
cell.content = this._data[$startIndex + Cell.CONTENT];
cell.fg = this._data[$startIndex + Cell.FG];
cell.bg = this._data[$startIndex + Cell.BG];
@@ -203,9 +203,9 @@ export class BufferLine implements IBufferLine {
if (cell.bg & BgFlags.HAS_EXTENDED) {
this._extendedAttrs[index] = cell.extended;
}
this._data[index * CELL_SIZE + Cell.CONTENT] = cell.content;
this._data[index * CELL_SIZE + Cell.FG] = cell.fg;
this._data[index * CELL_SIZE + Cell.BG] = cell.bg;
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = cell.content;
this._data[index * Constants.CELL_INDICIES + Cell.FG] = cell.fg;
this._data[index * Constants.CELL_INDICIES + Cell.BG] = cell.bg;
}
/**
@@ -217,9 +217,9 @@ export class BufferLine implements IBufferLine {
if (attrs.bg & BgFlags.HAS_EXTENDED) {
this._extendedAttrs[index] = attrs.extended;
}
this._data[index * CELL_SIZE + Cell.CONTENT] = codePoint | (width << Content.WIDTH_SHIFT);
this._data[index * CELL_SIZE + Cell.FG] = attrs.fg;
this._data[index * CELL_SIZE + Cell.BG] = attrs.bg;
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = codePoint | (width << Content.WIDTH_SHIFT);
this._data[index * Constants.CELL_INDICIES + Cell.FG] = attrs.fg;
this._data[index * Constants.CELL_INDICIES + Cell.BG] = attrs.bg;
}
/**
@@ -229,7 +229,7 @@ export class BufferLine implements IBufferLine {
* by the previous `setDataFromCodePoint` call, we can omit it here.
*/
public addCodepointToCell(index: number, codePoint: number, width: number): void {
let content = this._data[index * CELL_SIZE + Cell.CONTENT];
let content = this._data[index * Constants.CELL_INDICIES + Cell.CONTENT];
if (content & Content.IS_COMBINED_MASK) {
// we already have a combined string, simply add
this._combined[index] += stringFromCodePoint(codePoint);
@@ -251,7 +251,7 @@ export class BufferLine implements IBufferLine {
content &= ~Content.WIDTH_MASK;
content |= width << Content.WIDTH_SHIFT;
}
this._data[index * CELL_SIZE + Cell.CONTENT] = content;
this._data[index * Constants.CELL_INDICIES + Cell.CONTENT] = content;
}
public insertCells(pos: number, n: number, fillCellData: ICellData): void {
@@ -344,13 +344,13 @@ export class BufferLine implements IBufferLine {
* The underlying array buffer will not change if there is still enough space
* to hold the new buffer line data.
* Returns a boolean indicating, whether a `cleanupMemory` call would free
* excess memory (true after shrinking > CLEANUP_THRESHOLD).
* excess memory (true after shrinking > Constants.CLEANUP_THRESHOLD).
*/
public resize(cols: number, fillCellData: ICellData): boolean {
if (cols === this.length) {
return this._data.length * 4 * CLEANUP_THRESHOLD < this._data.buffer.byteLength;
return this._data.length * 4 * Constants.CLEANUP_THRESHOLD < this._data.buffer.byteLength;
}
const uint32Cells = cols * CELL_SIZE;
const uint32Cells = cols * Constants.CELL_INDICIES;
if (cols > this.length) {
if (this._data.buffer.byteLength >= uint32Cells * 4) {
// optimization: avoid alloc and data copy if buffer has enough room
@@ -385,17 +385,17 @@ export class BufferLine implements IBufferLine {
}
}
this.length = cols;
return uint32Cells * 4 * CLEANUP_THRESHOLD < this._data.buffer.byteLength;
return uint32Cells * 4 * Constants.CLEANUP_THRESHOLD < this._data.buffer.byteLength;
}
/**
* Cleanup underlying array buffer.
* A cleanup will be triggered if the array buffer exceeds the actual used
* memory by a factor of CLEANUP_THRESHOLD.
* memory by a factor of Constants.CLEANUP_THRESHOLD.
* Returns 0 or 1 indicating whether a cleanup happened.
*/
public cleanupMemory(): number {
if (this._data.length * 4 * CLEANUP_THRESHOLD < this._data.buffer.byteLength) {
if (this._data.length * 4 * Constants.CLEANUP_THRESHOLD < this._data.buffer.byteLength) {
const data = new Uint32Array(this._data.length);
data.set(this._data);
this._data = data;
@@ -459,8 +459,8 @@ export class BufferLine implements IBufferLine {
public getTrimmedLength(): number {
for (let i = this.length - 1; i >= 0; --i) {
if ((this._data[i * CELL_SIZE + Cell.CONTENT] & Content.HAS_CONTENT_MASK)) {
return i + (this._data[i * CELL_SIZE + Cell.CONTENT] >> Content.WIDTH_SHIFT);
if ((this._data[i * Constants.CELL_INDICIES + Cell.CONTENT] & Content.HAS_CONTENT_MASK)) {
return i + (this._data[i * Constants.CELL_INDICIES + Cell.CONTENT] >> Content.WIDTH_SHIFT);
}
}
return 0;
@@ -468,8 +468,8 @@ export class BufferLine implements IBufferLine {
public getNoBgTrimmedLength(): number {
for (let i = this.length - 1; i >= 0; --i) {
if ((this._data[i * CELL_SIZE + Cell.CONTENT] & Content.HAS_CONTENT_MASK) || (this._data[i * CELL_SIZE + Cell.BG] & Attributes.CM_MASK)) {
return i + (this._data[i * CELL_SIZE + Cell.CONTENT] >> Content.WIDTH_SHIFT);
if ((this._data[i * Constants.CELL_INDICIES + Cell.CONTENT] & Content.HAS_CONTENT_MASK) || (this._data[i * Constants.CELL_INDICIES + Cell.BG] & Attributes.CM_MASK)) {
return i + (this._data[i * Constants.CELL_INDICIES + Cell.CONTENT] >> Content.WIDTH_SHIFT);
}
}
return 0;
@@ -479,19 +479,19 @@ export class BufferLine implements IBufferLine {
const srcData = src._data;
if (applyInReverse) {
for (let cell = length - 1; cell >= 0; cell--) {
for (let i = 0; i < CELL_SIZE; i++) {
this._data[(destCol + cell) * CELL_SIZE + i] = srcData[(srcCol + cell) * CELL_SIZE + i];
for (let i = 0; i < Constants.CELL_INDICIES; i++) {
this._data[(destCol + cell) * Constants.CELL_INDICIES + i] = srcData[(srcCol + cell) * Constants.CELL_INDICIES + i];
}
if (srcData[(srcCol + cell) * CELL_SIZE + Cell.BG] & BgFlags.HAS_EXTENDED) {
if (srcData[(srcCol + cell) * Constants.CELL_INDICIES + Cell.BG] & BgFlags.HAS_EXTENDED) {
this._extendedAttrs[destCol + cell] = src._extendedAttrs[srcCol + cell];
}
}
} else {
for (let cell = 0; cell < length; cell++) {
for (let i = 0; i < CELL_SIZE; i++) {
this._data[(destCol + cell) * CELL_SIZE + i] = srcData[(srcCol + cell) * CELL_SIZE + i];
for (let i = 0; i < Constants.CELL_INDICIES; i++) {
this._data[(destCol + cell) * Constants.CELL_INDICIES + i] = srcData[(srcCol + cell) * Constants.CELL_INDICIES + i];
}
if (srcData[(srcCol + cell) * CELL_SIZE + Cell.BG] & BgFlags.HAS_EXTENDED) {
if (srcData[(srcCol + cell) * Constants.CELL_INDICIES + Cell.BG] & BgFlags.HAS_EXTENDED) {
this._extendedAttrs[destCol + cell] = src._extendedAttrs[srcCol + cell];
}
}
@@ -531,7 +531,7 @@ export class BufferLine implements IBufferLine {
}
let result = '';
while (startCol < endCol) {
const content = this._data[startCol * CELL_SIZE + Cell.CONTENT];
const content = this._data[startCol * Constants.CELL_INDICIES + Cell.CONTENT];
const cp = content & Content.CODEPOINT_MASK;
const chars = (content & Content.IS_COMBINED_MASK) ? this._combined[startCol] : (cp) ? stringFromCodePoint(cp) : WHITESPACE_CELL_CHAR;
result += chars;