Enable oxlint's import/no-cycle rule (import plugin) so circular module dependencies are caught in CI, similar to eslint-plugin-import/no-cycle and biome no-import-cycles discussed in the issue. Relocate shared types and dependencies to remove cycles under src/common: - Types.ts: host IInsertEvent, IDeleteEvent, IParams, UnderlineStyle, IBuffer, and IBufferSet; drop imports from CircularList, buffer/Types, parser/Types, and Services - CoreTerminal.ts: define and export ICoreTerminal - ServiceRegistry.ts: define IServiceIdentifier (break Services registry loop) - UnicodeService: stop constructing UnicodeV6; CoreTerminal registers the default v6 provider after service creation - buffer/Types.ts and parser/Types.ts: re-export moved types for callers Fixes https://github.com/xtermjs/xterm.js/issues/5897 Co-authored-by: Cursor <cursoragent@cursor.com>
107 lines
3.5 KiB
TypeScript
107 lines
3.5 KiB
TypeScript
/**
|
|
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
|
* @license MIT
|
|
*/
|
|
|
|
import { IUnicodeService, IUnicodeVersionProvider, UnicodeCharProperties, UnicodeCharWidth } from './Services';
|
|
import { Emitter } from '../Event';
|
|
|
|
export class UnicodeService implements IUnicodeService {
|
|
public serviceBrand: any;
|
|
|
|
private _providers: {[key: string]: IUnicodeVersionProvider} = Object.create(null);
|
|
private _active: string = '';
|
|
private _activeProvider!: IUnicodeVersionProvider;
|
|
|
|
private readonly _onChange = new Emitter<string>();
|
|
public readonly onChange = this._onChange.event;
|
|
|
|
public static extractShouldJoin(value: UnicodeCharProperties): boolean {
|
|
return (value & 1) !== 0;
|
|
}
|
|
public static extractWidth(value: UnicodeCharProperties): UnicodeCharWidth {
|
|
return ((value >> 1) & 0x3) as UnicodeCharWidth;
|
|
}
|
|
public static extractCharKind(value: UnicodeCharProperties): number {
|
|
return value >> 3;
|
|
}
|
|
public static createPropertyValue(state: number, width: number, shouldJoin: boolean = false): UnicodeCharProperties {
|
|
return ((state & 0xffffff) << 3) | ((width & 3) << 1) | (shouldJoin?1:0);
|
|
}
|
|
|
|
public dispose(): void {
|
|
this._onChange.dispose();
|
|
}
|
|
|
|
public get versions(): string[] {
|
|
return Object.keys(this._providers);
|
|
}
|
|
|
|
public get activeVersion(): string {
|
|
return this._active;
|
|
}
|
|
|
|
public set activeVersion(version: string) {
|
|
if (!this._providers[version]) {
|
|
throw new Error(`unknown Unicode version "${version}"`);
|
|
}
|
|
this._active = version;
|
|
this._activeProvider = this._providers[version];
|
|
this._onChange.fire(version);
|
|
}
|
|
|
|
public register(provider: IUnicodeVersionProvider): void {
|
|
this._providers[provider.version] = provider;
|
|
if (!this._active) {
|
|
this.activeVersion = provider.version;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Unicode version dependent interface.
|
|
*/
|
|
public wcwidth(num: number): UnicodeCharWidth {
|
|
return this._activeProvider.wcwidth(num);
|
|
}
|
|
|
|
public getStringCellWidth(s: string): number {
|
|
let result = 0;
|
|
let precedingInfo = 0;
|
|
const length = s.length;
|
|
for (let i = 0; i < length; ++i) {
|
|
let code = s.charCodeAt(i);
|
|
// surrogate pair first
|
|
if (0xD800 <= code && code <= 0xDBFF) {
|
|
if (++i >= length) {
|
|
// this should not happen with strings retrieved from
|
|
// Buffer.translateToString as it converts from UTF-32
|
|
// and therefore always should contain the second part
|
|
// for any other string we still have to handle it somehow:
|
|
// simply treat the lonely surrogate first as a single char (UCS-2 behavior)
|
|
return result + this.wcwidth(code);
|
|
}
|
|
const second = s.charCodeAt(i);
|
|
// convert surrogate pair to high codepoint only for valid second part (UTF-16)
|
|
// otherwise treat them independently (UCS-2 behavior)
|
|
if (0xDC00 <= second && second <= 0xDFFF) {
|
|
code = (code - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
|
|
} else {
|
|
result += this.wcwidth(second);
|
|
}
|
|
}
|
|
const currentInfo = this.charProperties(code, precedingInfo);
|
|
let chWidth = UnicodeService.extractWidth(currentInfo);
|
|
if (UnicodeService.extractShouldJoin(currentInfo)) {
|
|
chWidth -= UnicodeService.extractWidth(precedingInfo);
|
|
}
|
|
result += chWidth;
|
|
precedingInfo = currentInfo;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public charProperties(codepoint: number, preceding: UnicodeCharProperties): UnicodeCharProperties {
|
|
return this._activeProvider.charProperties(codepoint, preceding);
|
|
}
|
|
}
|