diff --git a/src/xterm.js b/src/xterm.js index 0c8359d1..618d1c79 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -1566,9 +1566,22 @@ } // insert combining char in last cell + // FIXME: needs handling after cursor jumps if (!ch_width && this.x) { - this.lines[this.y + this.ybase][this.x-1][1] += ch; - this.updateRange(this.y); + + // dont overflow left + if (this.lines[this.y + this.ybase][this.x-1]) { + if (!this.lines[this.y + this.ybase][this.x-1][2]) { + + // found empty cell after fullwidth, need to go 2 cells back + if (this.lines[this.y + this.ybase][this.x-2]) + this.lines[this.y + this.ybase][this.x-2][1] += ch; + + } else { + this.lines[this.y + this.ybase][this.x-1][1] += ch; + } + this.updateRange(this.y); + } break; } diff --git a/test/test.js b/test/test.js index fcfd8832..57bfd90b 100644 --- a/test/test.js +++ b/test/test.js @@ -1,4 +1,5 @@ var assert = require('chai').assert; +var chai = require('chai'); var Terminal = require('../src/xterm'); describe('xterm.js', function() { @@ -190,4 +191,261 @@ describe('xterm.js', function() { }); }); }); + +describe('unicode - surrogates', function() { + it('2 characters per cell', function () { + var high = '\uD800'; + for (var i=0xDC00; i<=0xDCFF; ++i) { + xterm.write(high + String.fromCharCode(i)); + var tchar = xterm.lines[0][0]; + chai.expect(tchar[1]).eql(high + String.fromCharCode(i)); + chai.expect(tchar[1].length).eql(2); + chai.expect(tchar[2]).eql(1); + chai.expect(xterm.lines[0][1][1]).eql(' '); + xterm.reset(); + } + }); + it('2 characters at last cell', function () { + var high = '\uD800'; + for (var i=0xDC00; i<=0xDCFF; ++i) { + xterm.x = xterm.cols - 1; + xterm.write(high + String.fromCharCode(i)); + chai.expect(xterm.lines[0][xterm.x-1][1]).eql(high + String.fromCharCode(i)); + chai.expect(xterm.lines[0][xterm.x-1][1].length).eql(2); + chai.expect(xterm.lines[1][0][1]).eql(' '); + xterm.reset(); + } + }); + it('2 characters per cell over line end with autowrap', function () { + var high = '\uD800'; + for (var i=0xDC00; i<=0xDCFF; ++i) { + xterm.x = xterm.cols - 1; + xterm.wraparoundMode = true; + xterm.write('a' + high + String.fromCharCode(i)); + chai.expect(xterm.lines[0][xterm.cols-1][1]).eql('a'); + chai.expect(xterm.lines[1][0][1]).eql(high + String.fromCharCode(i)); + chai.expect(xterm.lines[1][0][1].length).eql(2); + chai.expect(xterm.lines[1][1][1]).eql(' '); + xterm.reset(); + } + }); + /** FIXME - wrap is not respected in default state */ + /* + it('2 characters per cell over line end without autowrap', function () { + var high = '\uD800'; + for (var i=0xDC00; i<=0xDCFF; ++i) { + xterm.x = xterm.cols - 1; + xterm.wraparoundMode = false; + xterm.write('a' + high + String.fromCharCode(i)); + chai.expect(xterm.lines[0][xterm.cols-1][1]).eql(high + String.fromCharCode(i)); + chai.expect(xterm.lines[0][xterm.cols-1][1].length).eql(2); + chai.expect(xterm.lines[1][1][1]).eql(' '); + xterm.reset(); + } + }); + */ + it('splitted surrogates', function () { + var high = '\uD800'; + for (var i=0xDC00; i<=0xDCFF; ++i) { + xterm.write(high); + xterm.write(String.fromCharCode(i)); + var tchar = xterm.lines[0][0]; + chai.expect(tchar[1]).eql(high + String.fromCharCode(i)); + chai.expect(tchar[1].length).eql(2); + chai.expect(tchar[2]).eql(1); + chai.expect(xterm.lines[0][1][1]).eql(' '); + xterm.reset(); + } + }); +}); +describe('unicode - combining characters', function() { + it('café', function () { + xterm.write('cafe\u0301'); + chai.expect(xterm.lines[0][3][1]).eql('e\u0301'); + chai.expect(xterm.lines[0][3][1].length).eql(2); + chai.expect(xterm.lines[0][3][2]).eql(1); + }); + it('café - end of line', function () { + xterm.x = xterm.cols - 1 - 3; + xterm.write('cafe\u0301'); + chai.expect(xterm.lines[0][xterm.cols-1][1]).eql('e\u0301'); + chai.expect(xterm.lines[0][xterm.cols-1][1].length).eql(2); + chai.expect(xterm.lines[0][xterm.cols-1][2]).eql(1); + chai.expect(xterm.lines[0][1][1]).eql(' '); + chai.expect(xterm.lines[0][1][1].length).eql(1); + chai.expect(xterm.lines[0][1][2]).eql(1); + }); + it('multiple combined é', function () { + xterm.write(Array(100).join('e\u0301')); + for (var i=0; i