The import/no-cycle refactor had moved IBuffer, IBufferSet, and related cell/line types into src/common/Types.ts, with buffer/Types.ts only re-exporting them. That inverted the natural module boundary and made buffer code depend on the top-level types hub. Define buffer-owned types in buffer/Types.ts instead: - CharData, IExtendedAttrs, IAttributeData, ICellData, IBufferLine - IMarker, IBuffer, IBufferSet, BufferIndex Restore UnderlineStyle to buffer/Constants.ts (used by IExtendedAttrs) and remove those definitions from Types.ts. buffer/Types.ts imports only what it needs from outside the buffer layer: ICircularList and ICharset from Types, IDisposable from Lifecycle, IEvent from Event, and UnderlineStyle from Constants. Types.ts does not import buffer/Types.ts, so the previous Types <-> buffer cycle stays broken. Update imports across common, browser, headless, addons, and tests to use common/buffer/Types for buffer types rather than common/Types. Co-authored-by: Cursor <cursoragent@cursor.com>
152 lines
4.9 KiB
TypeScript
152 lines
4.9 KiB
TypeScript
/**
|
|
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
|
* @license MIT
|
|
*/
|
|
|
|
import { CharData, ICellData, IExtendedAttrs } from './Types';
|
|
import { stringFromCodePoint } from '../input/TextDecoder';
|
|
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_ATTR_INDEX, Content } from './Constants';
|
|
import { AttributeData, ExtendedAttrs } from './AttributeData';
|
|
import type { IBufferCell as IBufferCellApi } from '@xterm/xterm';
|
|
|
|
/**
|
|
* CellData - represents a single Cell in the terminal buffer.
|
|
*/
|
|
export class CellData extends AttributeData implements ICellData {
|
|
/** Helper to create CellData from CharData. */
|
|
public static fromCharData(value: CharData): CellData {
|
|
const obj = new CellData();
|
|
obj.setFromCharData(value);
|
|
return obj;
|
|
}
|
|
/** Primitives from terminal buffer. */
|
|
public content = 0;
|
|
public fg = 0;
|
|
public bg = 0;
|
|
public extended: IExtendedAttrs = new ExtendedAttrs();
|
|
public combinedData = '';
|
|
/** Whether cell contains a combined string. */
|
|
public isCombined(): number {
|
|
return this.content & Content.IS_COMBINED_MASK;
|
|
}
|
|
/** Width of the cell. */
|
|
public getWidth(): number {
|
|
return this.content >> Content.WIDTH_SHIFT;
|
|
}
|
|
/** JS string of the content. */
|
|
public getChars(): string {
|
|
if (this.content & Content.IS_COMBINED_MASK) {
|
|
return this.combinedData;
|
|
}
|
|
if (this.content & Content.CODEPOINT_MASK) {
|
|
return stringFromCodePoint(this.content & Content.CODEPOINT_MASK);
|
|
}
|
|
return '';
|
|
}
|
|
/**
|
|
* Codepoint of cell
|
|
* Note this returns the UTF32 codepoint of single chars,
|
|
* if content is a combined string it returns the codepoint
|
|
* of the last char in string to be in line with code in CharData.
|
|
*/
|
|
public getCode(): number {
|
|
return (this.isCombined())
|
|
? this.combinedData.charCodeAt(this.combinedData.length - 1)
|
|
: this.content & Content.CODEPOINT_MASK;
|
|
}
|
|
/** Set data from CharData */
|
|
public setFromCharData(value: CharData): void {
|
|
this.fg = value[CHAR_DATA_ATTR_INDEX];
|
|
this.bg = 0;
|
|
let combined = false;
|
|
// surrogates and combined strings need special treatment
|
|
if (value[CHAR_DATA_CHAR_INDEX].length > 2) {
|
|
combined = true;
|
|
}
|
|
else if (value[CHAR_DATA_CHAR_INDEX].length === 2) {
|
|
const code = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0);
|
|
// if the 2-char string is a surrogate create single codepoint
|
|
// everything else is combined
|
|
if (0xD800 <= code && code <= 0xDBFF) {
|
|
const second = value[CHAR_DATA_CHAR_INDEX].charCodeAt(1);
|
|
if (0xDC00 <= second && second <= 0xDFFF) {
|
|
this.content = ((code - 0xD800) * 0x400 + second - 0xDC00 + 0x10000) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
|
|
}
|
|
else {
|
|
combined = true;
|
|
}
|
|
}
|
|
else {
|
|
combined = true;
|
|
}
|
|
}
|
|
else {
|
|
this.content = value[CHAR_DATA_CHAR_INDEX].charCodeAt(0) | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
|
|
}
|
|
if (combined) {
|
|
this.combinedData = value[CHAR_DATA_CHAR_INDEX];
|
|
this.content = Content.IS_COMBINED_MASK | (value[CHAR_DATA_WIDTH_INDEX] << Content.WIDTH_SHIFT);
|
|
}
|
|
}
|
|
/** Get data as CharData. */
|
|
public getAsCharData(): CharData {
|
|
return [this.fg, this.getChars(), this.getWidth(), this.getCode()];
|
|
}
|
|
|
|
public attributesEquals(other: IBufferCellApi): boolean {
|
|
if (this.getFgColorMode() !== other.getFgColorMode() || this.getFgColor() !== other.getFgColor()) {
|
|
return false;
|
|
}
|
|
if (this.getBgColorMode() !== other.getBgColorMode() || this.getBgColor() !== other.getBgColor()) {
|
|
return false;
|
|
}
|
|
if (this.isInverse() !== other.isInverse()) {
|
|
return false;
|
|
}
|
|
if (this.isBold() !== other.isBold()) {
|
|
return false;
|
|
}
|
|
if (this.isUnderline() !== other.isUnderline()) {
|
|
return false;
|
|
}
|
|
if (this.isUnderline()) {
|
|
if (this.getUnderlineStyle() !== other.getUnderlineStyle()) {
|
|
return false;
|
|
}
|
|
const thisDefault = this.isUnderlineColorDefault();
|
|
const otherDefault = other.isUnderlineColorDefault();
|
|
if (!(thisDefault && otherDefault)) {
|
|
if (thisDefault !== otherDefault) {
|
|
return false;
|
|
}
|
|
if (this.getUnderlineColor() !== other.getUnderlineColor()) {
|
|
return false;
|
|
}
|
|
if (this.getUnderlineColorMode() !== other.getUnderlineColorMode()) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if (this.isOverline() !== other.isOverline()) {
|
|
return false;
|
|
}
|
|
if (this.isBlink() !== other.isBlink()) {
|
|
return false;
|
|
}
|
|
if (this.isInvisible() !== other.isInvisible()) {
|
|
return false;
|
|
}
|
|
if (this.isItalic() !== other.isItalic()) {
|
|
return false;
|
|
}
|
|
if (this.isDim() !== other.isDim()) {
|
|
return false;
|
|
}
|
|
if (this.isStrikethrough() !== other.isStrikethrough()) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|