Skip to content

Commit 948eedb

Browse files
authored
Merge pull request #938 from Tyriar/canvas_render
Render using canvas
2 parents 48391c3 + 0c19bc9 commit 948eedb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+3068
-3482
lines changed

README.md

+4-6
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,10 @@ xterm.fit();
9797

9898
Since xterm.js is typically implemented as a developer tool, only modern browsers are supported officially. Here is a list of the versions we aim to support:
9999

100-
- Chrome 48+
101-
- Edge 13+
102-
- Firefox 44+
103-
- Internet Explorer 11+
104-
- Opera 35+
105-
- Safari 8+
100+
- Chrome latest
101+
- Edge latest
102+
- Firefox latest
103+
- Safari latest
106104

107105
Xterm.js works seamlessly in Electron apps and may even work on earlier versions of the browsers but these are the browsers we strive to keep working.
108106

demo/main.js

+24-25
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ var term,
22
protocol,
33
socketURL,
44
socket,
5-
pid,
6-
charWidth,
7-
charHeight;
5+
pid;
86

97
var terminalContainer = document.getElementById('terminal-container'),
108
actionElements = {
@@ -21,11 +19,13 @@ var terminalContainer = document.getElementById('terminal-container'),
2119
colsElement = document.getElementById('cols'),
2220
rowsElement = document.getElementById('rows');
2321

24-
function setTerminalSize () {
25-
var cols = parseInt(colsElement.value, 10),
26-
rows = parseInt(rowsElement.value, 10),
27-
width = (cols * charWidth).toString() + 'px',
28-
height = (rows * charHeight).toString() + 'px';
22+
function setTerminalSize() {
23+
var cols = parseInt(colsElement.value, 10);
24+
var rows = parseInt(rowsElement.value, 10);
25+
var viewportElement = document.querySelector('.xterm-viewport');
26+
var scrollBarWidth = viewportElement.offsetWidth - viewportElement.clientWidth;
27+
var width = (cols * term.charMeasure.width + 20 /*room for scrollbar*/).toString() + 'px';
28+
var height = (rows * term.charMeasure.height).toString() + 'px';
2929

3030
terminalContainer.style.width = width;
3131
terminalContainer.style.height = height;
@@ -92,27 +92,26 @@ function createTerminal() {
9292
term.open(terminalContainer);
9393
term.fit();
9494

95-
var initialGeometry = term.proposeGeometry(),
96-
cols = initialGeometry.cols,
97-
rows = initialGeometry.rows;
95+
// fit is called within a setTimeout, cols and rows need this.
96+
setTimeout(() => {
97+
colsElement.value = term.cols;
98+
rowsElement.value = term.rows;
9899

99-
colsElement.value = cols;
100-
rowsElement.value = rows;
100+
// Set terminal size again to set the specific dimensions on the demo
101+
setTerminalSize();
101102

102-
fetch('/terminals?cols=' + cols + '&rows=' + rows, {method: 'POST'}).then(function (res) {
103+
fetch('/terminals?cols=' + term.cols + '&rows=' + term.rows, {method: 'POST'}).then(function (res) {
103104

104-
charWidth = Math.ceil(term.element.offsetWidth / cols);
105-
charHeight = Math.ceil(term.element.offsetHeight / rows);
106-
107-
res.text().then(function (pid) {
108-
window.pid = pid;
109-
socketURL += pid;
110-
socket = new WebSocket(socketURL);
111-
socket.onopen = runRealTerminal;
112-
socket.onclose = runFakeTerminal;
113-
socket.onerror = runFakeTerminal;
105+
res.text().then(function (pid) {
106+
window.pid = pid;
107+
socketURL += pid;
108+
socket = new WebSocket(socketURL);
109+
socket.onopen = runRealTerminal;
110+
socket.onclose = runFakeTerminal;
111+
socket.onerror = runFakeTerminal;
112+
});
114113
});
115-
});
114+
}, 0);
116115
}
117116

118117
function runRealTerminal() {

demo/style.css

-6
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,3 @@ h1 {
1414
margin: 0 auto;
1515
padding: 2px;
1616
}
17-
18-
#terminal-container .terminal {
19-
background-color: #111;
20-
color: #fafafa;
21-
padding: 2px;
22-
}

fixtures/typings-test/typings-test.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ namespace methods_core {
168168
t.setOption('bellStyle', 'visual');
169169
t.setOption('bellStyle', 'sound');
170170
t.setOption('bellStyle', 'both');
171+
t.setOption('fontSize', 1);
172+
t.setOption('lineHeight', 1);
173+
t.setOption('fontFamily', 'foo');
174+
t.setOption('theme', {background: '#ff0000'});
171175
}
172176
}
173177
namespace scrolling {
@@ -210,9 +214,13 @@ namespace methods_experimental {
210214
t.registerLinkMatcher(/foo/, () => true, {
211215
matchIndex: 1,
212216
priority: 1,
213-
validationCallback: (uri: string, element: HTMLElement, callback: (isValid: boolean) => void) => {
214-
console.log(uri, element, callback);
215-
}
217+
validationCallback: (uri: string, callback: (isValid: boolean) => void) => {
218+
console.log(uri, callback);
219+
},
220+
tooltipCallback: (e: MouseEvent, uri: string) => {
221+
console.log(e, uri);
222+
},
223+
leaveCallback: () => {}
216224
});
217225
t.deregisterLinkMatcher(1);
218226
}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"nodemon": "1.10.2",
6565
"sorcery": "^0.10.0",
6666
"tslint": "^4.0.2",
67-
"typescript": "~2.2.0",
67+
"typescript": "~2.4.0",
6868
"vinyl-buffer": "^1.0.0",
6969
"vinyl-source-stream": "^1.1.0"
7070
},

src/Buffer.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
2+
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
23
* @license MIT
34
*/
45

src/Buffer.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
/**
2+
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
23
* @license MIT
34
*/
45

56
import { ITerminal, IBuffer } from './Interfaces';
67
import { CircularList } from './utils/CircularList';
78
import { LineData, CharData } from './Types';
89

10+
export const CHAR_DATA_ATTR_INDEX = 0;
911
export const CHAR_DATA_CHAR_INDEX = 1;
1012
export const CHAR_DATA_WIDTH_INDEX = 2;
13+
export const CHAR_DATA_CODE_INDEX = 3;
1114

1215
/**
1316
* This class represents a terminal buffer (an internal state of the terminal), where the
@@ -32,8 +35,8 @@ export class Buffer implements IBuffer {
3235
/**
3336
* Create a new Buffer.
3437
* @param _terminal The terminal the Buffer will belong to.
35-
* @param _hasScrollback Whether the buffer should respecr the scrollback of
36-
* the terminal..
38+
* @param _hasScrollback Whether the buffer should respect the scrollback of
39+
* the terminal.
3740
*/
3841
constructor(
3942
private _terminal: ITerminal,
@@ -50,6 +53,12 @@ export class Buffer implements IBuffer {
5053
return this._hasScrollback && this.lines.maxLength > this._terminal.rows;
5154
}
5255

56+
public get isCursorInViewport(): boolean {
57+
const absoluteY = this.ybase + this.y;
58+
const relativeY = absoluteY - this.ydisp;
59+
return (relativeY >= 0 && relativeY < this._terminal.rows);
60+
}
61+
5362
/**
5463
* Gets the correct buffer length based on the rows provided, the terminal's
5564
* scrollback and whether this buffer is flagged to have scrollback or not.
@@ -106,7 +115,7 @@ export class Buffer implements IBuffer {
106115
if (this._lines.length > 0) {
107116
// Deal with columns increasing (we don't do anything when columns reduce)
108117
if (this._terminal.cols < newCols) {
109-
const ch: CharData = [this._terminal.defAttr, ' ', 1]; // does xterm use the default attr?
118+
const ch: CharData = [this._terminal.defAttr, ' ', 1, 32]; // does xterm use the default attr?
110119
for (let i = 0; i < this._lines.length; i++) {
111120
// TODO: This should be removed, with tests setup for the case that was
112121
// causing the underlying bug, see https://github.com/sourcelair/xterm.js/issues/824

src/BufferSet.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
2+
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
23
* @license MIT
34
*/
45

src/BufferSet.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
2+
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
23
* @license MIT
34
*/
45

src/Charsets.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
2+
* Copyright (c) 2016 The xterm.js authors. All rights reserved.
23
* @license MIT
34
*/
45

src/CompositionHelper.test.ts

+11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
2+
* Copyright (c) 2016 The xterm.js authors. All rights reserved.
23
* @license MIT
34
*/
45

@@ -42,6 +43,16 @@ describe('CompositionHelper', () => {
4243
},
4344
handler: (text: string) => {
4445
handledText += text;
46+
},
47+
buffer: {
48+
isCursorInViewport: true
49+
},
50+
charMeasure: {
51+
height: 10,
52+
width: 10
53+
},
54+
options: {
55+
lineHeight: 1
4556
}
4657
};
4758
handledText = '';

src/CompositionHelper.ts

+13-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
2+
* Copyright (c) 2016 The xterm.js authors. All rights reserved.
23
* @license MIT
34
*/
45

@@ -63,6 +64,7 @@ export class CompositionHelper {
6364
* @param {CompositionEvent} ev The event.
6465
*/
6566
public compositionupdate(ev: CompositionEvent): void {
67+
console.log('compositionupdate');
6668
this.compositionView.textContent = ev.data;
6769
this.updateCompositionElements();
6870
setTimeout(() => {
@@ -193,26 +195,26 @@ export class CompositionHelper {
193195
if (!this.isComposing) {
194196
return;
195197
}
196-
const cursor = <HTMLElement>this.terminal.element.querySelector('.terminal-cursor');
197-
if (cursor) {
198-
// Take .xterm-rows offsetTop into account as well in case it's positioned absolutely within
199-
// the .xterm element.
200-
const xtermRows = <HTMLElement>this.terminal.element.querySelector('.xterm-rows');
201-
const cursorTop = xtermRows.offsetTop + cursor.offsetTop;
202-
203-
this.compositionView.style.left = cursor.offsetLeft + 'px';
198+
199+
if (this.terminal.buffer.isCursorInViewport) {
200+
const cellHeight = Math.ceil(this.terminal.charMeasure.height * this.terminal.options.lineHeight);
201+
const cursorTop = this.terminal.buffer.y * cellHeight;
202+
const cursorLeft = this.terminal.buffer.x * this.terminal.charMeasure.width;
203+
204+
this.compositionView.style.left = cursorLeft + 'px';
204205
this.compositionView.style.top = cursorTop + 'px';
205-
this.compositionView.style.height = cursor.offsetHeight + 'px';
206-
this.compositionView.style.lineHeight = cursor.offsetHeight + 'px';
206+
this.compositionView.style.height = cellHeight + 'px';
207+
this.compositionView.style.lineHeight = cellHeight + 'px';
207208
// Sync the textarea to the exact position of the composition view so the IME knows where the
208209
// text is.
209210
const compositionViewBounds = this.compositionView.getBoundingClientRect();
210-
this.textarea.style.left = cursor.offsetLeft + 'px';
211+
this.textarea.style.left = cursorLeft + 'px';
211212
this.textarea.style.top = cursorTop + 'px';
212213
this.textarea.style.width = compositionViewBounds.width + 'px';
213214
this.textarea.style.height = compositionViewBounds.height + 'px';
214215
this.textarea.style.lineHeight = compositionViewBounds.height + 'px';
215216
}
217+
216218
if (!dontRecurse) {
217219
setTimeout(() => this.updateCompositionElements(true), 0);
218220
}

src/EscapeSequences.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
2+
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
23
* @license MIT
34
*/
45

src/EventEmitter.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
2+
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
23
* @license MIT
34
*/
45

src/EventEmitter.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
2+
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
23
* @license MIT
34
*/
45

src/InputHandler.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
2+
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
23
* @license MIT
34
*/
45

src/InputHandler.ts

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/**
2+
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
3+
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
24
* @license MIT
35
*/
46

@@ -36,13 +38,14 @@ export class InputHandler implements IInputHandler {
3638
// dont overflow left
3739
if (this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1]) {
3840
if (!this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1][CHAR_DATA_WIDTH_INDEX]) {
39-
4041
// found empty cell after fullwidth, need to go 2 cells back
41-
if (this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2])
42+
if (this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2]) {
4243
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2][CHAR_DATA_CHAR_INDEX] += char;
43-
44+
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2][3] = char.charCodeAt(0);
45+
}
4446
} else {
4547
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1][CHAR_DATA_CHAR_INDEX] += char;
48+
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1][3] = char.charCodeAt(0);
4649
}
4750
this._terminal.updateRange(this._terminal.buffer.y);
4851
}
@@ -81,21 +84,21 @@ export class InputHandler implements IInputHandler {
8184
if (removed[CHAR_DATA_WIDTH_INDEX] === 0
8285
&& this._terminal.buffer.lines.get(row)[this._terminal.cols - 2]
8386
&& this._terminal.buffer.lines.get(row)[this._terminal.cols - 2][CHAR_DATA_WIDTH_INDEX] === 2) {
84-
this._terminal.buffer.lines.get(row)[this._terminal.cols - 2] = [this._terminal.curAttr, ' ', 1];
87+
this._terminal.buffer.lines.get(row)[this._terminal.cols - 2] = [this._terminal.curAttr, ' ', 1, ' '.charCodeAt(0)];
8588
}
8689

8790
// insert empty cell at cursor
88-
this._terminal.buffer.lines.get(row).splice(this._terminal.buffer.x, 0, [this._terminal.curAttr, ' ', 1]);
91+
this._terminal.buffer.lines.get(row).splice(this._terminal.buffer.x, 0, [this._terminal.curAttr, ' ', 1, ' '.charCodeAt(0)]);
8992
}
9093
}
9194

92-
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, char, ch_width];
95+
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, char, ch_width, char.charCodeAt(0)];
9396
this._terminal.buffer.x++;
9497
this._terminal.updateRange(this._terminal.buffer.y);
9598

9699
// fullwidth char - set next cell width to zero and advance cursor
97100
if (ch_width === 2) {
98-
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, '', 0];
101+
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, '', 0, undefined];
99102
this._terminal.buffer.x++;
100103
}
101104
}
@@ -188,7 +191,7 @@ export class InputHandler implements IInputHandler {
188191

189192
const row = this._terminal.buffer.y + this._terminal.buffer.ybase;
190193
let j = this._terminal.buffer.x;
191-
const ch: CharData = [this._terminal.eraseAttr(), ' ', 1]; // xterm
194+
const ch: CharData = [this._terminal.eraseAttr(), ' ', 1, 32]; // xterm
192195

193196
while (param-- && j < this._terminal.cols) {
194197
this._terminal.buffer.lines.get(row).splice(j++, 0, ch);
@@ -487,7 +490,7 @@ export class InputHandler implements IInputHandler {
487490
}
488491

489492
const row = this._terminal.buffer.y + this._terminal.buffer.ybase;
490-
const ch: CharData = [this._terminal.eraseAttr(), ' ', 1]; // xterm
493+
const ch: CharData = [this._terminal.eraseAttr(), ' ', 1, 32]; // xterm
491494

492495
while (param--) {
493496
this._terminal.buffer.lines.get(row).splice(this._terminal.buffer.x, 1);
@@ -535,7 +538,7 @@ export class InputHandler implements IInputHandler {
535538

536539
const row = this._terminal.buffer.y + this._terminal.buffer.ybase;
537540
let j = this._terminal.buffer.x;
538-
const ch: CharData = [this._terminal.eraseAttr(), ' ', 1]; // xterm
541+
const ch: CharData = [this._terminal.eraseAttr(), ' ', 1, 32]; // xterm
539542

540543
while (param-- && j < this._terminal.cols) {
541544
this._terminal.buffer.lines.get(row)[j++] = ch;
@@ -589,7 +592,7 @@ export class InputHandler implements IInputHandler {
589592
public repeatPrecedingCharacter(params: number[]): void {
590593
let param = params[0] || 1;
591594
const line = this._terminal.buffer.lines.get(this._terminal.buffer.ybase + this._terminal.buffer.y);
592-
const ch = line[this._terminal.buffer.x - 1] || [this._terminal.defAttr, ' ', 1];
595+
const ch = line[this._terminal.buffer.x - 1] || [this._terminal.defAttr, ' ', 1, 32];
593596

594597
while (param--) {
595598
line[this._terminal.buffer.x++] = ch;

0 commit comments

Comments
 (0)