Skip to content

Commit

Permalink
Merge pull request #440 from Tyriar/439_wide_char_class
Browse files Browse the repository at this point in the history
Style wide characters at charWidth*2 in DOM
  • Loading branch information
Tyriar authored Jan 9, 2017
2 parents facc265 + 9385b93 commit e9da2a6
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 34 deletions.
26 changes: 10 additions & 16 deletions src/Viewport.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { assert } from 'chai';
import { Viewport } from './Viewport';

describe('Viewport', () => {
var terminal;
var viewportElement;
var charMeasureElement;
var viewport;
var scrollAreaElement;
let terminal;
let viewportElement;
let charMeasure;
let viewport;
let scrollAreaElement;

const CHARACTER_HEIGHT = 10;

Expand Down Expand Up @@ -34,21 +34,17 @@ describe('Viewport', () => {
height: 0
}
};
charMeasureElement = {
getBoundingClientRect: () => {
return { width: null, height: CHARACTER_HEIGHT };
}
charMeasure = {
height: CHARACTER_HEIGHT
};
viewport = new Viewport(terminal, viewportElement, scrollAreaElement, charMeasureElement);
viewport = new Viewport(terminal, viewportElement, scrollAreaElement, charMeasure);
});

describe('refresh', () => {
it('should set the line-height of the terminal', () => {
assert.equal(viewportElement.style.lineHeight, CHARACTER_HEIGHT + 'px');
assert.equal(terminal.rowContainer.style.lineHeight, CHARACTER_HEIGHT + 'px');
charMeasureElement.getBoundingClientRect = () => {
return { width: null, height: 1 };
};
charMeasure.height = 1;
viewport.refresh();
assert.equal(viewportElement.style.lineHeight, '1px');
assert.equal(terminal.rowContainer.style.lineHeight, '1px');
Expand All @@ -59,9 +55,7 @@ describe('Viewport', () => {
terminal.rows = 1;
viewport.refresh();
assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px');
charMeasureElement.getBoundingClientRect = () => {
return { width: null, height: 20 };
};
charMeasure.height = 20;
viewport.refresh();
assert.equal(viewportElement.style.height, 20 + 'px');
});
Expand Down
25 changes: 12 additions & 13 deletions src/Viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

import { ITerminal } from './Interfaces';
import { CharMeasure } from './utils/CharMeasure';

/**
* Represents the viewport of a terminal, the visible area within the larger buffer of output.
Expand All @@ -24,7 +25,7 @@ export class Viewport {
private terminal: ITerminal,
private viewportElement: HTMLElement,
private scrollArea: HTMLElement,
private charMeasureElement: HTMLElement
private charMeasure: CharMeasure
) {
this.currentRowHeight = 0;
this.lastRecordedBufferLength = 0;
Expand All @@ -43,21 +44,20 @@ export class Viewport {
* @param charSize A character size measurement bounding rect object, if it doesn't exist it will
* be created.
*/
private refresh(charSize?: ClientRect): void {
var size = charSize || this.charMeasureElement.getBoundingClientRect();
if (size.height > 0) {
var rowHeightChanged = size.height !== this.currentRowHeight;
private refresh(): void {
if (this.charMeasure.height > 0) {
var rowHeightChanged = this.charMeasure.height !== this.currentRowHeight;
if (rowHeightChanged) {
this.currentRowHeight = size.height;
this.viewportElement.style.lineHeight = size.height + 'px';
this.terminal.rowContainer.style.lineHeight = size.height + 'px';
this.currentRowHeight = this.charMeasure.height;
this.viewportElement.style.lineHeight = this.charMeasure.height + 'px';
this.terminal.rowContainer.style.lineHeight = this.charMeasure.height + 'px';
}
var viewportHeightChanged = this.lastRecordedViewportHeight !== this.terminal.rows;
if (rowHeightChanged || viewportHeightChanged) {
this.lastRecordedViewportHeight = this.terminal.rows;
this.viewportElement.style.height = size.height * this.terminal.rows + 'px';
this.viewportElement.style.height = this.charMeasure.height * this.terminal.rows + 'px';
}
this.scrollArea.style.height = (size.height * this.lastRecordedBufferLength) + 'px';
this.scrollArea.style.height = (this.charMeasure.height * this.lastRecordedBufferLength) + 'px';
}
}

Expand All @@ -74,9 +74,8 @@ export class Viewport {
this.refresh();
} else {
// If size has changed, refresh viewport
var size = this.charMeasureElement.getBoundingClientRect();
if (size.height !== this.currentRowHeight) {
this.refresh(size);
if (this.charMeasure.height !== this.currentRowHeight) {
this.refresh();
}
}

Expand Down
52 changes: 52 additions & 0 deletions src/utils/CharMeasure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* @module xterm/utils/CharMeasure
* @license MIT
*/

import { EventEmitter } from '../EventEmitter.js';

/**
* Utility class that measures the size of a character.
*/
export class CharMeasure extends EventEmitter {
private _parentElement: HTMLElement;
private _measureElement: HTMLElement;
private _width: number;
private _height: number;

constructor(parentElement: HTMLElement) {
super();
this._parentElement = parentElement;
}

public get width(): number {
return this._width;
}

public get height(): number {
return this._height;
}

public measure(): void {
const oldWidth = this._width;
const oldHeight = this._height;

if (!this._measureElement) {
this._measureElement = document.createElement('span');
this._measureElement.style.position = 'absolute';
this._measureElement.style.top = '0';
this._measureElement.style.left = '-9999em';
this._measureElement.textContent = 'W';
}

this._parentElement.appendChild(this._measureElement);
const geometry = this._measureElement.getBoundingClientRect();
this._width = geometry.width;
this._height = geometry.height;
this._parentElement.removeChild(this._measureElement);

if (this._width !== oldWidth || this._height !== oldHeight) {
this.emit('charsizechanged');
}
}
}
4 changes: 4 additions & 0 deletions src/xterm.css
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@
overflow-y: scroll;
}

.terminal .xterm-wide-char {
display: inline-block;
}

.terminal .xterm-rows {
position: absolute;
left: 0;
Expand Down
30 changes: 25 additions & 5 deletions src/xterm.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { EventEmitter } from './EventEmitter.js';
import { Viewport } from './Viewport.js';
import { rightClickHandler, pasteHandler, copyHandler } from './handlers/Clipboard.js';
import { CircularList } from './utils/CircularList.js';
import { CharMeasure } from './utils/CharMeasure.js';
import * as Browser from './utils/Browser';
import * as Keyboard from './utils/Keyboard';

Expand Down Expand Up @@ -567,17 +568,21 @@ Terminal.prototype.open = function(parent) {
this.compositionHelper = new CompositionHelper(this.textarea, this.compositionView, this);
this.helperContainer.appendChild(this.compositionView);

this.charMeasureElement = document.createElement('div');
this.charMeasureElement.classList.add('xterm-char-measure-element');
this.charMeasureElement.innerHTML = 'W';
this.helperContainer.appendChild(this.charMeasureElement);
this.charSizeStyleElement = document.createElement('style');
this.helperContainer.appendChild(this.charSizeStyleElement);

for (; i < this.rows; i++) {
this.insertRow();
}
this.parent.appendChild(this.element);

this.viewport = new Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasureElement);
this.charMeasure = new CharMeasure(this.rowContainer);
this.charMeasure.on('charsizechanged', function () {
self.updateCharSizeCSS();
});
this.charMeasure.measure();

this.viewport = new Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasure);

// Setup loop that draws to screen
this.queueRefresh(0, this.rows - 1);
Expand Down Expand Up @@ -636,6 +641,13 @@ Terminal.loadAddon = function(addon, callback) {
}
};

/**
* Updates the helper CSS class with any changes necessary after the terminal's
* character width has been changed.
*/
Terminal.prototype.updateCharSizeCSS = function() {
this.charSizeStyleElement.textContent = '.xterm-wide-char{width:' + (this.charMeasure.width * 2) + 'px;}';
}

/**
* XTerm mouse events
Expand Down Expand Up @@ -1182,6 +1194,9 @@ Terminal.prototype.refresh = function(start, end) {
}
}

if (ch_width === 2) {
out += '<span class="xterm-wide-char">';
}
switch (ch) {
case '&':
out += '&amp;';
Expand All @@ -1200,6 +1215,9 @@ Terminal.prototype.refresh = function(start, end) {
}
break;
}
if (ch_width === 2) {
out += '</span>';
}

attr = data;
}
Expand Down Expand Up @@ -2945,6 +2963,8 @@ Terminal.prototype.resize = function(x, y) {
this.scrollTop = 0;
this.scrollBottom = y - 1;

this.charMeasure.measure();

this.queueRefresh(0, this.rows - 1);

this.normal = null;
Expand Down

0 comments on commit e9da2a6

Please sign in to comment.