87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
/**
|
|
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
|
* @license MIT
|
|
*/
|
|
import { IUnicodeService, IUnicodeVersionProvider } from 'common/services/Services';
|
|
import { EventEmitter, IEvent } from 'common/EventEmitter';
|
|
import { UnicodeV6 } from 'common/input/UnicodeV6';
|
|
|
|
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 EventEmitter<string>();
|
|
public readonly onChange = this._onChange.event;
|
|
|
|
constructor() {
|
|
const defaultProvider = new UnicodeV6();
|
|
this.register(defaultProvider);
|
|
this._active = defaultProvider.version;
|
|
this._activeProvider = defaultProvider;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Unicode version dependent interface.
|
|
*/
|
|
public wcwidth(num: number): number {
|
|
return this._activeProvider.wcwidth(num);
|
|
}
|
|
|
|
public getStringCellWidth(s: string): number {
|
|
let result = 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);
|
|
}
|
|
}
|
|
result += this.wcwidth(code);
|
|
}
|
|
return result;
|
|
}
|
|
}
|