First pass at supporting wide UTF8 chars like 中文

This commit is contained in:
Thomas Buckley-Houston 2018-01-14 22:25:38 +08:00
parent 97a36b68b4
commit 64431be7c3
5 changed files with 4595 additions and 6 deletions

4556
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,7 @@
"webpack": "^3.10.0"
},
"dependencies": {
"lodash": "^4.17.4"
"lodash": "^4.17.4",
"string-width": "^2.1.1"
}
}

View file

@ -1,3 +1,5 @@
import charWidthInTTY from 'string-width';
import utils from 'utils';
// Handle commands from tabs, like sending a frame or information about
@ -43,13 +45,15 @@ export default (MixinBase) => class extends MixinBase {
_buildTTYRow(text) {
let char;
let row = "";
for (let index = 0; index < this.tty_width; index++) {
let index = 0;
while (index < this.tty_width) {
if (index < text.length) {
char = text[index];
} else {
char = " "
}
row += utils.ttyPixel([255, 255, 255], [0, 0, 0], char);
index += charWidthInTTY(char);
}
return row;
}

View file

@ -1,3 +1,5 @@
import charWidthInTTY from 'string-width';
import utils from 'utils';
import BaseBuilder from 'dom/base_builder';
import GraphicsBuilder from 'dom/graphics_builder';
@ -233,21 +235,47 @@ export default class FrameBuilder extends BaseBuilder{
// However we can't just write random pixels to a TTY screen, we must collate 2 rows
// of native pixels for every row of the terminal.
_buildTtyRow(bg_row, fg_row, y) {
let tty_index, char;
let tty_index, char, x_shoved;
let row = "";
let char_width_debt = 0;
const tty_row = parseInt(y / 2);
for (let x = 0; x < this.frame_width; x++) {
if (x + char_width_debt >= this.frame_width) {
// Ideally this shouldn't happen because the CSS 'should' deal with wide
// characters.
break;
}
tty_index = (tty_row * this.frame_width) + x;
if (this._doesCellHaveACharacter(tty_index)) {
char = this.formatted_text[tty_index];
char_width_debt = this._calculateCharWidthDebt(char_width_debt, char[0]);
// Don't display a wide character in the final column
if (x + char_width_debt >= this.frame_width) char[0] = ' ';
row += utils.ttyPixel(char[1], char[2], char[0]);
} else {
row += utils.ttyPixel(fg_row[x], bg_row[x], '▄');
// Wide characters take up more than one cell, so we might not always be
// iterating by 1.
x_shoved = x + char_width_debt;
row += utils.ttyPixel(fg_row[x_shoved], bg_row[x_shoved], '▄');
}
}
return row;
}
// Deal with UTF8 characters that take up more than a single cell in the TTY.
// TODO:
// 1. Do all terminals deal with wide characters the same?
// 2. Use CSS or JS so that wide characters actually flow in the DOM as 2
// monospaced characters. This will allow pages of nothing but wide
// characters to properly display.
_calculateCharWidthDebt(current_debt, char) {
const char_width_in_tty = charWidthInTTY(char);
if (char_width_in_tty > 1) {
current_debt += char_width_in_tty - 1;
}
return current_debt;
}
// We need to know this because we want all empty cells to be 'transparent'
_doesCellHaveACharacter(index) {
if (this.formatted_text[index] === undefined) return false;

View file

@ -172,6 +172,7 @@ export default class TextBuillder extends BaseBuilder {
// real browser.
_formatTextForTTYGrid(text, dom_rects) {
let col, tty_box, step, character, previous_box, origin;
this.char_width_debt = 0
let character_index = 0;
for (const box of dom_rects) {
if (this._isBoxOutsideViewport(box)) return;
@ -188,9 +189,9 @@ export default class TextBuillder extends BaseBuilder {
for (step = 0; step < tty_box.width; step++) {
character = text.charAt(character_index);
this._placeCharacterOnTTYGrid(col, tty_box.row, origin, character);
col++;
origin.x = origin.x + this.char_width;
character_index++;
col++
}
previous_box = box;
}
@ -213,7 +214,6 @@ export default class TextBuillder extends BaseBuilder {
_placeCharacterOnTTYGrid(col, row, original_position, character) {
const index = (row * this.tty_dom_width) + col;
if (this._isExistingCharacter(index)) return;
if (this._isCharOutsideGrid(col, row)) return;
const colours = this._getCharacterColours(original_position);
if (!colours) return;