Merge branch 'master' into script_improvements

This commit is contained in:
Daniel Imms
2018-05-21 07:54:07 -07:00
committed by GitHub
41 changed files with 1298 additions and 482 deletions
+44 -12
View File
@@ -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/
-1
View File
@@ -17,4 +17,3 @@ env:
notifications:
email: false
script: npm run $NPM_COMMAND
after_success: npm run coveralls
+8
View File
@@ -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>
+25 -4
View File
@@ -1,6 +1,6 @@
# [![xterm.js logo](logo-full.png)](https://xtermjs.org)
[![xterm.js build status](https://api.travis-ci.org/xtermjs/xterm.js.svg)](https://travis-ci.org/xtermjs/xterm.js) [![Coverage Status](https://coveralls.io/repos/github/sourcelair/xterm.js/badge.svg)](https://coveralls.io/github/sourcelair/xterm.js) [![Gitter](https://badges.gitter.im/sourcelair/xterm.js.svg)](https://gitter.im/sourcelair/xterm.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/xterm/badge?style=rounded)](https://www.jsdelivr.com/package/npm/xterm)
[![xterm.js build status](https://api.travis-ci.org/xtermjs/xterm.js.svg)](https://travis-ci.org/xtermjs/xterm.js) [![Coverage Status](https://coveralls.io/repos/github/xtermjs/xterm.js/badge.svg?branch=master)](https://coveralls.io/github/xtermjs/xterm.js?branch=master) [![Gitter](https://badges.gitter.im/sourcelair/xterm.js.svg)](https://gitter.im/sourcelair/xterm.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/xterm/badge?style=rounded)](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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+3 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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
View File
@@ -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,
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+5 -5
View File
@@ -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 {
+1 -2
View File
@@ -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;
+24 -23
View File
@@ -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