change to v11, expose unicodeVersion, fix linkifier

This commit is contained in:
Jörg Breitbart
2019-11-15 18:08:17 +01:00
parent 25bbde2be2
commit aca6d24e96
10 changed files with 48 additions and 36 deletions
+1 -1
View File
@@ -257,7 +257,7 @@ function initOptions(term: TerminalType): void {
logLevel: ['debug', 'info', 'warn', 'error', 'off'],
rendererType: ['dom', 'canvas'],
wordSeparator: null,
unicodeVersion: ['6', '10']
unicodeVersion: ['6', '11']
};
const options = Object.keys((<any>term)._core.options);
const booleanOptions = [];
+3 -3
View File
@@ -7,7 +7,7 @@
import { IInputHandler, IInputHandlingTerminal } from './Types';
import { C0, C1 } from 'common/data/EscapeSequences';
import { CHARSETS, DEFAULT_CHARSET } from 'common/data/Charsets';
import { wcwidthV6, wcwidthV10 } from 'common/CharWidth';
import { wcwidthV6, wcwidthV11 } from 'common/CharWidth';
import { EscapeSequenceParser } from 'common/parser/EscapeSequenceParser';
import { Disposable } from 'common/Lifecycle';
import { concat } from 'common/TypedArrayUtils';
@@ -147,10 +147,10 @@ export class InputHandler extends Disposable implements IInputHandler {
private readonly _parser: IEscapeSequenceParser = new EscapeSequenceParser())
{
super();
this._wcwidth = this._optionsService.options.unicodeVersion === '10' ? wcwidthV10 : wcwidthV6;
this._wcwidth = this._optionsService.options.unicodeVersion === '11' ? wcwidthV11 : wcwidthV6;
this._optionsService.onOptionChange(option => {
if (option === 'unicodeVersion') {
this._wcwidth = this._optionsService.options.unicodeVersion === '10' ? wcwidthV10 : wcwidthV6;
this._wcwidth = this._optionsService.options.unicodeVersion === '11' ? wcwidthV11 : wcwidthV6;
}
});
+2 -2
View File
@@ -10,7 +10,7 @@ import { CellData } from 'common/buffer/CellData';
import { wcwidthV6 } from 'common/CharWidth';
import { IBufferService } from 'common/services/Services';
import { Linkifier } from 'browser/Linkifier';
import { MockLogService } from 'common/TestUtils.test';
import { MockLogService, MockOptionsService } from 'common/TestUtils.test';
import { IRegisteredLinkMatcher, IMouseZoneManager, IMouseZone } from 'browser/Types';
const INIT_COLS = 80;
@@ -1371,7 +1371,7 @@ describe('Terminal', () => {
class TestLinkifier extends Linkifier {
constructor(bufferService: IBufferService) {
super(bufferService, new MockLogService());
super(bufferService, new MockLogService(), new MockOptionsService());
Linkifier._timeBeforeLatency = 0;
}
+1 -1
View File
@@ -281,7 +281,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp
this._inputHandler.onLineFeed(() => this._onLineFeed.fire());
this.register(this._inputHandler);
this.linkifier = this.linkifier || new Linkifier(this._bufferService, this._logService);
this.linkifier = this.linkifier || new Linkifier(this._bufferService, this._logService, this.optionsService);
if (this.options.windowsMode) {
this._windowsMode = applyWindowsMode(this);
+2 -2
View File
@@ -9,12 +9,12 @@ import { IBufferLine } from 'common/Types';
import { Linkifier } from 'browser/Linkifier';
import { BufferLine } from 'common/buffer/BufferLine';
import { CellData } from 'common/buffer/CellData';
import { MockLogService, MockBufferService } from 'common/TestUtils.test';
import { MockLogService, MockBufferService, MockOptionsService } from 'common/TestUtils.test';
import { IBufferService } from 'common/services/Services';
class TestLinkifier extends Linkifier {
constructor(bufferService: IBufferService) {
super(bufferService, new MockLogService());
super(bufferService, new MockLogService(), new MockOptionsService());
Linkifier._timeBeforeLatency = 0;
}
+5 -5
View File
@@ -5,9 +5,9 @@
import { ILinkifierEvent, ILinkMatcher, LinkMatcherHandler, ILinkMatcherOptions, ILinkifier, IMouseZoneManager, IMouseZone, IRegisteredLinkMatcher } from 'browser/Types';
import { IBufferStringIteratorResult } from 'common/buffer/Types';
import { getStringCellWidthV6 } from 'common/CharWidth';
import { getStringCellWidthV6, getStringCellWidthV11 } from 'common/CharWidth';
import { EventEmitter, IEvent } from 'common/EventEmitter';
import { ILogService, IBufferService } from 'common/services/Services';
import { ILogService, IBufferService, IOptionsService } from 'common/services/Services';
/**
* Limit of the unwrapping line expansion (overscan) at the top and bottom
@@ -45,7 +45,8 @@ export class Linkifier implements ILinkifier {
constructor(
protected readonly _bufferService: IBufferService,
private readonly _logService: ILogService
private readonly _logService: ILogService,
private readonly _optionsService: IOptionsService
) {
this._rowsToLinkify = {
start: undefined,
@@ -277,8 +278,7 @@ export class Linkifier implements ILinkifier {
if (!this._mouseZoneManager || !this._element) {
return;
}
const width = getStringCellWidthV6(uri); // FIXME: apply options.unicodeVersion
const width = this._optionsService.options.unicodeVersion === '11' ? getStringCellWidthV11(uri) : getStringCellWidthV6(uri);
const x1 = x % this._bufferService.cols;
const y1 = y + Math.floor(x / this._bufferService.cols);
let x2 = (x1 + width) % this._bufferService.cols;
+8 -1
View File
@@ -4,7 +4,7 @@
*/
import { assert } from 'chai';
import { wcwidthV6 } from 'common/CharWidth';
import { wcwidthV6, getStringCellWidthV6, getStringCellWidthV11 } from 'common/CharWidth';
it('wcwidth should match all values from the old implementation', function(): void {
// old implementation
@@ -180,3 +180,10 @@ it('wcwidth should match all values from the old implementation', function(): vo
assert.equal(wcwidthV6(i), wcwidthOld(i), `mismatch for i: ${i}`);
}
});
it('wcwidth V6 vs. V11', () => {
const widthV6 = getStringCellWidthV6('🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣');
assert.equal(widthV6, 10);
const widthV10 = getStringCellWidthV11('🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣');
assert.equal(widthV10, 20);
});
+19 -19
View File
@@ -159,7 +159,7 @@ export function getStringCellWidthV6(s: string): number {
/**
* Unicode version 10
*/
const BMP_COMBINING_V10 = [
const BMP_COMBINING_V11 = [
[0x0300, 0x036F], [0x0483, 0x0489], [0x0591, 0x05BD],
[0x05BF, 0x05BF], [0x05C1, 0x05C2], [0x05C4, 0x05C5],
[0x05C7, 0x05C7], [0x0600, 0x0605], [0x0610, 0x061A],
@@ -234,7 +234,7 @@ const BMP_COMBINING_V10 = [
[0xFFF9, 0xFFFB]
];
const HIGH_COMBINING_V10 = [
const HIGH_COMBINING_V11 = [
[0x101FD, 0x101FD], [0x102E0, 0x102E0],
[0x10376, 0x1037A], [0x10A01, 0x10A03], [0x10A05, 0x10A06],
[0x10A0C, 0x10A0F], [0x10A38, 0x10A3A], [0x10A3F, 0x10A3F],
@@ -277,7 +277,7 @@ const HIGH_COMBINING_V10 = [
[0xE0100, 0xE01EF]
];
const BMP_WIDE_V10 = [
const BMP_WIDE_V11 = [
[0x1100, 0x115F], [0x231A, 0x231B], [0x2329, 0x232A],
[0x23E9, 0x23EC], [0x23F0, 0x23F0], [0x23F3, 0x23F3],
[0x25FD, 0x25FE], [0x2614, 0x2615], [0x2648, 0x2653],
@@ -301,7 +301,7 @@ const BMP_WIDE_V10 = [
[0xFFE0, 0xFFE6]
];
const HIGH_WIDE_V10 = [
const HIGH_WIDE_V11 = [
[0x16FE0, 0x16FE3], [0x17000, 0x187F7],
[0x18800, 0x18AF2], [0x1B000, 0x1B11E], [0x1B150, 0x1B152],
[0x1B164, 0x1B167], [0x1B170, 0x1B2FB], [0x1F004, 0x1F004],
@@ -322,27 +322,27 @@ const HIGH_WIDE_V10 = [
[0x1FA90, 0x1FA95], [0x20000, 0x2FFFD], [0x30000, 0x3FFFD]
];
const BMP_TABLE_V10 = new Uint8Array(65536);
fill(BMP_TABLE_V10, 1);
BMP_TABLE_V10[0] = 0;
fill(BMP_TABLE_V10, 0, 1, 32);
fill(BMP_TABLE_V10, 0, 0x7f, 0xa0);
for (let r = 0; r < BMP_COMBINING_V10.length; ++r) {
fill(BMP_TABLE_V10, 0, BMP_COMBINING_V10[r][0], BMP_COMBINING_V10[r][1] + 1);
const BMP_TABLE_V11 = new Uint8Array(65536);
fill(BMP_TABLE_V11, 1);
BMP_TABLE_V11[0] = 0;
fill(BMP_TABLE_V11, 0, 1, 32);
fill(BMP_TABLE_V11, 0, 0x7f, 0xa0);
for (let r = 0; r < BMP_COMBINING_V11.length; ++r) {
fill(BMP_TABLE_V11, 0, BMP_COMBINING_V11[r][0], BMP_COMBINING_V11[r][1] + 1);
}
for (let r = 0; r < BMP_WIDE_V10.length; ++r) {
fill(BMP_TABLE_V10, 2, BMP_WIDE_V10[r][0], BMP_WIDE_V10[r][1] + 1);
for (let r = 0; r < BMP_WIDE_V11.length; ++r) {
fill(BMP_TABLE_V11, 2, BMP_WIDE_V11[r][0], BMP_WIDE_V11[r][1] + 1);
}
export function wcwidthV10(num: number): number {
export function wcwidthV11(num: number): number {
if (num < 32) return 0;
if (num < 127) return 1;
if (num < 65536) return BMP_TABLE_V10[num];
if (bisearch(num, HIGH_COMBINING_V10)) return 0;
if (bisearch(num, HIGH_WIDE_V10)) return 2;
if (num < 65536) return BMP_TABLE_V11[num];
if (bisearch(num, HIGH_COMBINING_V11)) return 0;
if (bisearch(num, HIGH_WIDE_V11)) return 2;
return 1;
}
export function getStringCellWidthV10(s: string): number {
return getStringCellWidthPrivate(wcwidthV10, s);
export function getStringCellWidthV11(s: string): number {
return getStringCellWidthPrivate(wcwidthV11, s);
}
+2 -2
View File
@@ -212,7 +212,7 @@ export interface IPartialTerminalOptions {
scrollSensitivity?: number;
tabStopWidth?: number;
theme?: ITheme;
unicodeVersion?: '6' | '10';
unicodeVersion?: '6' | '11';
windowsMode?: boolean;
wordSeparator?: string;
}
@@ -245,7 +245,7 @@ export interface ITerminalOptions {
scrollSensitivity: number;
tabStopWidth: number;
theme: ITheme;
unicodeVersion: '6' | '10';
unicodeVersion: '6' | '11';
windowsMode: boolean;
wordSeparator: string;
+5
View File
@@ -198,6 +198,11 @@ declare module 'xterm' {
*/
theme?: ITheme;
/**
* Unicode version to be used for wcwidth. Default is version 6.
*/
unicodeVersion?: '6' | '11';
/**
* Whether "Windows mode" is enabled. Because Windows backends winpty and
* conpty operate by doing line wrapping on their side, xterm.js does not