mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge branch 'master' into script_improvements
This commit is contained in:
+44
-12
@@ -1,16 +1,48 @@
|
||||
node_modules/
|
||||
*.swp
|
||||
.lock-wscript
|
||||
lib/*.test.js
|
||||
lib/*.test.js.map
|
||||
# Blacklist - exclude everything except npm defaults such as LICENSE, etc
|
||||
*
|
||||
!*/
|
||||
|
||||
# Whitelist - entries to be included must be negated with "!"
|
||||
!*.js
|
||||
!*.json
|
||||
|
||||
# Whitelist - dist/
|
||||
!dist/**/*.js
|
||||
!dist/**/*.js.map
|
||||
|
||||
!dist/**/*.css
|
||||
|
||||
# Whitelist - lib/
|
||||
!lib/**/*.d.ts
|
||||
|
||||
!lib/**/*.js
|
||||
!lib/**/*.js.map
|
||||
|
||||
!lib/**/*.css
|
||||
|
||||
# Whitelist - src/
|
||||
!src/**/*.ts
|
||||
!src/**/*.d.ts
|
||||
|
||||
!src/**/*.js
|
||||
!src/**/*.js.map
|
||||
|
||||
!src/**/*.css
|
||||
|
||||
# Whitelist - typings/
|
||||
!typings/*.d.ts
|
||||
|
||||
# Blacklist - (normal behavior) these will override any whitelist
|
||||
*.test.ts
|
||||
*.test.d.ts
|
||||
*.test.js
|
||||
*.test.js.map
|
||||
lib/test/
|
||||
Makefile.gyp
|
||||
*.Makefile
|
||||
*.target.gyp.mk
|
||||
*.node
|
||||
example/*.log
|
||||
|
||||
docs/
|
||||
npm-debug.log
|
||||
/.idea/
|
||||
.env
|
||||
.vscode/
|
||||
build/
|
||||
fixtures/
|
||||
coverage/
|
||||
demo/
|
||||
|
||||
@@ -17,4 +17,3 @@ env:
|
||||
notifications:
|
||||
email: false
|
||||
script: npm run $NPM_COMMAND
|
||||
after_success: npm run coveralls
|
||||
|
||||
@@ -23,6 +23,7 @@ Benjamin Woodruff <github@benjam.info>
|
||||
Bill Church <billchurch@users.noreply.github.com>
|
||||
Bob Reid <bobreid@Bobs-MacBook-Pro.local>
|
||||
bottleofwater <nison.mael+bottleofwater@gmail.com>
|
||||
Brandon Bayer <b@bayer.ws>
|
||||
Brian Mock <brian@mockbrian.com>
|
||||
Bruno Ribeiro <b.m.fernandes.ribeiro@gmail.com>
|
||||
Bruno Ribeito <b.m.fernandes.ribeiro@gmail.com>
|
||||
@@ -62,12 +63,16 @@ Jianhui Zhao <jianhuizhao329@gmail.com>
|
||||
Joao Moreno <jomo@microsoft.com>
|
||||
Joao Moreno <mail@joaomoreno.com>
|
||||
Johannes Zellner <johannes@nebulon.de>
|
||||
Jon Austin <jon.i.austin@gmail.com>
|
||||
Jon Masters <jon.masters@sky.com>
|
||||
Jörg Breitbart <jerch@rockborn.de>
|
||||
jpoth <poth.john@gmail.com>
|
||||
Justin Luk <jluk@users.noreply.github.com>
|
||||
Justin Mecham <justin@mecham.me>
|
||||
Kirill Merkushev <lanwen@yandex.ru>
|
||||
Krasimir Tsonev <krasimir@outset.ws>
|
||||
Ledion Bitincka <lbitincka@gmail.com>
|
||||
Linus Unnebäck <linus@folkdatorn.se>
|
||||
Luca <LucaT1@users.noreply.github.com>
|
||||
Lucian Buzzo <lucian.buzzo@gmail.com>
|
||||
Lukas Drgon <lukas.drgon@gmail.com>
|
||||
@@ -88,8 +93,11 @@ npezza93 <npezza93@gmail.com>
|
||||
Oleksandr Andriienko <oandriie@redhat.com>
|
||||
Paris Kasidiaris <pariskasidiaris@gmail.com>
|
||||
Paris Kasidiaris <paris@sourcelair.com>
|
||||
Peng Xiao <pengxiao@outlook.com>
|
||||
Peter Baumgarten <me@peterbaumgarten.com>
|
||||
Philip Olson <philip.olson@protonmail.ch>
|
||||
pro-src <34285059+pro-src@users.noreply.github.com>
|
||||
pro-src <rodneyd.teal@gmail.com>
|
||||
Rick Baker <rick@ricktbaker.com>
|
||||
runarberg <runar@greenqloud.com>
|
||||
Saad Malik <simfox3@gmail.com>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# [](https://xtermjs.org)
|
||||
|
||||
[](https://travis-ci.org/xtermjs/xterm.js) [](https://coveralls.io/github/sourcelair/xterm.js) [](https://gitter.im/sourcelair/xterm.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [](https://www.jsdelivr.com/package/npm/xterm)
|
||||
[](https://travis-ci.org/xtermjs/xterm.js) [](https://coveralls.io/github/xtermjs/xterm.js?branch=master) [](https://gitter.im/sourcelair/xterm.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [](https://www.jsdelivr.com/package/npm/xterm)
|
||||
|
||||
Xterm.js is a terminal front-end component written in JavaScript that works in the browser.
|
||||
|
||||
@@ -41,7 +41,7 @@ To start using xterm.js on your browser, add the `xterm.js` and `xterm.css` to t
|
||||
<script>
|
||||
var term = new Terminal();
|
||||
term.open(document.getElementById('terminal'));
|
||||
term.write('Hello from \033[1;3;31mxterm.js\033[0m $ ')
|
||||
term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -57,8 +57,6 @@ The proposed way to load xterm.js is via the ES6 module syntax.
|
||||
import { Terminal } from 'xterm';
|
||||
```
|
||||
|
||||
*Note: There are currently no typings for addons so you will need to upcast if using TypeScript, eg. `(<any>xterm).fit()`.*
|
||||
|
||||
### Addons
|
||||
|
||||
Addons are JavaScript modules that extend the `Terminal` prototype with new methods and attributes to provide additional functionality. There are a handful available in the main repository in the `src/addons` directory and you can even write your own, by using xterm.js' public API.
|
||||
@@ -76,6 +74,27 @@ var xterm = new Terminal(); // Instantiate the terminal
|
||||
xterm.fit(); // Use the `fit` method, provided by the `fit` addon
|
||||
```
|
||||
|
||||
#### Importing Addons in TypeScript
|
||||
|
||||
There are currently no typings for addons if they are accessed via extending Terminal prototype, so you will need to upcast if using TypeScript, eg. `(<any>xterm).fit()`.
|
||||
|
||||
Alternatively, you can import addon function and enhance the terminal on demand. This would have better typing support and is friendly to treeshaking. E.g.:
|
||||
|
||||
```typescript
|
||||
import { Terminal } from 'xterm';
|
||||
import { fit } from 'xterm/lib/addons/fit/fit';
|
||||
const xterm = new Terminal();
|
||||
|
||||
// Fit the terminal when necessary:
|
||||
fit(xterm);
|
||||
```
|
||||
|
||||
#### Third party addons
|
||||
|
||||
There are also the following third party addons available:
|
||||
|
||||
- [xterm-webfont](https://www.npmjs.com/package/xterm-webfont)
|
||||
|
||||
## Browser Support
|
||||
|
||||
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:
|
||||
@@ -128,6 +147,8 @@ computational environment for Jupyter, supporting interactive data science and s
|
||||
- [**Microsoft SQL Operations Studio**](https://github.com/Microsoft/sqlopsstudio): A data management tool that enables working with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux
|
||||
- [**FreeMAN**](https://github.com/matthew-matvei/freeman): A free, cross-platform file manager for power users
|
||||
- [**Fluent Terminal**](https://github.com/felixse/FluentTerminal): A terminal emulator based on UWP and web technologies.
|
||||
- [**Hyper**](https://hyper.is): A terminal built on web technologies
|
||||
- [**Diag**](https://diag.ai): A better way to troubleshoot problems faster. Capture, share and reapply troubleshooting knowledge so you can focus on solving problems that matter.
|
||||
|
||||
Do you use xterm.js in your application as well? Please [open a Pull Request](https://github.com/sourcelair/xterm.js/pulls) to include it here. We would love to have it in our list.
|
||||
|
||||
|
||||
+14
-1
@@ -9,7 +9,7 @@
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>xterm.js: xterm, in the browser</h1>
|
||||
<h1 style="color: #2D2E2C">xterm.js: A terminal for the <em style="color: #5DA5D5">web</em></h1>
|
||||
<div id="terminal-container"></div>
|
||||
<div>
|
||||
<h2>Actions</h2>
|
||||
@@ -26,6 +26,9 @@
|
||||
<p>
|
||||
<label><input type="checkbox" id="option-mac-option-is-meta"> macOptionIsMeta</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" id="option-transparency"> transparency</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
cursorStyle
|
||||
@@ -53,6 +56,16 @@
|
||||
<p>
|
||||
<label>tabStopWidth <input type="number" id="option-tabstopwidth" value="8" /></label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
experimentalCharAtlas
|
||||
<select id="option-experimental-char-atlas">
|
||||
<option value="static" selected>static</option>
|
||||
<option value="dynamic">dynamic</option>
|
||||
<option value="none">none</option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<div>
|
||||
<h3>Size</h3>
|
||||
<div>
|
||||
|
||||
+13
-3
@@ -31,7 +31,9 @@ var terminalContainer = document.getElementById('terminal-container'),
|
||||
cursorStyle: document.querySelector('#option-cursor-style'),
|
||||
macOptionIsMeta: document.querySelector('#option-mac-option-is-meta'),
|
||||
scrollback: document.querySelector('#option-scrollback'),
|
||||
transparency: document.querySelector('#option-transparency'),
|
||||
tabstopwidth: document.querySelector('#option-tabstopwidth'),
|
||||
experimentalCharAtlas: document.querySelector('#option-experimental-char-atlas'),
|
||||
bellStyle: document.querySelector('#option-bell-style'),
|
||||
screenReaderMode: document.querySelector('#option-screen-reader-mode')
|
||||
},
|
||||
@@ -74,21 +76,29 @@ actionElements.findPrevious.addEventListener('keypress', function (e) {
|
||||
optionElements.cursorBlink.addEventListener('change', function () {
|
||||
term.setOption('cursorBlink', optionElements.cursorBlink.checked);
|
||||
});
|
||||
optionElements.macOptionIsMeta.addEventListener('change', function () {
|
||||
term.setOption('macOptionIsMeta', optionElements.macOptionIsMeta.checked);
|
||||
});
|
||||
optionElements.transparency.addEventListener('change', function () {
|
||||
var checked = optionElements.transparency.checked;
|
||||
term.setOption('allowTransparency', checked);
|
||||
term.setOption('theme', checked ? {background: 'rgba(0, 0, 0, .5)'} : {});
|
||||
});
|
||||
optionElements.cursorStyle.addEventListener('change', function () {
|
||||
term.setOption('cursorStyle', optionElements.cursorStyle.value);
|
||||
});
|
||||
optionElements.bellStyle.addEventListener('change', function () {
|
||||
term.setOption('bellStyle', optionElements.bellStyle.value);
|
||||
});
|
||||
optionElements.macOptionIsMeta.addEventListener('change', function () {
|
||||
term.setOption('macOptionIsMeta', optionElements.macOptionIsMeta.checked);
|
||||
});
|
||||
optionElements.scrollback.addEventListener('change', function () {
|
||||
term.setOption('scrollback', parseInt(optionElements.scrollback.value, 10));
|
||||
});
|
||||
optionElements.tabstopwidth.addEventListener('change', function () {
|
||||
term.setOption('tabStopWidth', parseInt(optionElements.tabstopwidth.value, 10));
|
||||
});
|
||||
optionElements.experimentalCharAtlas.addEventListener('change', function () {
|
||||
term.setOption('experimentalCharAtlas', optionElements.experimentalCharAtlas.value);
|
||||
});
|
||||
optionElements.screenReaderMode.addEventListener('change', function () {
|
||||
term.setOption('screenReaderMode', optionElements.screenReaderMode.checked);
|
||||
});
|
||||
|
||||
+5
-37
@@ -1,48 +1,16 @@
|
||||
{
|
||||
"name": "xterm",
|
||||
"description": "Full xterm terminal, in your browser",
|
||||
"version": "3.3.0",
|
||||
"ignore": [
|
||||
"demo",
|
||||
"test",
|
||||
".gitignore"
|
||||
],
|
||||
"version": "3.4.0",
|
||||
"main": "lib/Terminal.js",
|
||||
"types": "typings/xterm.d.ts",
|
||||
"repository": "https://github.com/xtermjs/xterm.js",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.json",
|
||||
"dist/*.css",
|
||||
"dist/**/*.css",
|
||||
"dist/*.js",
|
||||
"dist/*.js.map",
|
||||
"dist/**/*.js",
|
||||
"dist/**/*.js.map",
|
||||
"lib/*.css",
|
||||
"lib/**/*.css",
|
||||
"lib/*.d.ts",
|
||||
"lib/*.js",
|
||||
"lib/*.js.map",
|
||||
"lib/**/*.d.ts",
|
||||
"lib/**/*.js",
|
||||
"lib/**/*.js.map",
|
||||
"src/*.css",
|
||||
"src/**/*.css",
|
||||
"src/*.js",
|
||||
"src/*.js.map",
|
||||
"src/*.ts",
|
||||
"src/**/*.js",
|
||||
"src/**/*.js.map",
|
||||
"src/**/*.ts",
|
||||
"typings/*.d.ts"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/chai": "^3.4.34",
|
||||
"@types/jsdom": "^11.0.1",
|
||||
"@types/mocha": "^2.2.33",
|
||||
"@types/node": "^6.0.41",
|
||||
"@types/node": "6.0.108",
|
||||
"@types/text-encoding": "0.0.32",
|
||||
"browserify": "^13.3.0",
|
||||
"chai": "3.5.0",
|
||||
@@ -67,6 +35,7 @@
|
||||
"npm-run-all": "^4.1.2",
|
||||
"sorcery": "^0.10.0",
|
||||
"tslint": "^5.9.1",
|
||||
"tslint-consistent-codestyle": "^1.13.0",
|
||||
"typescript": "~2.7.1",
|
||||
"vinyl-buffer": "^1.0.0",
|
||||
"vinyl-source-stream": "^1.1.0",
|
||||
@@ -77,7 +46,7 @@
|
||||
"scripts": {
|
||||
"start": "node demo/app",
|
||||
"start-zmodem": "node demo/zmodem/app",
|
||||
"lint": "tslint src/*.ts src/**/*.ts",
|
||||
"lint": "tslint 'src/**/*.ts'",
|
||||
"test": "npm-run-all mocha lint",
|
||||
"test-debug": "node --inspect-brk node_modules/.bin/gulp test",
|
||||
"test-suite": "gulp mocha-suite --test",
|
||||
@@ -90,6 +59,5 @@
|
||||
"coveralls": "gulp coveralls",
|
||||
"webpack": "gulp webpack",
|
||||
"watch": "gulp watch"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-11
@@ -12,9 +12,9 @@ import { IDisposable } from 'xterm';
|
||||
|
||||
const MAX_ROWS_TO_READ = 20;
|
||||
|
||||
enum BoundaryPosition {
|
||||
Top,
|
||||
Bottom
|
||||
const enum BoundaryPosition {
|
||||
TOP,
|
||||
BOTTOM
|
||||
}
|
||||
|
||||
export class AccessibilityManager implements IDisposable {
|
||||
@@ -54,8 +54,8 @@ export class AccessibilityManager implements IDisposable {
|
||||
this._rowContainer.appendChild(this._rowElements[i]);
|
||||
}
|
||||
|
||||
this._topBoundaryFocusListener = e => this._onBoundaryFocus(e, BoundaryPosition.Top);
|
||||
this._bottomBoundaryFocusListener = e => this._onBoundaryFocus(e, BoundaryPosition.Bottom);
|
||||
this._topBoundaryFocusListener = e => this._onBoundaryFocus(e, BoundaryPosition.TOP);
|
||||
this._bottomBoundaryFocusListener = e => this._onBoundaryFocus(e, BoundaryPosition.BOTTOM);
|
||||
this._rowElements[0].addEventListener('focus', this._topBoundaryFocusListener);
|
||||
this._rowElements[this._rowElements.length - 1].addEventListener('focus', this._bottomBoundaryFocusListener);
|
||||
|
||||
@@ -101,11 +101,11 @@ export class AccessibilityManager implements IDisposable {
|
||||
|
||||
private _onBoundaryFocus(e: FocusEvent, position: BoundaryPosition): void {
|
||||
const boundaryElement = <HTMLElement>e.target;
|
||||
const beforeBoundaryElement = this._rowElements[position === BoundaryPosition.Top ? 1 : this._rowElements.length - 2];
|
||||
const beforeBoundaryElement = this._rowElements[position === BoundaryPosition.TOP ? 1 : this._rowElements.length - 2];
|
||||
|
||||
// Don't scroll if the buffer top has reached the end in that direction
|
||||
const posInSet = boundaryElement.getAttribute('aria-posinset');
|
||||
const lastRowPos = position === BoundaryPosition.Top ? '1' : `${this._terminal.buffer.lines.length}`;
|
||||
const lastRowPos = position === BoundaryPosition.TOP ? '1' : `${this._terminal.buffer.lines.length}`;
|
||||
if (posInSet === lastRowPos) {
|
||||
return;
|
||||
}
|
||||
@@ -119,7 +119,7 @@ export class AccessibilityManager implements IDisposable {
|
||||
// Remove old boundary element from array
|
||||
let topBoundaryElement: HTMLElement;
|
||||
let bottomBoundaryElement: HTMLElement;
|
||||
if (position === BoundaryPosition.Top) {
|
||||
if (position === BoundaryPosition.TOP) {
|
||||
topBoundaryElement = boundaryElement;
|
||||
bottomBoundaryElement = this._rowElements.pop()!;
|
||||
this._rowContainer.removeChild(bottomBoundaryElement);
|
||||
@@ -134,7 +134,7 @@ export class AccessibilityManager implements IDisposable {
|
||||
bottomBoundaryElement.removeEventListener('focus', this._bottomBoundaryFocusListener);
|
||||
|
||||
// Add new element to array/DOM
|
||||
if (position === BoundaryPosition.Top) {
|
||||
if (position === BoundaryPosition.TOP) {
|
||||
const newElement = this._createAccessibilityTreeNode();
|
||||
this._rowElements.unshift(newElement);
|
||||
this._rowContainer.insertAdjacentElement('afterbegin', newElement);
|
||||
@@ -149,10 +149,10 @@ export class AccessibilityManager implements IDisposable {
|
||||
this._rowElements[this._rowElements.length - 1].addEventListener('focus', this._bottomBoundaryFocusListener);
|
||||
|
||||
// Scroll up
|
||||
this._terminal.scrollLines(position === BoundaryPosition.Top ? -1 : 1);
|
||||
this._terminal.scrollLines(position === BoundaryPosition.TOP ? -1 : 1);
|
||||
|
||||
// Focus new boundary before element
|
||||
this._rowElements[position === BoundaryPosition.Top ? 1 : this._rowElements.length - 2].focus();
|
||||
this._rowElements[position === BoundaryPosition.TOP ? 1 : this._rowElements.length - 2].focus();
|
||||
|
||||
// Prevent the standard behavior
|
||||
e.preventDefault();
|
||||
|
||||
+20
-25
@@ -22,8 +22,7 @@ export const MAX_BUFFER_SIZE = 4294967295; // 2^32 - 1
|
||||
* - scroll position
|
||||
*/
|
||||
export class Buffer implements IBuffer {
|
||||
private _lines: CircularList<LineData>;
|
||||
|
||||
public lines: CircularList<LineData>;
|
||||
public ydisp: number;
|
||||
public ybase: number;
|
||||
public y: number;
|
||||
@@ -48,10 +47,6 @@ export class Buffer implements IBuffer {
|
||||
this.clear();
|
||||
}
|
||||
|
||||
public get lines(): CircularList<LineData> {
|
||||
return this._lines;
|
||||
}
|
||||
|
||||
public get hasScrollback(): boolean {
|
||||
return this._hasScrollback && this.lines.maxLength > this._terminal.rows;
|
||||
}
|
||||
@@ -81,7 +76,7 @@ export class Buffer implements IBuffer {
|
||||
* Fills the buffer's viewport with blank lines.
|
||||
*/
|
||||
public fillViewportRows(): void {
|
||||
if (this._lines.length === 0) {
|
||||
if (this.lines.length === 0) {
|
||||
let i = this._terminal.rows;
|
||||
while (i--) {
|
||||
this.lines.push(this._terminal.blankLine());
|
||||
@@ -97,7 +92,7 @@ export class Buffer implements IBuffer {
|
||||
this.ybase = 0;
|
||||
this.y = 0;
|
||||
this.x = 0;
|
||||
this._lines = new CircularList<LineData>(this._getCorrectBufferLength(this._terminal.rows));
|
||||
this.lines = new CircularList<LineData>(this._getCorrectBufferLength(this._terminal.rows));
|
||||
this.scrollTop = 0;
|
||||
this.scrollBottom = this._terminal.rows - 1;
|
||||
this.setupTabStops();
|
||||
@@ -112,19 +107,19 @@ export class Buffer implements IBuffer {
|
||||
// Increase max length if needed before adjustments to allow space to fill
|
||||
// as required.
|
||||
const newMaxLength = this._getCorrectBufferLength(newRows);
|
||||
if (newMaxLength > this._lines.maxLength) {
|
||||
this._lines.maxLength = newMaxLength;
|
||||
if (newMaxLength > this.lines.maxLength) {
|
||||
this.lines.maxLength = newMaxLength;
|
||||
}
|
||||
|
||||
// The following adjustments should only happen if the buffer has been
|
||||
// initialized/filled.
|
||||
if (this._lines.length > 0) {
|
||||
if (this.lines.length > 0) {
|
||||
// Deal with columns increasing (we don't do anything when columns reduce)
|
||||
if (this._terminal.cols < newCols) {
|
||||
const ch: CharData = [this._terminal.defAttr, ' ', 1, 32]; // does xterm use the default attr?
|
||||
for (let i = 0; i < this._lines.length; i++) {
|
||||
while (this._lines.get(i).length < newCols) {
|
||||
this._lines.get(i).push(ch);
|
||||
for (let i = 0; i < this.lines.length; i++) {
|
||||
while (this.lines.get(i).length < newCols) {
|
||||
this.lines.get(i).push(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,8 +128,8 @@ export class Buffer implements IBuffer {
|
||||
let addToY = 0;
|
||||
if (this._terminal.rows < newRows) {
|
||||
for (let y = this._terminal.rows; y < newRows; y++) {
|
||||
if (this._lines.length < newRows + this.ybase) {
|
||||
if (this.ybase > 0 && this._lines.length <= this.ybase + this.y + addToY + 1) {
|
||||
if (this.lines.length < newRows + this.ybase) {
|
||||
if (this.ybase > 0 && this.lines.length <= this.ybase + this.y + addToY + 1) {
|
||||
// There is room above the buffer and there are no empty elements below the line,
|
||||
// scroll up
|
||||
this.ybase--;
|
||||
@@ -146,16 +141,16 @@ export class Buffer implements IBuffer {
|
||||
} else {
|
||||
// Add a blank line if there is no buffer left at the top to scroll to, or if there
|
||||
// are blank lines after the cursor
|
||||
this._lines.push(this._terminal.blankLine(undefined, undefined, newCols));
|
||||
this.lines.push(this._terminal.blankLine(undefined, undefined, newCols));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // (this._terminal.rows >= newRows)
|
||||
for (let y = this._terminal.rows; y > newRows; y--) {
|
||||
if (this._lines.length > newRows + this.ybase) {
|
||||
if (this._lines.length > this.ybase + this.y + 1) {
|
||||
if (this.lines.length > newRows + this.ybase) {
|
||||
if (this.lines.length > this.ybase + this.y + 1) {
|
||||
// The line is a blank line below the cursor, remove it
|
||||
this._lines.pop();
|
||||
this.lines.pop();
|
||||
} else {
|
||||
// The line is the cursor, scroll down
|
||||
this.ybase++;
|
||||
@@ -167,15 +162,15 @@ export class Buffer implements IBuffer {
|
||||
|
||||
// Reduce max length if needed after adjustments, this is done after as it
|
||||
// would otherwise cut data from the bottom of the buffer.
|
||||
if (newMaxLength < this._lines.maxLength) {
|
||||
if (newMaxLength < this.lines.maxLength) {
|
||||
// Trim from the top of the buffer and adjust ybase and ydisp.
|
||||
const amountToTrim = this._lines.length - newMaxLength;
|
||||
const amountToTrim = this.lines.length - newMaxLength;
|
||||
if (amountToTrim > 0) {
|
||||
this._lines.trimStart(amountToTrim);
|
||||
this.lines.trimStart(amountToTrim);
|
||||
this.ybase = Math.max(this.ybase - amountToTrim, 0);
|
||||
this.ydisp = Math.max(this.ydisp - amountToTrim, 0);
|
||||
}
|
||||
this._lines.maxLength = newMaxLength;
|
||||
this.lines.maxLength = newMaxLength;
|
||||
}
|
||||
|
||||
// Make sure that the cursor stays on screen
|
||||
@@ -310,7 +305,7 @@ export class Buffer implements IBuffer {
|
||||
public addMarker(y: number): Marker {
|
||||
const marker = new Marker(y);
|
||||
this.markers.push(marker);
|
||||
marker.disposables.push(this._lines.addDisposableListener('trim', amount => {
|
||||
marker.disposables.push(this.lines.addDisposableListener('trim', amount => {
|
||||
marker.line -= amount;
|
||||
// The marker should be disposed when the line is trimmed from the buffer
|
||||
if (marker.line < 0) {
|
||||
|
||||
@@ -92,11 +92,10 @@ export class CompositionHelper {
|
||||
} else if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) {
|
||||
// Continue composing if the keyCode is a modifier key
|
||||
return false;
|
||||
} else {
|
||||
// Finish composition immediately. This is mainly here for the case where enter is
|
||||
// pressed and the handler needs to be triggered before the command is executed.
|
||||
this._finalizeComposition(false);
|
||||
}
|
||||
// Finish composition immediately. This is mainly here for the case where enter is
|
||||
// pressed and the handler needs to be triggered before the command is executed.
|
||||
this._finalizeComposition(false);
|
||||
}
|
||||
|
||||
if (ev.keyCode === 229) {
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
import { XtermListener } from './Types';
|
||||
import { IEventEmitter, IDisposable } from 'xterm';
|
||||
|
||||
export class EventEmitter implements IEventEmitter {
|
||||
export class EventEmitter implements IEventEmitter, IDisposable {
|
||||
private _events: {[type: string]: XtermListener[]};
|
||||
|
||||
constructor() {
|
||||
@@ -75,7 +75,7 @@ export class EventEmitter implements IEventEmitter {
|
||||
return this._events[type] || [];
|
||||
}
|
||||
|
||||
protected destroy(): void {
|
||||
public dispose(): void {
|
||||
this._events = {};
|
||||
}
|
||||
}
|
||||
|
||||
+113
-70
@@ -23,6 +23,10 @@ export class InputHandler implements IInputHandler {
|
||||
|
||||
public addChar(char: string, code: number): void {
|
||||
if (char >= ' ') {
|
||||
|
||||
// make buffer local for faster access
|
||||
const buffer = this._terminal.buffer;
|
||||
|
||||
// calculate print space
|
||||
// expensive call, therefore we save width in line buffer
|
||||
const chWidth = wcwidth(code);
|
||||
@@ -35,42 +39,42 @@ export class InputHandler implements IInputHandler {
|
||||
this._terminal.emit('a11y.char', char);
|
||||
}
|
||||
|
||||
let row = this._terminal.buffer.y + this._terminal.buffer.ybase;
|
||||
let row = buffer.y + buffer.ybase;
|
||||
|
||||
// insert combining char in last cell
|
||||
// FIXME: needs handling after cursor jumps
|
||||
if (!chWidth && this._terminal.buffer.x) {
|
||||
if (!chWidth && buffer.x) {
|
||||
// dont overflow left
|
||||
if (this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1]) {
|
||||
if (!this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1][CHAR_DATA_WIDTH_INDEX]) {
|
||||
if (buffer.lines.get(row)[buffer.x - 1]) {
|
||||
if (!buffer.lines.get(row)[buffer.x - 1][CHAR_DATA_WIDTH_INDEX]) {
|
||||
// found empty cell after fullwidth, need to go 2 cells back
|
||||
if (this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2]) {
|
||||
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2][CHAR_DATA_CHAR_INDEX] += char;
|
||||
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2][3] = char.charCodeAt(0);
|
||||
if (buffer.lines.get(row)[buffer.x - 2]) {
|
||||
buffer.lines.get(row)[buffer.x - 2][CHAR_DATA_CHAR_INDEX] += char;
|
||||
buffer.lines.get(row)[buffer.x - 2][3] = char.charCodeAt(0);
|
||||
}
|
||||
} else {
|
||||
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1][CHAR_DATA_CHAR_INDEX] += char;
|
||||
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1][3] = char.charCodeAt(0);
|
||||
buffer.lines.get(row)[buffer.x - 1][CHAR_DATA_CHAR_INDEX] += char;
|
||||
buffer.lines.get(row)[buffer.x - 1][3] = char.charCodeAt(0);
|
||||
}
|
||||
this._terminal.updateRange(this._terminal.buffer.y);
|
||||
this._terminal.updateRange(buffer.y);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// goto next line if ch would overflow
|
||||
// TODO: needs a global min terminal width of 2
|
||||
if (this._terminal.buffer.x + chWidth - 1 >= this._terminal.cols) {
|
||||
if (buffer.x + chWidth - 1 >= this._terminal.cols) {
|
||||
// autowrap - DECAWM
|
||||
if (this._terminal.wraparoundMode) {
|
||||
this._terminal.buffer.x = 0;
|
||||
this._terminal.buffer.y++;
|
||||
if (this._terminal.buffer.y > this._terminal.buffer.scrollBottom) {
|
||||
this._terminal.buffer.y--;
|
||||
buffer.x = 0;
|
||||
buffer.y++;
|
||||
if (buffer.y > buffer.scrollBottom) {
|
||||
buffer.y--;
|
||||
this._terminal.scroll(true);
|
||||
} else {
|
||||
// The line already exists (eg. the initial viewport), mark it as a
|
||||
// wrapped line
|
||||
(<any>this._terminal.buffer.lines.get(this._terminal.buffer.y)).isWrapped = true;
|
||||
(<any>buffer.lines.get(buffer.y)).isWrapped = true;
|
||||
}
|
||||
} else {
|
||||
if (chWidth === 2) { // FIXME: check for xterm behavior
|
||||
@@ -78,7 +82,7 @@ export class InputHandler implements IInputHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
row = this._terminal.buffer.y + this._terminal.buffer.ybase;
|
||||
row = buffer.y + buffer.ybase;
|
||||
|
||||
// insert mode: move characters to right
|
||||
if (this._terminal.insertMode) {
|
||||
@@ -86,26 +90,26 @@ export class InputHandler implements IInputHandler {
|
||||
for (let moves = 0; moves < chWidth; ++moves) {
|
||||
// remove last cell, if it's width is 0
|
||||
// we have to adjust the second last cell as well
|
||||
const removed = this._terminal.buffer.lines.get(this._terminal.buffer.y + this._terminal.buffer.ybase).pop();
|
||||
const removed = buffer.lines.get(buffer.y + buffer.ybase).pop();
|
||||
if (removed[CHAR_DATA_WIDTH_INDEX] === 0
|
||||
&& this._terminal.buffer.lines.get(row)[this._terminal.cols - 2]
|
||||
&& this._terminal.buffer.lines.get(row)[this._terminal.cols - 2][CHAR_DATA_WIDTH_INDEX] === 2) {
|
||||
this._terminal.buffer.lines.get(row)[this._terminal.cols - 2] = [this._terminal.curAttr, ' ', 1, ' '.charCodeAt(0)];
|
||||
&& buffer.lines.get(row)[this._terminal.cols - 2]
|
||||
&& buffer.lines.get(row)[this._terminal.cols - 2][CHAR_DATA_WIDTH_INDEX] === 2) {
|
||||
buffer.lines.get(row)[this._terminal.cols - 2] = [this._terminal.curAttr, ' ', 1, ' '.charCodeAt(0)];
|
||||
}
|
||||
|
||||
// insert empty cell at cursor
|
||||
this._terminal.buffer.lines.get(row).splice(this._terminal.buffer.x, 0, [this._terminal.curAttr, ' ', 1, ' '.charCodeAt(0)]);
|
||||
buffer.lines.get(row).splice(buffer.x, 0, [this._terminal.curAttr, ' ', 1, ' '.charCodeAt(0)]);
|
||||
}
|
||||
}
|
||||
|
||||
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, char, chWidth, char.charCodeAt(0)];
|
||||
this._terminal.buffer.x++;
|
||||
this._terminal.updateRange(this._terminal.buffer.y);
|
||||
buffer.lines.get(row)[buffer.x] = [this._terminal.curAttr, char, chWidth, char.charCodeAt(0)];
|
||||
buffer.x++;
|
||||
this._terminal.updateRange(buffer.y);
|
||||
|
||||
// fullwidth char - set next cell width to zero and advance cursor
|
||||
if (chWidth === 2) {
|
||||
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, '', 0, undefined];
|
||||
this._terminal.buffer.x++;
|
||||
buffer.lines.get(row)[buffer.x] = [this._terminal.curAttr, '', 0, undefined];
|
||||
buffer.x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,17 +127,20 @@ export class InputHandler implements IInputHandler {
|
||||
* Line Feed or New Line (NL). (LF is Ctrl-J).
|
||||
*/
|
||||
public lineFeed(): void {
|
||||
// make buffer local for faster access
|
||||
const buffer = this._terminal.buffer;
|
||||
|
||||
if (this._terminal.convertEol) {
|
||||
this._terminal.buffer.x = 0;
|
||||
buffer.x = 0;
|
||||
}
|
||||
this._terminal.buffer.y++;
|
||||
if (this._terminal.buffer.y > this._terminal.buffer.scrollBottom) {
|
||||
this._terminal.buffer.y--;
|
||||
buffer.y++;
|
||||
if (buffer.y > buffer.scrollBottom) {
|
||||
buffer.y--;
|
||||
this._terminal.scroll();
|
||||
}
|
||||
// If the end of the line is hit, prevent this action from wrapping around to the next line.
|
||||
if (this._terminal.buffer.x >= this._terminal.cols) {
|
||||
this._terminal.buffer.x--;
|
||||
if (buffer.x >= this._terminal.cols) {
|
||||
buffer.x--;
|
||||
}
|
||||
/**
|
||||
* This event is emitted whenever the terminal outputs a LF or NL.
|
||||
@@ -199,13 +206,16 @@ export class InputHandler implements IInputHandler {
|
||||
let param = params[0];
|
||||
if (param < 1) param = 1;
|
||||
|
||||
const row = this._terminal.buffer.y + this._terminal.buffer.ybase;
|
||||
let j = this._terminal.buffer.x;
|
||||
// make buffer local for faster access
|
||||
const buffer = this._terminal.buffer;
|
||||
|
||||
const row = buffer.y + buffer.ybase;
|
||||
let j = buffer.x;
|
||||
const ch: CharData = [this._terminal.eraseAttr(), ' ', 1, 32]; // xterm
|
||||
|
||||
while (param-- && j < this._terminal.cols) {
|
||||
this._terminal.buffer.lines.get(row).splice(j++, 0, ch);
|
||||
this._terminal.buffer.lines.get(row).pop();
|
||||
buffer.lines.get(row).splice(j++, 0, ch);
|
||||
buffer.lines.get(row).pop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,20 +457,24 @@ export class InputHandler implements IInputHandler {
|
||||
if (param < 1) {
|
||||
param = 1;
|
||||
}
|
||||
let row: number = this._terminal.buffer.y + this._terminal.buffer.ybase;
|
||||
|
||||
let scrollBottomRowsOffset = this._terminal.rows - 1 - this._terminal.buffer.scrollBottom;
|
||||
let scrollBottomAbsolute = this._terminal.rows - 1 + this._terminal.buffer.ybase - scrollBottomRowsOffset + 1;
|
||||
// make buffer local for faster access
|
||||
const buffer = this._terminal.buffer;
|
||||
|
||||
let row: number = buffer.y + buffer.ybase;
|
||||
|
||||
let scrollBottomRowsOffset = this._terminal.rows - 1 - buffer.scrollBottom;
|
||||
let scrollBottomAbsolute = this._terminal.rows - 1 + buffer.ybase - scrollBottomRowsOffset + 1;
|
||||
while (param--) {
|
||||
// test: echo -e '\e[44m\e[1L\e[0m'
|
||||
// blankLine(true) - xterm/linux behavior
|
||||
this._terminal.buffer.lines.splice(scrollBottomAbsolute - 1, 1);
|
||||
this._terminal.buffer.lines.splice(row, 0, this._terminal.blankLine(true));
|
||||
buffer.lines.splice(scrollBottomAbsolute - 1, 1);
|
||||
buffer.lines.splice(row, 0, this._terminal.blankLine(true));
|
||||
}
|
||||
|
||||
// this.maxRange();
|
||||
this._terminal.updateRange(this._terminal.buffer.y);
|
||||
this._terminal.updateRange(this._terminal.buffer.scrollBottom);
|
||||
this._terminal.updateRange(buffer.y);
|
||||
this._terminal.updateRange(buffer.scrollBottom);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -472,21 +486,25 @@ export class InputHandler implements IInputHandler {
|
||||
if (param < 1) {
|
||||
param = 1;
|
||||
}
|
||||
const row: number = this._terminal.buffer.y + this._terminal.buffer.ybase;
|
||||
|
||||
// make buffer local for faster access
|
||||
const buffer = this._terminal.buffer;
|
||||
|
||||
const row: number = buffer.y + buffer.ybase;
|
||||
|
||||
let j: number;
|
||||
j = this._terminal.rows - 1 - this._terminal.buffer.scrollBottom;
|
||||
j = this._terminal.rows - 1 + this._terminal.buffer.ybase - j;
|
||||
j = this._terminal.rows - 1 - buffer.scrollBottom;
|
||||
j = this._terminal.rows - 1 + buffer.ybase - j;
|
||||
while (param--) {
|
||||
// test: echo -e '\e[44m\e[1M\e[0m'
|
||||
// blankLine(true) - xterm/linux behavior
|
||||
this._terminal.buffer.lines.splice(row, 1);
|
||||
this._terminal.buffer.lines.splice(j, 0, this._terminal.blankLine(true));
|
||||
buffer.lines.splice(row, 1);
|
||||
buffer.lines.splice(j, 0, this._terminal.blankLine(true));
|
||||
}
|
||||
|
||||
// this.maxRange();
|
||||
this._terminal.updateRange(this._terminal.buffer.y);
|
||||
this._terminal.updateRange(this._terminal.buffer.scrollBottom);
|
||||
this._terminal.updateRange(buffer.y);
|
||||
this._terminal.updateRange(buffer.scrollBottom);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -499,14 +517,17 @@ export class InputHandler implements IInputHandler {
|
||||
param = 1;
|
||||
}
|
||||
|
||||
const row = this._terminal.buffer.y + this._terminal.buffer.ybase;
|
||||
// make buffer local for faster access
|
||||
const buffer = this._terminal.buffer;
|
||||
|
||||
const row = buffer.y + buffer.ybase;
|
||||
const ch: CharData = [this._terminal.eraseAttr(), ' ', 1, 32]; // xterm
|
||||
|
||||
while (param--) {
|
||||
this._terminal.buffer.lines.get(row).splice(this._terminal.buffer.x, 1);
|
||||
this._terminal.buffer.lines.get(row).push(ch);
|
||||
buffer.lines.get(row).splice(buffer.x, 1);
|
||||
buffer.lines.get(row).push(ch);
|
||||
}
|
||||
this._terminal.updateRange(this._terminal.buffer.y);
|
||||
this._terminal.updateRange(buffer.y);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -514,13 +535,17 @@ export class InputHandler implements IInputHandler {
|
||||
*/
|
||||
public scrollUp(params: number[]): void {
|
||||
let param = params[0] || 1;
|
||||
|
||||
// make buffer local for faster access
|
||||
const buffer = this._terminal.buffer;
|
||||
|
||||
while (param--) {
|
||||
this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollTop, 1);
|
||||
this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollBottom, 0, this._terminal.blankLine());
|
||||
buffer.lines.splice(buffer.ybase + buffer.scrollTop, 1);
|
||||
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, this._terminal.blankLine());
|
||||
}
|
||||
// this.maxRange();
|
||||
this._terminal.updateRange(this._terminal.buffer.scrollTop);
|
||||
this._terminal.updateRange(this._terminal.buffer.scrollBottom);
|
||||
this._terminal.updateRange(buffer.scrollTop);
|
||||
this._terminal.updateRange(buffer.scrollBottom);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -528,13 +553,17 @@ export class InputHandler implements IInputHandler {
|
||||
*/
|
||||
public scrollDown(params: number[]): void {
|
||||
let param = params[0] || 1;
|
||||
|
||||
// make buffer local for faster access
|
||||
const buffer = this._terminal.buffer;
|
||||
|
||||
while (param--) {
|
||||
this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollBottom, 1);
|
||||
this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollTop, 0, this._terminal.blankLine());
|
||||
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 1);
|
||||
buffer.lines.splice(buffer.ybase + buffer.scrollTop, 0, this._terminal.blankLine());
|
||||
}
|
||||
// this.maxRange();
|
||||
this._terminal.updateRange(this._terminal.buffer.scrollTop);
|
||||
this._terminal.updateRange(this._terminal.buffer.scrollBottom);
|
||||
this._terminal.updateRange(buffer.scrollTop);
|
||||
this._terminal.updateRange(buffer.scrollBottom);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -547,12 +576,15 @@ export class InputHandler implements IInputHandler {
|
||||
param = 1;
|
||||
}
|
||||
|
||||
const row = this._terminal.buffer.y + this._terminal.buffer.ybase;
|
||||
let j = this._terminal.buffer.x;
|
||||
// make buffer local for faster access
|
||||
const buffer = this._terminal.buffer;
|
||||
|
||||
const row = buffer.y + buffer.ybase;
|
||||
let j = buffer.x;
|
||||
const ch: CharData = [this._terminal.eraseAttr(), ' ', 1, 32]; // xterm
|
||||
|
||||
while (param-- && j < this._terminal.cols) {
|
||||
this._terminal.buffer.lines.get(row)[j++] = ch;
|
||||
buffer.lines.get(row)[j++] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -561,8 +593,12 @@ export class InputHandler implements IInputHandler {
|
||||
*/
|
||||
public cursorBackwardTab(params: number[]): void {
|
||||
let param = params[0] || 1;
|
||||
|
||||
// make buffer local for faster access
|
||||
const buffer = this._terminal.buffer;
|
||||
|
||||
while (param--) {
|
||||
this._terminal.buffer.x = this._terminal.buffer.prevStop();
|
||||
buffer.x = buffer.prevStop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,11 +638,15 @@ export class InputHandler implements IInputHandler {
|
||||
*/
|
||||
public repeatPrecedingCharacter(params: number[]): void {
|
||||
let param = params[0] || 1;
|
||||
const line = this._terminal.buffer.lines.get(this._terminal.buffer.ybase + this._terminal.buffer.y);
|
||||
const ch = line[this._terminal.buffer.x - 1] || [this._terminal.defAttr, ' ', 1, 32];
|
||||
|
||||
// make buffer local for faster access
|
||||
const buffer = this._terminal.buffer;
|
||||
|
||||
const line = buffer.lines.get(buffer.ybase + buffer.y);
|
||||
const ch = line[buffer.x - 1] || [this._terminal.defAttr, ' ', 1, 32];
|
||||
|
||||
while (param--) {
|
||||
line[this._terminal.buffer.x++] = ch;
|
||||
line[buffer.x++] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1223,6 +1263,9 @@ export class InputHandler implements IInputHandler {
|
||||
} else if (p === 1) {
|
||||
// bold text
|
||||
flags |= FLAGS.BOLD;
|
||||
} else if (p === 3) {
|
||||
// italic text
|
||||
flags |= FLAGS.ITALIC;
|
||||
} else if (p === 4) {
|
||||
// underlined text
|
||||
flags |= FLAGS.UNDERLINE;
|
||||
|
||||
@@ -40,7 +40,7 @@ describe('Linkifier', () => {
|
||||
terminal = new MockTerminal();
|
||||
terminal.cols = 100;
|
||||
terminal.buffer = new MockBuffer();
|
||||
terminal.buffer.lines = new CircularList<LineData>(20);
|
||||
(<MockBuffer>terminal.buffer).setLines(new CircularList<LineData>(20));
|
||||
terminal.buffer.ydisp = 0;
|
||||
linkifier = new TestLinkifier(terminal);
|
||||
mouseZoneManager = new TestMouseZoneManager();
|
||||
|
||||
+1
-1
@@ -150,7 +150,7 @@ csiStateHandler['s'] = (handler, params) => handler.saveCursor(params);
|
||||
csiStateHandler['u'] = (handler, params) => handler.restoreCursor(params);
|
||||
csiStateHandler[C0.CAN] = (handler, params, prefix, postfix, parser) => parser.setState(ParserState.NORMAL);
|
||||
|
||||
export enum ParserState {
|
||||
export const enum ParserState {
|
||||
NORMAL = 0,
|
||||
ESCAPED = 1,
|
||||
CSI_PARAM = 2,
|
||||
|
||||
@@ -54,7 +54,7 @@ interface IWordPosition {
|
||||
/**
|
||||
* A selection mode, this drives how the selection behaves on mouse move.
|
||||
*/
|
||||
enum SelectionMode {
|
||||
const enum SelectionMode {
|
||||
NORMAL,
|
||||
WORD,
|
||||
LINE
|
||||
|
||||
+43
-24
@@ -38,6 +38,7 @@ import { Linkifier } from './Linkifier';
|
||||
import { SelectionManager } from './SelectionManager';
|
||||
import { CharMeasure } from './utils/CharMeasure';
|
||||
import * as Browser from './shared/utils/Browser';
|
||||
import * as Dom from './utils/Dom';
|
||||
import * as Strings from './Strings';
|
||||
import { MouseHelper } from './utils/MouseHelper';
|
||||
import { clone } from './utils/Clone';
|
||||
@@ -46,7 +47,8 @@ import { DEFAULT_ANSI_COLORS } from './renderer/ColorManager';
|
||||
import { MouseZoneManager } from './input/MouseZoneManager';
|
||||
import { AccessibilityManager } from './AccessibilityManager';
|
||||
import { ScreenDprMonitor } from './utils/ScreenDprMonitor';
|
||||
import { ITheme, ILocalizableStrings, IMarker } from 'xterm';
|
||||
import { ITheme, ILocalizableStrings, IMarker, IDisposable } from 'xterm';
|
||||
import { removeTerminalFromCache } from './renderer/atlas/CharAtlasCache';
|
||||
|
||||
// reg + shift key mappings for digits and special chars
|
||||
const KEYCODE_KEY_MAPPINGS = {
|
||||
@@ -101,7 +103,9 @@ const DEFAULT_OPTIONS: ITerminalOptions = {
|
||||
cursorStyle: 'block',
|
||||
bellSound: DEFAULT_BELL_SOUND,
|
||||
bellStyle: 'none',
|
||||
drawBoldTextInBrightColors: true,
|
||||
enableBold: true,
|
||||
experimentalCharAtlas: 'static',
|
||||
fontFamily: 'courier-new, courier, monospace',
|
||||
fontSize: 15,
|
||||
fontWeight: 'normal',
|
||||
@@ -120,15 +124,15 @@ const DEFAULT_OPTIONS: ITerminalOptions = {
|
||||
tabStopWidth: 8,
|
||||
theme: null,
|
||||
rightClickSelectsWord: Browser.isMac
|
||||
// programFeatures: false,
|
||||
// focusKeys: false,
|
||||
};
|
||||
|
||||
export class Terminal extends EventEmitter implements ITerminal, IInputHandlingTerminal {
|
||||
export class Terminal extends EventEmitter implements ITerminal, IDisposable, IInputHandlingTerminal {
|
||||
public textarea: HTMLTextAreaElement;
|
||||
public element: HTMLElement;
|
||||
public screenElement: HTMLElement;
|
||||
|
||||
private _disposables: IDisposable[];
|
||||
|
||||
/**
|
||||
* The HTMLElement that the terminal is created in, set by Terminal.open.
|
||||
*/
|
||||
@@ -250,7 +254,28 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
||||
this._setup();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
this._disposables.forEach(d => d.dispose());
|
||||
this._disposables.length = 0;
|
||||
removeTerminalFromCache(this);
|
||||
this.handler = () => {};
|
||||
this.write = () => {};
|
||||
if (this.element && this.element.parentNode) {
|
||||
this.element.parentNode.removeChild(this.element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use dispose instead.
|
||||
*/
|
||||
public destroy(): void {
|
||||
this.dispose();
|
||||
}
|
||||
|
||||
private _setup(): void {
|
||||
this._disposables = [];
|
||||
|
||||
Object.keys(DEFAULT_OPTIONS).forEach((key) => {
|
||||
if (this.options[key] == null) {
|
||||
this.options[key] = DEFAULT_OPTIONS[key];
|
||||
@@ -449,21 +474,28 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
||||
case 'fontFamily':
|
||||
case 'fontSize':
|
||||
// When the font changes the size of the cells may change which requires a renderer clear
|
||||
this.renderer.clear();
|
||||
this.charMeasure.measure(this.options);
|
||||
if (this.renderer) {
|
||||
this.renderer.clear();
|
||||
this.charMeasure.measure(this.options);
|
||||
}
|
||||
break;
|
||||
case 'experimentalCharAtlas':
|
||||
case 'enableBold':
|
||||
case 'letterSpacing':
|
||||
case 'lineHeight':
|
||||
case 'fontWeight':
|
||||
case 'fontWeightBold':
|
||||
// When the font changes the size of the cells may change which requires a renderer clear
|
||||
this.renderer.clear();
|
||||
this.renderer.onResize(this.cols, this.rows);
|
||||
this.refresh(0, this.rows - 1);
|
||||
if (this.renderer) {
|
||||
this.renderer.clear();
|
||||
this.renderer.onResize(this.cols, this.rows);
|
||||
this.refresh(0, this.rows - 1);
|
||||
}
|
||||
case 'scrollback':
|
||||
this.buffers.resize(this.cols, this.rows);
|
||||
this.viewport.syncScrollArea();
|
||||
if (this.viewport) {
|
||||
this.viewport.syncScrollArea();
|
||||
}
|
||||
break;
|
||||
case 'screenReaderMode':
|
||||
if (value) {
|
||||
@@ -686,7 +718,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
||||
this.on('dprchange', () => this.renderer.onWindowResize(window.devicePixelRatio));
|
||||
// dprchange should handle this case, we need this as well for browsers that don't support the
|
||||
// matchMedia query.
|
||||
window.addEventListener('resize', () => this.renderer.onWindowResize(window.devicePixelRatio));
|
||||
this._disposables.push(Dom.addDisposableListener(window, 'resize', () => this.renderer.onWindowResize(window.devicePixelRatio)));
|
||||
this.charMeasure.on('charsizechanged', () => this.renderer.onResize(this.cols, this.rows));
|
||||
this.renderer.on('resize', (dimensions) => this.viewport.syncScrollArea());
|
||||
|
||||
@@ -1079,19 +1111,6 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the terminal.
|
||||
*/
|
||||
public destroy(): void {
|
||||
super.destroy();
|
||||
this.handler = () => {};
|
||||
this.write = () => {};
|
||||
if (this.element && this.element.parentNode) {
|
||||
this.element.parentNode.removeChild(this.element);
|
||||
}
|
||||
// this.emit('close');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the renderer to refresh terminal content between two rows (inclusive) at the next
|
||||
* opportunity.
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ export type LineData = CharData[];
|
||||
export type LinkMatcherHandler = (event: MouseEvent, uri: string) => void;
|
||||
export type LinkMatcherValidationCallback = (uri: string, callback: (isValid: boolean) => void) => void;
|
||||
|
||||
export enum LinkHoverEventTypes {
|
||||
export const enum LinkHoverEventTypes {
|
||||
HOVER = 'linkhover',
|
||||
TOOLTIP = 'linktooltip',
|
||||
LEAVE = 'linkleave'
|
||||
@@ -248,7 +248,7 @@ export interface ITerminalOptions extends IPublicTerminalOptions {
|
||||
}
|
||||
|
||||
export interface IBuffer {
|
||||
lines: ICircularList<LineData>;
|
||||
readonly lines: ICircularList<LineData>;
|
||||
ydisp: number;
|
||||
ybase: number;
|
||||
y: number;
|
||||
|
||||
@@ -43,7 +43,7 @@ export function attach(term: Terminal, socket: WebSocket, bidirectional: boolean
|
||||
addonTerminal.__getMessage = function(ev: MessageEvent): void {
|
||||
let str;
|
||||
|
||||
if (typeof ev.data == 'object') {
|
||||
if (typeof ev.data === 'object') {
|
||||
if (!myTextDecoder) {
|
||||
myTextDecoder = new TextDecoder();
|
||||
}
|
||||
@@ -53,14 +53,14 @@ export function attach(term: Terminal, socket: WebSocket, bidirectional: boolean
|
||||
} else {
|
||||
let fileReader = new FileReader();
|
||||
|
||||
fileReader.addEventListener('load', function() {
|
||||
fileReader.addEventListener('load', () => {
|
||||
str = myTextDecoder.decode(this.result);
|
||||
displayData(str);
|
||||
});
|
||||
fileReader.readAsArrayBuffer(ev.data);
|
||||
}
|
||||
} else if (typeof ev.data == 'string') {
|
||||
displayData(ev.data)
|
||||
} else if (typeof ev.data === 'string') {
|
||||
displayData(ev.data);
|
||||
} else {
|
||||
throw Error(`Cannot handle "${typeof ev.data}" websocket message.`);
|
||||
}
|
||||
@@ -73,7 +73,7 @@ export function attach(term: Terminal, socket: WebSocket, bidirectional: boolean
|
||||
* @param str String decoded by FileReader.
|
||||
* @param data The data of the EventMessage.
|
||||
*/
|
||||
function displayData(str?: string, data?: string) {
|
||||
function displayData(str?: string, data?: string): void {
|
||||
if (buffered) {
|
||||
addonTerminal.__pushToBuffer(str || data);
|
||||
} else {
|
||||
|
||||
@@ -43,8 +43,7 @@ export interface IZmodemOptions {
|
||||
}
|
||||
|
||||
function zmodemAttach(ws: WebSocket, opts: IZmodemOptions = {}): void {
|
||||
var term = this;
|
||||
|
||||
const term = this;
|
||||
const senderFunc = (octets: ArrayLike<number>) => ws.send(new Uint8Array(octets));
|
||||
|
||||
let zsentry;
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
import { ITerminal, ICircularList, LineData } from '../Types';
|
||||
import { C0 } from '../EscapeSequences';
|
||||
|
||||
enum Direction {
|
||||
Up = 'A',
|
||||
Down = 'B',
|
||||
Right = 'C',
|
||||
Left = 'D'
|
||||
const enum Direction {
|
||||
UP = 'A',
|
||||
DOWN = 'B',
|
||||
RIGHT = 'C',
|
||||
LEFT = 'D'
|
||||
}
|
||||
|
||||
export class AltClickHandler {
|
||||
@@ -28,7 +28,7 @@ export class AltClickHandler {
|
||||
this._startCol = this._terminal.buffer.x;
|
||||
this._startRow = this._terminal.buffer.y;
|
||||
|
||||
[this._endCol, this._endRow] = this._terminal.mouseHelper.getCoords(
|
||||
let coordinates = this._terminal.mouseHelper.getCoords(
|
||||
this._mouseEvent,
|
||||
this._terminal.element,
|
||||
this._terminal.charMeasure,
|
||||
@@ -36,16 +36,20 @@ export class AltClickHandler {
|
||||
this._terminal.cols,
|
||||
this._terminal.rows,
|
||||
false
|
||||
).map((coordinate: number) => {
|
||||
return coordinate - 1;
|
||||
});
|
||||
);
|
||||
|
||||
if (coordinates) {
|
||||
[this._endCol, this._endRow] = coordinates.map((coordinate: number) => {
|
||||
return coordinate - 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the escape sequences of arrows to the terminal
|
||||
*/
|
||||
public move(): void {
|
||||
if (this._mouseEvent.altKey) {
|
||||
if (this._mouseEvent.altKey && this._endCol !== undefined && this._endRow !== undefined) {
|
||||
this._terminal.send(this._arrowSequences());
|
||||
}
|
||||
}
|
||||
@@ -73,12 +77,11 @@ export class AltClickHandler {
|
||||
private _resetStartingRow(): string {
|
||||
if (this._moveToRequestedRow().length === 0) {
|
||||
return '';
|
||||
} else {
|
||||
return repeat(this._bufferLine(
|
||||
this._startCol, this._startRow, this._startCol,
|
||||
this._startRow - this._wrappedRowsForRow(this._startRow), false
|
||||
).length, this._sequence(Direction.Left));
|
||||
}
|
||||
return repeat(this._bufferLine(
|
||||
this._startCol, this._startRow, this._startCol,
|
||||
this._startRow - this._wrappedRowsForRow(this._startRow), false
|
||||
).length, this._sequence(Direction.LEFT));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,7 +113,7 @@ export class AltClickHandler {
|
||||
|
||||
return repeat(this._bufferLine(
|
||||
this._startCol, startRow, this._endCol, endRow,
|
||||
direction === Direction.Right
|
||||
direction === Direction.RIGHT
|
||||
).length, this._sequence(direction));
|
||||
}
|
||||
|
||||
@@ -133,7 +136,7 @@ export class AltClickHandler {
|
||||
let endRow = this._endRow - this._wrappedRowsForRow(this._endRow);
|
||||
|
||||
for (let i = 0; i < Math.abs(startRow - endRow); i++) {
|
||||
let direction = this._verticalDirection() === Direction.Up ? -1 : 1;
|
||||
let direction = this._verticalDirection() === Direction.UP ? -1 : 1;
|
||||
|
||||
if ((<any>this._lines.get(startRow + (direction * i))).isWrapped) {
|
||||
wrappedRows++;
|
||||
@@ -179,10 +182,9 @@ export class AltClickHandler {
|
||||
startRow <= this._endRow) || // down/right or same y/right
|
||||
(this._startCol >= this._endCol &&
|
||||
startRow < this._endRow)) { // down/left or same y/left
|
||||
return Direction.Right;
|
||||
} else {
|
||||
return Direction.Left;
|
||||
return Direction.RIGHT;
|
||||
}
|
||||
return Direction.LEFT;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,10 +192,9 @@ export class AltClickHandler {
|
||||
*/
|
||||
private _verticalDirection(): Direction {
|
||||
if (this._startRow > this._endRow) {
|
||||
return Direction.Up;
|
||||
} else {
|
||||
return Direction.Down;
|
||||
return Direction.UP;
|
||||
}
|
||||
return Direction.DOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user