Merge pull request #440 from Tyriar/439_wide_char_class

Style wide characters at charWidth*2 in DOM
This commit is contained in:
Daniel Imms
2017-01-08 17:00:30 -08:00
committed by GitHub
5 changed files with 103 additions and 34 deletions
+10 -16
View File
@@ -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;
@@ -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');
@@ -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');
});
+12 -13
View File
@@ -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.
@@ -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;
@@ -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';
}
}
@@ -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();
}
}
+52
View File
@@ -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
View File
@@ -116,6 +116,10 @@
overflow-y: scroll;
}
.terminal .xterm-wide-char {
display: inline-block;
}
.terminal .xterm-rows {
position: absolute;
left: 0;
+25 -5
View File
@@ -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';
@@ -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);
@@ -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
@@ -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;';
@@ -1200,6 +1215,9 @@ Terminal.prototype.refresh = function(start, end) {
}
break;
}
if (ch_width === 2) {
out += '</span>';
}
attr = data;
}
@@ -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;