Skip to content

Commit

Permalink
Merge b57eaa8 into f3cd652
Browse files Browse the repository at this point in the history
  • Loading branch information
jerch committed Oct 29, 2018
2 parents f3cd652 + b57eaa8 commit 2b836fd
Show file tree
Hide file tree
Showing 11 changed files with 1,098 additions and 6 deletions.
5 changes: 4 additions & 1 deletion demo/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ function initOptions(term: TerminalType): void {
fontWeight: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
fontWeightBold: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
rendererType: ['dom', 'canvas'],
unicodeVersion: (term as any)._core.unicodeProvider.getRegisteredVersions(),
experimentalBufferLineImpl: ['JsArray', 'TypedArray']
};
const options = Object.keys((<any>term)._core.options);
Expand All @@ -219,7 +220,9 @@ function initOptions(term: TerminalType): void {
booleanOptions.push(o);
break;
case 'number':
numberOptions.push(o);
if (o !== 'unicodeVersion') {
numberOptions.push(o);
}
break;
default:
if (Object.keys(stringOptions).indexOf(o) === -1) {
Expand Down
2 changes: 1 addition & 1 deletion src/Buffer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ describe('Buffer', () => {
});

it('fullwidth combining with emoji - match emoji cell', () => {
const input = 'Lots of ¥\u0301 make me 😃.';
const input = 'Lots of ¥\u0301 make me very 😃.';
terminal.writeSync(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
Expand Down
3 changes: 2 additions & 1 deletion src/InputHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { C0, C1 } from './common/data/EscapeSequences';
import { CHARSETS, DEFAULT_CHARSET } from './core/data/Charsets';
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CODE_INDEX, DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE } from './Buffer';
import { FLAGS } from './renderer/Types';
import { wcwidth } from './CharWidth';
import { EscapeSequenceParser } from './EscapeSequenceParser';
import { ICharset } from './core/Types';
import { Disposable } from './common/Lifecycle';
Expand Down Expand Up @@ -315,6 +314,7 @@ export class InputHandler extends Disposable implements IInputHandler {
const wraparoundMode: boolean = this._terminal.wraparoundMode;
const insertMode: boolean = this._terminal.insertMode;
const curAttr: number = this._terminal.curAttr;
const wcwidth = this._terminal.unicodeProvider.wcwidth;
let bufferRow = buffer.lines.get(buffer.y + buffer.ybase);

this._terminal.updateRange(buffer.y);
Expand Down Expand Up @@ -342,6 +342,7 @@ export class InputHandler extends Disposable implements IInputHandler {

// calculate print space
// expensive call, therefore we save width in line buffer
// chWidth = wcwidth(code);
chWidth = wcwidth(code);

// get charset replacement character
Expand Down
3 changes: 1 addition & 2 deletions src/Linkifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { ILinkHoverEvent, ILinkMatcher, LinkMatcherHandler, LinkHoverEventTypes,
import { MouseZone } from './ui/MouseZoneManager';
import { EventEmitter } from './common/EventEmitter';
import { CHAR_DATA_ATTR_INDEX } from './Buffer';
import { getStringCellWidth } from './CharWidth';

/**
* The Linkifier applies links to rows shortly after they have been refreshed.
Expand Down Expand Up @@ -256,7 +255,7 @@ export class Linkifier extends EventEmitter implements ILinkifier {
* @param fg The link color for hover event.
*/
private _addLink(x: number, y: number, uri: string, matcher: ILinkMatcher, fg: number): void {
const width = getStringCellWidth(uri);
const width = (this._terminal as any).unicodeProvider.getStringCellWidth(uri);
const x1 = x % this._terminal.cols;
const y1 = y + Math.floor(x / this._terminal.cols);
let x2 = (x1 + width) % this._terminal.cols;
Expand Down
6 changes: 6 additions & 0 deletions src/Terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import { DomRenderer } from './renderer/dom/DomRenderer';
import { IKeyboardEvent } from './common/Types';
import { evaluateKeyboardEvent } from './core/input/Keyboard';
import { KeyboardResultType, ICharset } from './core/Types';
import { UnicodeProvider } from './UnicodeProvider';

// Let it work inside Node.js for automated testing purposes.
const document = (typeof window !== 'undefined') ? window.document : null;
Expand Down Expand Up @@ -106,6 +107,7 @@ const DEFAULT_OPTIONS: ITerminalOptions = {
theme: null,
rightClickSelectsWord: Browser.isMac,
rendererType: 'canvas',
unicodeVersion: 11,
experimentalBufferLineImpl: 'JsArray'
};

Expand Down Expand Up @@ -194,6 +196,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
private _userScrolling: boolean;

private _inputHandler: InputHandler;
public unicodeProvider: UnicodeProvider;
public soundManager: SoundManager;
public renderer: IRenderer;
public selectionManager: SelectionManager;
Expand Down Expand Up @@ -300,6 +303,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
// this._writeStopped = false;
this._userScrolling = false;

this.unicodeProvider = new UnicodeProvider();
this.register(this.unicodeProvider);
this._inputHandler = new InputHandler(this);
this.register(this._inputHandler);
// Reuse renderer if the Terminal is being recreated via a reset call.
Expand Down Expand Up @@ -494,6 +499,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
}
break;
case 'tabStopWidth': this.buffers.setupTabStops(); break;
case 'unicodeVersion': this.unicodeProvider.setActiveVersion(parseFloat(value)); break;
case 'experimentalBufferLineImpl':
this.buffers.normal.setBufferLineFactory(value);
this.buffers.alt.setBufferLineFactory(value);
Expand Down
18 changes: 18 additions & 0 deletions src/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export interface IInputHandlingTerminal extends IEventEmitter {
handleTitle(title: string): void;
index(): void;
reverseIndex(): void;
unicodeProvider: IUnicodeProvider;
}

export interface IViewport extends IDisposable {
Expand Down Expand Up @@ -529,3 +530,20 @@ export interface IBufferLine {
export interface IBufferLineConstructor {
new(cols: number, fillCharData?: CharData, isWrapped?: boolean): IBufferLine;
}

/**
* Interface for unicode version implementations.
*/
export interface IUnicodeImplementation {
version: number;
wcwidth(ucs: number): number;
}

export interface IUnicodeProvider {
addRegisterListener(callback: (version: number, provider: IUnicodeProvider) => void): void;
getRegisteredVersions(): number[];
getActiveVersion(): number;
setActiveVersion(version: number, mode?: 'exact' | 'closest' | 'next' | 'previous'): number;
wcwidth(ucs: number): number;
getStringCellWidth(s: string): number;
}
144 changes: 144 additions & 0 deletions src/UnicodeProvider.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { assert } from 'chai';
import { UnicodeProvider } from './UnicodeProvider';
import { IUnicodeImplementation } from './Types';

const VERSION_DUMMY1: IUnicodeImplementation = {
version: 15,
wcwidth: (n: number) => n
};
const VERSION_DUMMY2: IUnicodeImplementation = {
version: 17,
wcwidth: (n: number) => n
};

describe('UnicodeProvider', function(): void {
describe('static part', function(): void {

it('provided default versions', function(): void {
assert.deepEqual(UnicodeProvider.getRegisteredVersions(), [6, 11]);
});

it('add version', function(): void {
UnicodeProvider.registerVersion(VERSION_DUMMY1);
assert.deepEqual(UnicodeProvider.getRegisteredVersions(), [6, 11, 15]);
delete UnicodeProvider.versions[15];
});

it('register callback', function(): void {
UnicodeProvider.addRegisterListener((version) => {
assert.equal(version, 15);
});
UnicodeProvider.registerVersion(VERSION_DUMMY1);
delete UnicodeProvider.versions[15];
UnicodeProvider.removeAllRegisterListener();
});

it('remove callback', function(): void {
let gotCalled = false;
const listener = (version: number) => {
assert.equal(version, 15);
gotCalled = true;
};
UnicodeProvider.addRegisterListener(listener);
UnicodeProvider.registerVersion(VERSION_DUMMY1);
assert.equal(gotCalled, true);
gotCalled = false;
UnicodeProvider.removeRegisterListener(listener);
UnicodeProvider.registerVersion(VERSION_DUMMY2);
assert.equal(gotCalled, false);
delete UnicodeProvider.versions[15];
delete UnicodeProvider.versions[17];
UnicodeProvider.removeAllRegisterListener();
});
});
describe('instance', function(): void {
let provider: UnicodeProvider;

beforeEach(function(): void {
provider = new UnicodeProvider();
});

it('highest version activated by default', function(): void {
assert.equal(provider.getActiveVersion(), 11);
});

it('activate nearest version', function(): void {
provider.setActiveVersion(0);
assert.equal(provider.getActiveVersion(), 6);
provider.setActiveVersion(5);
assert.equal(provider.getActiveVersion(), 6);
provider.setActiveVersion(7);
assert.equal(provider.getActiveVersion(), 6);
provider.setActiveVersion(8);
assert.equal(provider.getActiveVersion(), 6);
provider.setActiveVersion(10);
assert.equal(provider.getActiveVersion(), 11);
provider.setActiveVersion(13);
assert.equal(provider.getActiveVersion(), 11);
});

it('activate next lower', function(): void {
provider.setActiveVersion(15, 'previous');
assert.equal(provider.getActiveVersion(), 11);
provider.setActiveVersion(11, 'previous');
assert.equal(provider.getActiveVersion(), 11);
provider.setActiveVersion(10.5, 'previous');
assert.equal(provider.getActiveVersion(), 6);
provider.setActiveVersion(5, 'previous');
assert.equal(provider.getActiveVersion(), 6);
});

it('activate next higher', function(): void {
provider.setActiveVersion(5, 'next');
assert.equal(provider.getActiveVersion(), 6);
provider.setActiveVersion(6, 'next');
assert.equal(provider.getActiveVersion(), 6);
provider.setActiveVersion(10.5, 'next');
assert.equal(provider.getActiveVersion(), 11);
provider.setActiveVersion(15, 'next');
assert.equal(provider.getActiveVersion(), 11);
});

it('activate exact', function(): void {
assert.throws(() => provider.setActiveVersion(5, 'exact'));
assert.throws(() => provider.setActiveVersion(7, 'exact'));
assert.throws(() => provider.setActiveVersion(10, 'exact'));
assert.throws(() => provider.setActiveVersion(12, 'exact'));
assert.throws(() => provider.setActiveVersion(200, 'exact'));
assert.doesNotThrow(() => provider.setActiveVersion(6, 'exact'));
assert.doesNotThrow(() => provider.setActiveVersion(11, 'exact'));
});

it('register/remove callback', function(): void {
let gotCalled = false;
const listener = (version: number, prov: UnicodeProvider) => {
assert.equal(version, 15);
assert.equal(prov, provider);
gotCalled = true;
};
provider.addRegisterListener(listener);
UnicodeProvider.registerVersion(VERSION_DUMMY1);
assert.equal(gotCalled, true);
gotCalled = false;
provider.removeRegisterListener(listener);
UnicodeProvider.registerVersion(VERSION_DUMMY2);
assert.equal(gotCalled, false);
delete UnicodeProvider.versions[15];
delete UnicodeProvider.versions[17];
UnicodeProvider.removeAllRegisterListener();
provider.dispose();
});

it('unicode test', function(): void {
const data = '🔷🔷🔷🔷🔷';
provider.setActiveVersion(6);
assert.equal(provider.getStringCellWidth(data), 5);
provider.setActiveVersion(11);
assert.equal(provider.getStringCellWidth(data), 10);
});
});
});
Loading

0 comments on commit 2b836fd

Please sign in to comment.