diff --git a/README.md b/README.md
index 93e7f262a..85c2ac18c 100644
--- a/README.md
+++ b/README.md
@@ -122,6 +122,9 @@ computational environment for Jupyter, supporting interactive data science and s
- [**Kubebox**](https://github.com/astefanutti/kubebox): Terminal console for Kubernetes clusters.
- [**Azure Cloud Shell**](https://shell.azure.com): Azure Cloud Shell is a Microsoft-managed admin machine built on Azure, for Azure.
- [**atom-xterm**](https://atom.io/packages/atom-xterm): Atom plugin for providing terminals inside your Atom workspace.
+- [**rtty**](https://github.com/zhaojh329/rtty): A reverse proxy WebTTY. It is composed of the client and the server.
+- [**Pisth**](https://github.com/ColdGrub1384/Pisth): An SFTP and SSH client for iOS
+- [**abstruse**](https://github.com/bleenco/abstruse): Abstruse CI is a continuous integration platform based on Node.JS and Docker.
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.
diff --git a/demo/index.html b/demo/index.html
index 93399f9cd..da348f5e6 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -23,6 +23,9 @@
cursorBlink
+
+ macOptionIsMeta
+
cursorStyle
diff --git a/demo/main.js b/demo/main.js
index 95b15a0db..1faf77d8a 100644
--- a/demo/main.js
+++ b/demo/main.js
@@ -27,6 +27,7 @@ var terminalContainer = document.getElementById('terminal-container'),
optionElements = {
cursorBlink: document.querySelector('#option-cursor-blink'),
cursorStyle: document.querySelector('#option-cursor-style'),
+ macOptionIsMeta: document.querySelector('#option-mac-option-is-meta'),
scrollback: document.querySelector('#option-scrollback'),
tabstopwidth: document.querySelector('#option-tabstopwidth'),
bellStyle: document.querySelector('#option-bell-style')
@@ -72,6 +73,9 @@ optionElements.cursorStyle.addEventListener('change', function () {
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));
});
@@ -87,6 +91,7 @@ function createTerminal() {
terminalContainer.removeChild(terminalContainer.children[0]);
}
term = new Terminal({
+ macOptionIsMeta: optionElements.macOptionIsMeta.enabled,
cursorBlink: optionElements.cursorBlink.checked,
scrollback: parseInt(optionElements.scrollback.value, 10),
tabStopWidth: parseInt(optionElements.tabstopwidth.value, 10)
diff --git a/fixtures/typings-test/typings-test.ts b/fixtures/typings-test/typings-test.ts
index b33362377..2aa2264ed 100644
--- a/fixtures/typings-test/typings-test.ts
+++ b/fixtures/typings-test/typings-test.ts
@@ -142,9 +142,11 @@ namespace methods_core {
const r18: (data: string) => void = t.getOption('handler');
const r19: string = t.getOption('bellSound');
const r20: string = t.getOption('bellStyle');
- const r21: number = t.getOption('letterSpacing');
- const r22: number = t.getOption('fontWeight');
- const r23: number = t.getOption('fontWeightBold');
+ const r21: boolean = t.getOption('enableBold');
+ const r22: number = t.getOption('letterSpacing');
+ const r23: boolean = t.getOption('macOptionIsMeta');
+ const r24: number = t.getOption('fontWeight');
+ const r25: number = t.getOption('fontWeightBold');
}
{
const t: Terminal = new Terminal();
@@ -179,6 +181,7 @@ namespace methods_core {
t.setOption('lineHeight', 1);
t.setOption('fontFamily', 'foo');
t.setOption('theme', {background: '#ff0000'});
+ t.setOption('macOptionIsMeta', true);
}
}
namespace scrolling {
diff --git a/src/Buffer.ts b/src/Buffer.ts
index 623c38543..3e7d61224 100644
--- a/src/Buffer.ts
+++ b/src/Buffer.ts
@@ -121,11 +121,6 @@ export class Buffer implements IBuffer {
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++) {
- // TODO: This should be removed, with tests setup for the case that was
- // causing the underlying bug, see https://github.com/sourcelair/xterm.js/issues/824
- if (this._lines.get(i) === undefined) {
- this._lines.set(i, this._terminal.blankLine(undefined, undefined, newCols));
- }
while (this._lines.get(i).length < newCols) {
this._lines.get(i).push(ch);
}
diff --git a/src/BufferSet.ts b/src/BufferSet.ts
index e31d2278f..da8c75f24 100644
--- a/src/BufferSet.ts
+++ b/src/BufferSet.ts
@@ -61,24 +61,35 @@ export class BufferSet extends EventEmitter implements IBufferSet {
* Sets the normal Buffer of the BufferSet as its currently active Buffer
*/
public activateNormalBuffer(): void {
+ if (this._activeBuffer === this._normal) {
+ return;
+ }
// The alt buffer should always be cleared when we switch to the normal
// buffer. This frees up memory since the alt buffer should always be new
// when activated.
this._alt.clear();
-
this._activeBuffer = this._normal;
- this.emit('activate', this._normal);
+ this.emit('activate', {
+ activeBuffer: this._normal,
+ inactiveBuffer: this._alt
+ });
}
/**
* Sets the alt Buffer of the BufferSet as its currently active Buffer
*/
public activateAltBuffer(): void {
+ if (this._activeBuffer === this._alt) {
+ return;
+ }
// Since the alt buffer is always cleared when the normal buffer is
// activated, we want to fill it when switching to it.
this._alt.fillViewportRows();
this._activeBuffer = this._alt;
- this.emit('activate', this._alt);
+ this.emit('activate', {
+ activeBuffer: this._alt,
+ inactiveBuffer: this._normal
+ });
}
/**
diff --git a/src/InputHandler.ts b/src/InputHandler.ts
index 7d3a4d24b..96e34cc07 100644
--- a/src/InputHandler.ts
+++ b/src/InputHandler.ts
@@ -928,7 +928,6 @@ export class InputHandler implements IInputHandler {
case 47: // alt screen buffer
case 1047: // alt screen buffer
this._terminal.buffers.activateAltBuffer();
- this._terminal.selectionManager.setBuffer(this._terminal.buffer);
this._terminal.viewport.syncScrollArea();
this._terminal.showCursor();
break;
@@ -1100,7 +1099,6 @@ export class InputHandler implements IInputHandler {
// if (params[0] === 1049) {
// this.restoreCursor(params);
// }
- this._terminal.selectionManager.setBuffer(this._terminal.buffer);
this._terminal.refresh(0, this._terminal.rows - 1);
this._terminal.viewport.syncScrollArea();
this._terminal.showCursor();
diff --git a/src/Interfaces.ts b/src/Interfaces.ts
index 9ddc129c0..424f76925 100644
--- a/src/Interfaces.ts
+++ b/src/Interfaces.ts
@@ -144,6 +144,7 @@ export interface ITerminalOptions {
handler?: (data: string) => void;
letterSpacing?: number;
lineHeight?: number;
+ macOptionIsMeta?: boolean;
rows?: number;
screenKeys?: boolean;
scrollback?: number;
@@ -170,7 +171,7 @@ export interface IBuffer {
prevStop(x?: number): number;
}
-export interface IBufferSet {
+export interface IBufferSet extends IEventEmitter {
alt: IBuffer;
normal: IBuffer;
active: IBuffer;
@@ -199,7 +200,6 @@ export interface ISelectionManager {
disable(): void;
enable(): void;
- setBuffer(buffer: IBuffer): void;
setSelection(row: number, col: number, length: number): void;
}
diff --git a/src/Linkifier.ts b/src/Linkifier.ts
index 767719301..b5f30b562 100644
--- a/src/Linkifier.ts
+++ b/src/Linkifier.ts
@@ -82,12 +82,12 @@ export class Linkifier extends EventEmitter implements ILinkifier {
}
// Increase range to linkify
- if (!this._rowsToLinkify.start) {
+ if (this._rowsToLinkify.start === null) {
this._rowsToLinkify.start = start;
this._rowsToLinkify.end = end;
} else {
- this._rowsToLinkify.start = this._rowsToLinkify.start < start ? this._rowsToLinkify.start : start;
- this._rowsToLinkify.end = this._rowsToLinkify.end > end ? this._rowsToLinkify.end : end;
+ this._rowsToLinkify.start = Math.min(this._rowsToLinkify.start, start);
+ this._rowsToLinkify.end = Math.max(this._rowsToLinkify.end, end);
}
// Clear out any existing links on this row range
diff --git a/src/SelectionManager.test.ts b/src/SelectionManager.test.ts
index a10dc6692..97afcf2b7 100644
--- a/src/SelectionManager.test.ts
+++ b/src/SelectionManager.test.ts
@@ -21,10 +21,9 @@ class TestMockTerminal extends MockTerminal {
class TestSelectionManager extends SelectionManager {
constructor(
terminal: ITerminal,
- buffer: IBuffer,
charMeasure: CharMeasure
) {
- super(terminal, buffer, charMeasure);
+ super(terminal, charMeasure);
}
public get model(): SelectionModel { return this._model; }
@@ -59,7 +58,7 @@ describe('SelectionManager', () => {
terminal.buffers = new BufferSet(terminal);
terminal.buffer = terminal.buffers.active;
buffer = terminal.buffer;
- selectionManager = new TestSelectionManager(terminal, buffer, null);
+ selectionManager = new TestSelectionManager(terminal, null);
});
function stringToRow(text: string): LineData {
diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts
index cd6fc9961..608ca4124 100644
--- a/src/SelectionManager.ts
+++ b/src/SelectionManager.ts
@@ -8,7 +8,7 @@ import * as Browser from './utils/Browser';
import { CharMeasure } from './utils/CharMeasure';
import { CircularList } from './utils/CircularList';
import { EventEmitter } from './EventEmitter';
-import { ITerminal, ICircularList, ISelectionManager, IBuffer } from './Interfaces';
+import { ITerminal, ICircularList, ISelectionManager, IBuffer, IListenerType } from './Interfaces';
import { SelectionModel } from './SelectionModel';
import { LineData, CharData } from './Types';
import { CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX } from './Buffer';
@@ -95,10 +95,10 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
private _mouseMoveListener: EventListener;
private _mouseUpListener: EventListener;
+ private _trimListener: IListenerType;
constructor(
private _terminal: ITerminal,
- private _buffer: IBuffer,
private _charMeasure: CharMeasure
) {
super();
@@ -109,18 +109,24 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
this._activeSelectionMode = SelectionMode.NORMAL;
}
+ private get _buffer(): IBuffer {
+ return this._terminal.buffers.active;
+ }
+
/**
* Initializes listener variables.
*/
private _initListeners(): void {
this._mouseMoveListener = event => this._onMouseMove(event);
this._mouseUpListener = event => this._onMouseUp(event);
+ this._trimListener = (amount: number) => this._onTrim(amount);
- // Only adjust the selection on trim, shiftElements is rarely used (only in
- // reverseIndex) and delete in a splice is only ever used when the same
- // number of elements was just added. Given this is could actually be
- // beneficial to leave the selection as is for these cases.
- this._buffer.lines.on('trim', (amount: number) => this._onTrim(amount));
+ this.initBuffersListeners();
+ }
+
+ public initBuffersListeners(): void {
+ this._terminal.buffer.lines.on('trim', this._trimListener);
+ this._terminal.buffers.on('activate', e => this._onBufferActivate(e));
}
/**
@@ -139,16 +145,6 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
this._enabled = true;
}
- /**
- * Sets the active buffer, this should be called when the alt buffer is
- * switched in or out.
- * @param buffer The active buffer.
- */
- public setBuffer(buffer: IBuffer): void {
- this._buffer = buffer;
- this.clearSelection();
- }
-
public get selectionStart(): [number, number] { return this._model.finalSelectionStart; }
public get selectionEnd(): [number, number] { return this._model.finalSelectionEnd; }
@@ -547,6 +543,16 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
this._terminal.emit('selection');
}
+ private _onBufferActivate(e: {activeBuffer: IBuffer, inactiveBuffer: IBuffer}): void {
+ this.clearSelection();
+ // Only adjust the selection on trim, shiftElements is rarely used (only in
+ // reverseIndex) and delete in a splice is only ever used when the same
+ // number of elements was just added. Given this is could actually be
+ // beneficial to leave the selection as is for these cases.
+ e.inactiveBuffer.lines.off('trim', this._trimListener);
+ e.activeBuffer.lines.on('trim', this._trimListener);
+ }
+
/**
* Converts a viewport column to the character index on the buffer line, the
* latter takes into account wide characters.
diff --git a/src/Terminal.test.ts b/src/Terminal.test.ts
index 9cb0b75c1..946e9efb1 100644
--- a/src/Terminal.test.ts
+++ b/src/Terminal.test.ts
@@ -503,6 +503,9 @@ describe('term.js addons', () => {
it('should return \\x1b[5C for alt+right', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C
});
+ it('should return \\x1ba for alt+a', () => {
+ assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 65 }).key, '\x1ba');
+ });
});
describe('On macOS platforms', () => {
@@ -515,6 +518,19 @@ describe('term.js addons', () => {
it('should return \\x1bf for alt+right', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1bf'); // CSI 5 C
});
+ it('should return undefined for alt+a', () => {
+ assert.strictEqual(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 65 }).key, undefined);
+ });
+ });
+
+ describe('with macOptionIsMeta', () => {
+ beforeEach(() => {
+ term.browser.isMac = true;
+ term.setOption('macOptionIsMeta', true);
+ });
+ it('should return \\x1ba for alt+a', () => {
+ assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 65 }).key, '\x1ba');
+ });
});
it('should return \\x1b[5A for alt+up', () => {
@@ -597,6 +613,22 @@ describe('term.js addons', () => {
};
});
+ describe('with macOptionIsMeta', () => {
+ beforeEach(() => {
+ term.browser.isMac = true;
+ term.setOption('macOptionIsMeta', true);
+ });
+
+ it('should interfere with the alt key on keyDown', () => {
+ evKeyDown.altKey = true;
+ evKeyDown.keyCode = 81;
+ assert.equal(term.keyDown(evKeyDown), false);
+ evKeyDown.altKey = true;
+ evKeyDown.keyCode = 192;
+ assert.equal(term.keyDown(evKeyDown), false);
+ });
+ });
+
describe('On Mac OS', () => {
beforeEach(() => {
term.browser.isMac = true;
diff --git a/src/Terminal.ts b/src/Terminal.ts
index aae3a1015..044f5351f 100644
--- a/src/Terminal.ts
+++ b/src/Terminal.ts
@@ -81,6 +81,7 @@ const DEFAULT_OPTIONS: ITerminalOptions = {
scrollback: 1000,
screenKeys: false,
debug: false,
+ macOptionIsMeta: false,
cancelEvents: false,
disableStdin: false,
useFlowControl: false,
@@ -193,7 +194,6 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
public selectionManager: SelectionManager;
public linkifier: ILinkifier;
public buffers: BufferSet;
- public buffer: Buffer;
public viewport: IViewport;
private compositionHelper: ICompositionHelper;
public charMeasure: CharMeasure;
@@ -294,17 +294,19 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
// Create the terminal's buffers and set the current buffer
this.buffers = new BufferSet(this);
- this.buffer = this.buffers.active; // Convenience shortcut;
- this.buffers.on('activate', (buffer: Buffer) => {
- this.buffer = buffer;
- });
-
- // Ensure the selection manager has the correct buffer
if (this.selectionManager) {
- this.selectionManager.setBuffer(this.buffer);
+ this.selectionManager.clearSelection();
+ this.selectionManager.initBuffersListeners();
}
}
+ /**
+ * Convenience property to active buffer.
+ */
+ public get buffer(): Buffer {
+ return this.buffers.active;
+ }
+
/**
* back_color_erase feature for xterm.
*/
@@ -653,7 +655,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
this.charMeasure.on('charsizechanged', () => this.renderer.onResize(this.cols, this.rows, true));
this.renderer.on('resize', (dimensions) => this.viewport.syncScrollArea());
- this.selectionManager = new SelectionManager(this, this.buffer, this.charMeasure);
+ this.selectionManager = new SelectionManager(this, this.charMeasure);
this.element.addEventListener('mousedown', (e: MouseEvent) => this.selectionManager.onMouseDown(e));
this.selectionManager.on('refresh', data => this.renderer.onSelectionChanged(data.start, data.end));
this.selectionManager.on('newselection', text => {
@@ -1386,7 +1388,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
return this.cancel(ev, true);
}
- if (isThirdLevelShift(this.browser, ev)) {
+ if (this._isThirdLevelShift(this.browser, ev)) {
return true;
}
@@ -1407,6 +1409,19 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
return this.cancel(ev, true);
}
+ private _isThirdLevelShift(browser: IBrowser, ev: KeyboardEvent): boolean {
+ const thirdLevelKey =
+ (browser.isMac && !this.options.macOptionIsMeta && ev.altKey && !ev.ctrlKey && !ev.metaKey) ||
+ (browser.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey);
+
+ if (ev.type === 'keypress') {
+ return thirdLevelKey;
+ }
+
+ // Don't invoke for arrows, pageDown, home, backspace, etc. (on non-keypress events)
+ return thirdLevelKey && (!ev.keyCode || ev.keyCode > 47);
+ }
+
/**
* Returns an object that determines how a KeyboardEvent should be handled. The key of the
* returned value is the new key code to pass to the PTY.
@@ -1711,8 +1726,8 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
// ^] - Operating System Command (OSC)
result.key = String.fromCharCode(29);
}
- } else if (!this.browser.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) {
- // On Mac this is a third level shift. Use instead.
+ } else if ((!this.browser.isMac || this.options.macOptionIsMeta) && ev.altKey && !ev.ctrlKey && !ev.metaKey) {
+ // On macOS this is a third level shift when !macOptionIsMeta. Use instead.
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
result.key = C0.ESC + String.fromCharCode(ev.keyCode + 32);
} else if (ev.keyCode === 192) {
@@ -1778,7 +1793,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
}
if (!key || (
- (ev.altKey || ev.ctrlKey || ev.metaKey) && !isThirdLevelShift(this.browser, ev)
+ (ev.altKey || ev.ctrlKey || ev.metaKey) && !this._isThirdLevelShift(this.browser, ev)
)) {
return false;
}
@@ -2092,11 +2107,9 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
this.options.cols = this.cols;
const customKeyEventHandler = this.customKeyEventHandler;
const inputHandler = this.inputHandler;
- const buffers = this.buffers;
this.setup();
this.customKeyEventHandler = customKeyEventHandler;
this.inputHandler = inputHandler;
- this.buffers = buffers;
this.refresh(0, this.rows - 1);
this.viewport.syncScrollArea();
}
@@ -2172,19 +2185,6 @@ function off(el: any, type: string, handler: (event: Event) => any, capture: boo
el.removeEventListener(type, handler, capture);
}
-function isThirdLevelShift(browser: IBrowser, ev: KeyboardEvent): boolean {
- const thirdLevelKey =
- (browser.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) ||
- (browser.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey);
-
- if (ev.type === 'keypress') {
- return thirdLevelKey;
- }
-
- // Don't invoke for arrows, pageDown, home, backspace, etc. (on non-keypress events)
- return thirdLevelKey && (!ev.keyCode || ev.keyCode > 47);
-}
-
function wasMondifierKeyOnlyEvent(ev: KeyboardEvent): boolean {
return ev.keyCode === 16 || // Shift
ev.keyCode === 17 || // Ctrl
diff --git a/src/addons/attach/Intefaces.ts b/src/addons/attach/Intefaces.ts
new file mode 100644
index 000000000..ab809af9c
--- /dev/null
+++ b/src/addons/attach/Intefaces.ts
@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) 2018 The xterm.js authors. All rights reserved.
+ * @license MIT
+ *
+ * Implements the attach method, that attaches the terminal to a WebSocket stream.
+ */
+
+import { Terminal } from 'xterm';
+
+export interface IAttachAddonTerminal extends Terminal {
+ __socket?: WebSocket;
+ __attachSocketBuffer?: string;
+
+ __getMessage?(ev: MessageEvent): void;
+ __flushBuffer?(): void;
+ __pushToBuffer?(data: string): void;
+ __sendData?(data: string): void;
+}
diff --git a/src/addons/attach/attach.test.ts b/src/addons/attach/attach.test.ts
index a13885bbc..018cfb31c 100644
--- a/src/addons/attach/attach.test.ts
+++ b/src/addons/attach/attach.test.ts
@@ -12,7 +12,7 @@ class MockTerminal {}
describe('attach addon', () => {
describe('apply', () => {
it('should do register the `attach` and `detach` methods', () => {
- attach.apply(MockTerminal);
+ attach.apply(MockTerminal);
assert.equal(typeof (MockTerminal).prototype.attach, 'function');
assert.equal(typeof (MockTerminal).prototype.detach, 'function');
});
diff --git a/src/addons/attach/attach.ts b/src/addons/attach/attach.ts
index ba9386958..d963a658f 100644
--- a/src/addons/attach/attach.ts
+++ b/src/addons/attach/attach.ts
@@ -5,38 +5,42 @@
* Implements the attach method, that attaches the terminal to a WebSocket stream.
*/
+///
+
+import { Terminal } from 'xterm';
+import { IAttachAddonTerminal } from './Intefaces';
+
/**
* Attaches the given terminal to the given socket.
*
- * @param {Terminal} term - The terminal to be attached to the given socket.
- * @param {WebSocket} socket - The socket to attach the current terminal.
- * @param {boolean} bidirectional - Whether the terminal should send data
- * to the socket as well.
- * @param {boolean} buffered - Whether the rendering of incoming data
- * should happen instantly or at a maximum
- * frequency of 1 rendering per 10ms.
+ * @param term The terminal to be attached to the given socket.
+ * @param socket The socket to attach the current terminal.
+ * @param bidirectional Whether the terminal should send data to the socket as well.
+ * @param buffered Whether the rendering of incoming data should happen instantly or at a maximum
+ * frequency of 1 rendering per 10ms.
*/
-export function attach(term: any, socket: WebSocket, bidirectional: boolean, buffered: boolean): void {
+export function attach(term: Terminal, socket: WebSocket, bidirectional: boolean, buffered: boolean): void {
+ const addonTerminal = term;
bidirectional = (typeof bidirectional === 'undefined') ? true : bidirectional;
- term.socket = socket;
+ addonTerminal.__socket = socket;
- term._flushBuffer = () => {
- term.write(term._attachSocketBuffer);
- term._attachSocketBuffer = null;
+ addonTerminal.__flushBuffer = () => {
+ addonTerminal.write(addonTerminal.__attachSocketBuffer);
+ addonTerminal.__attachSocketBuffer = null;
};
- term._pushToBuffer = (data: string) => {
- if (term._attachSocketBuffer) {
- term._attachSocketBuffer += data;
+ addonTerminal.__pushToBuffer = (data: string) => {
+ if (addonTerminal.__attachSocketBuffer) {
+ addonTerminal.__attachSocketBuffer += data;
} else {
- term._attachSocketBuffer = data;
- setTimeout(term._flushBuffer, 10);
+ addonTerminal.__attachSocketBuffer = data;
+ setTimeout(addonTerminal.__flushBuffer, 10);
}
};
let myTextDecoder;
- term._getMessage = function(ev: MessageEvent): void {
+ addonTerminal.__getMessage = function(ev: MessageEvent): void {
let str;
if (typeof ev.data === 'object') {
if (ev.data instanceof ArrayBuffer) {
@@ -51,71 +55,68 @@ export function attach(term: any, socket: WebSocket, bidirectional: boolean, buf
}
if (buffered) {
- term._pushToBuffer(str || ev.data);
+ addonTerminal.__pushToBuffer(str || ev.data);
} else {
- term.write(str || ev.data);
+ addonTerminal.write(str || ev.data);
}
};
- term._sendData = (data: string) => {
+ addonTerminal.__sendData = (data: string) => {
if (socket.readyState !== 1) {
return;
}
socket.send(data);
};
- socket.addEventListener('message', term._getMessage);
+ socket.addEventListener('message', addonTerminal.__getMessage);
if (bidirectional) {
- term.on('data', term._sendData);
+ addonTerminal.on('data', addonTerminal.__sendData);
}
- socket.addEventListener('close', term.detach.bind(term, socket));
- socket.addEventListener('error', term.detach.bind(term, socket));
+ socket.addEventListener('close', () => detach(addonTerminal, socket));
+ socket.addEventListener('error', () => detach(addonTerminal, socket));
}
/**
* Detaches the given terminal from the given socket
*
- * @param {Terminal} term - The terminal to be detached from the given socket.
- * @param {WebSocket} socket - The socket from which to detach the current
- * terminal.
+ * @param term The terminal to be detached from the given socket.
+ * @param socket The socket from which to detach the current terminal.
*/
-export function detach(term: any, socket: WebSocket): void {
- term.off('data', term._sendData);
+export function detach(term: Terminal, socket: WebSocket): void {
+ const addonTerminal = term;
+ addonTerminal.off('data', addonTerminal.__sendData);
- socket = (typeof socket === 'undefined') ? term.socket : socket;
+ socket = (typeof socket === 'undefined') ? addonTerminal.__socket : socket;
if (socket) {
- socket.removeEventListener('message', term._getMessage);
+ socket.removeEventListener('message', addonTerminal.__getMessage);
}
- delete term.socket;
+ delete addonTerminal.__socket;
}
-export function apply(terminalConstructor: any): void {
+export function apply(terminalConstructor: typeof Terminal): void {
/**
* Attaches the current terminal to the given socket
*
- * @param {WebSocket} socket - The socket to attach the current terminal.
- * @param {boolean} bidirectional - Whether the terminal should send data
- * to the socket as well.
- * @param {boolean} buffered - Whether the rendering of incoming data
- * should happen instantly or at a maximum
- * frequency of 1 rendering per 10ms.
+ * @param socket The socket to attach the current terminal.
+ * @param bidirectional Whether the terminal should send data to the socket as well.
+ * @param buffered Whether the rendering of incoming data should happen instantly or at a maximum
+ * frequency of 1 rendering per 10ms.
*/
- terminalConstructor.prototype.attach = function (socket: WebSocket, bidirectional: boolean, buffered: boolean): void {
+ (terminalConstructor.prototype).attach = function (socket: WebSocket, bidirectional: boolean, buffered: boolean): void {
attach(this, socket, bidirectional, buffered);
};
/**
* Detaches the current terminal from the given socket.
*
- * @param {WebSocket} socket - The socket from which to detach the current
- * terminal.
+ * @param socket The socket from which to detach the current terminal.
*/
- terminalConstructor.prototype.detach = function (socket: WebSocket): void {
+ (terminalConstructor.prototype).detach = function (socket: WebSocket): void {
detach(this, socket);
};
}
diff --git a/src/addons/fit/fit.test.ts b/src/addons/fit/fit.test.ts
index 0dc179630..9a6d89fd0 100644
--- a/src/addons/fit/fit.test.ts
+++ b/src/addons/fit/fit.test.ts
@@ -12,7 +12,7 @@ class MockTerminal {}
describe('fit addon', () => {
describe('apply', () => {
it('should do register the `proposeGeometry` and `fit` methods', () => {
- fit.apply(MockTerminal);
+ fit.apply(MockTerminal);
assert.equal(typeof (MockTerminal).prototype.proposeGeometry, 'function');
assert.equal(typeof (MockTerminal).prototype.fit, 'function');
});
diff --git a/src/addons/fit/fit.ts b/src/addons/fit/fit.ts
index 631110941..75e854d97 100644
--- a/src/addons/fit/fit.ts
+++ b/src/addons/fit/fit.ts
@@ -13,12 +13,16 @@
* row and truncate its width with the current number of columns).
*/
+///
+
+import { Terminal } from 'xterm';
+
export interface IGeometry {
rows: number;
cols: number;
}
-export function proposeGeometry(term: any): IGeometry {
+export function proposeGeometry(term: Terminal): IGeometry {
if (!term.element.parentElement) {
return null;
}
@@ -31,30 +35,30 @@ export function proposeGeometry(term: any): IGeometry {
const availableHeight = parentElementHeight - elementPaddingVer;
const availableWidth = parentElementWidth - elementPaddingHor;
const geometry = {
- cols: Math.floor(availableWidth / term.renderer.dimensions.actualCellWidth),
- rows: Math.floor(availableHeight / term.renderer.dimensions.actualCellHeight)
+ cols: Math.floor(availableWidth / (term).renderer.dimensions.actualCellWidth),
+ rows: Math.floor(availableHeight / (term).renderer.dimensions.actualCellHeight)
};
return geometry;
}
-export function fit(term: any): void {
+export function fit(term: Terminal): void {
const geometry = proposeGeometry(term);
if (geometry) {
// Force a full render
if (term.rows !== geometry.rows || term.cols !== geometry.cols) {
- term.renderer.clear();
+ (term).renderer.clear();
term.resize(geometry.cols, geometry.rows);
}
}
}
-export function apply(terminalConstructor: any): void {
- terminalConstructor.prototype.proposeGeometry = function (): IGeometry {
+export function apply(terminalConstructor: typeof Terminal): void {
+ (terminalConstructor.prototype).proposeGeometry = function (): IGeometry {
return proposeGeometry(this);
};
- terminalConstructor.prototype.fit = function (): void {
+ (terminalConstructor.prototype).fit = function (): void {
fit(this);
};
}
diff --git a/src/addons/fullscreen/fullscreen.test.ts b/src/addons/fullscreen/fullscreen.test.ts
index 9326ac4e7..bb98bd30d 100644
--- a/src/addons/fullscreen/fullscreen.test.ts
+++ b/src/addons/fullscreen/fullscreen.test.ts
@@ -12,7 +12,7 @@ class MockTerminal {}
describe('fullscreen addon', () => {
describe('apply', () => {
it('should do register the `toggleFullscreen` method', () => {
- fullscreen.apply(MockTerminal);
+ fullscreen.apply(MockTerminal);
assert.equal(typeof (MockTerminal).prototype.toggleFullScreen, 'function');
});
});
diff --git a/src/addons/fullscreen/fullscreen.ts b/src/addons/fullscreen/fullscreen.ts
index 2e5b72e1f..474406677 100644
--- a/src/addons/fullscreen/fullscreen.ts
+++ b/src/addons/fullscreen/fullscreen.ts
@@ -3,13 +3,17 @@
* @license MIT
*/
+///
+
+import { Terminal } from 'xterm';
+
/**
* Toggle the given terminal's fullscreen mode.
- * @param {Terminal} term - The terminal to toggle full screen mode
- * @param {boolean} fullscreen - Toggle fullscreen on (true) or off (false)
+ * @param term The terminal to toggle full screen mode
+ * @param fullscreen Toggle fullscreen on (true) or off (false)
*/
-export function toggleFullScreen(term: any, fullscreen: boolean): void {
- let fn;
+export function toggleFullScreen(term: Terminal, fullscreen: boolean): void {
+ let fn: string;
if (typeof fullscreen === 'undefined') {
fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add';
@@ -22,8 +26,8 @@ export function toggleFullScreen(term: any, fullscreen: boolean): void {
term.element.classList[fn]('fullscreen');
}
-export function apply(terminalConstructor: any): void {
- terminalConstructor.prototype.toggleFullScreen = function (fullscreen: boolean): void {
+export function apply(terminalConstructor: typeof Terminal): void {
+ (terminalConstructor.prototype).toggleFullScreen = function (fullscreen: boolean): void {
toggleFullScreen(this, fullscreen);
};
}
diff --git a/src/addons/search/Interfaces.ts b/src/addons/search/Interfaces.ts
new file mode 100644
index 000000000..6faa03e2e
--- /dev/null
+++ b/src/addons/search/Interfaces.ts
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2018 The xterm.js authors. All rights reserved.
+ * @license MIT
+ */
+
+import { Terminal } from 'xterm';
+
+export interface ISearchAddonTerminal extends Terminal {
+ __searchHelper?: ISearchHelper;
+
+ // TODO: Reuse ITerminal from core
+ buffer: any;
+ selectionManager: any;
+}
+
+export interface ISearchHelper {
+ findNext(term: string): boolean;
+ findPrevious(term: string): boolean;
+}
diff --git a/src/addons/search/SearchHelper.ts b/src/addons/search/SearchHelper.ts
index 5735dd48e..dd941682a 100644
--- a/src/addons/search/SearchHelper.ts
+++ b/src/addons/search/SearchHelper.ts
@@ -3,8 +3,7 @@
* @license MIT
*/
-// import { ITerminal } from '../../Interfaces';
-// import { translateBufferLineToString } from '../../utils/BufferLine';
+import { ISearchHelper, ISearchAddonTerminal } from './Interfaces';
interface ISearchResult {
term: string;
@@ -15,8 +14,8 @@ interface ISearchResult {
/**
* A class that knows how to search the terminal and how to display the results.
*/
-export class SearchHelper {
- constructor(private _terminal: any) {
+export class SearchHelper implements ISearchHelper {
+ constructor(private _terminal: ISearchAddonTerminal) {
// TODO: Search for multiple instances on 1 line
// TODO: Don't use the actual selection, instead use a "find selection" so multiple instances can be highlighted
// TODO: Highlight other instances in the viewport
@@ -134,7 +133,7 @@ export class SearchHelper {
return false;
}
this._terminal.selectionManager.setSelection(result.col, result.row, result.term.length);
- this._terminal.scrollLines(result.row - this._terminal.buffer.ydisp, false);
+ this._terminal.scrollLines(result.row - this._terminal.buffer.ydisp);
return true;
}
}
diff --git a/src/addons/search/search.ts b/src/addons/search/search.ts
index 473c78fcf..5c0b2b96d 100644
--- a/src/addons/search/search.ts
+++ b/src/addons/search/search.ts
@@ -3,8 +3,11 @@
* @license MIT
*/
-import { SearchHelper } from './SearchHelper';
+///
+import { SearchHelper } from './SearchHelper';
+import { Terminal } from 'xterm';
+import { ISearchAddonTerminal } from './Interfaces';
/**
* Find the next instance of the term, then scroll to and select it. If it
@@ -12,11 +15,12 @@ import { SearchHelper } from './SearchHelper';
* @param term Tne search term.
* @return Whether a result was found.
*/
-export function findNext(terminal: any, term: string): boolean {
- if (!terminal._searchHelper) {
- terminal.searchHelper = new SearchHelper(terminal);
+export function findNext(terminal: Terminal, term: string): boolean {
+ const addonTerminal = terminal;
+ if (!addonTerminal.__searchHelper) {
+ addonTerminal.__searchHelper = new SearchHelper(addonTerminal);
}
- return (terminal.searchHelper).findNext(term);
+ return addonTerminal.__searchHelper.findNext(term);
}
/**
@@ -25,19 +29,20 @@ export function findNext(terminal: any, term: string): boolean {
* @param term Tne search term.
* @return Whether a result was found.
*/
-export function findPrevious(terminal: any, term: string): boolean {
- if (!terminal._searchHelper) {
- terminal.searchHelper = new SearchHelper(terminal);
+export function findPrevious(terminal: Terminal, term: string): boolean {
+ const addonTerminal = terminal;
+ if (!addonTerminal.__searchHelper) {
+ addonTerminal.__searchHelper = new SearchHelper(addonTerminal);
}
- return (terminal.searchHelper).findPrevious(term);
+ return addonTerminal.__searchHelper.findPrevious(term);
}
-export function apply(terminalConstructor: any): void {
- terminalConstructor.prototype.findNext = function(term: any): boolean {
+export function apply(terminalConstructor: typeof Terminal): void {
+ (terminalConstructor.prototype).findNext = function(term: string): boolean {
return findNext(this, term);
};
- terminalConstructor.prototype.findPrevious = function(term: any): boolean {
+ (terminalConstructor.prototype).findPrevious = function(term: string): boolean {
return findPrevious(this, term);
};
}
diff --git a/src/addons/terminado/Intefaces.ts b/src/addons/terminado/Intefaces.ts
new file mode 100644
index 000000000..8f17b0cc7
--- /dev/null
+++ b/src/addons/terminado/Intefaces.ts
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2018 The xterm.js authors. All rights reserved.
+ * @license MIT
+ *
+ * Implements the attach method, that attaches the terminal to a WebSocket stream.
+ */
+
+import { Terminal } from 'xterm';
+
+export interface ITerminadoAddonTerminal extends Terminal {
+ __socket?: WebSocket;
+ __attachSocketBuffer?: string;
+
+ __getMessage?(ev: MessageEvent): void;
+ __flushBuffer?(): void;
+ __pushToBuffer?(data: string): void;
+ __sendData?(data: string): void;
+ __setSize?(size: {rows: number, cols: number}): void;
+}
diff --git a/src/addons/terminado/terminado.test.ts b/src/addons/terminado/terminado.test.ts
index e258bd7cb..2e4a53c5a 100644
--- a/src/addons/terminado/terminado.test.ts
+++ b/src/addons/terminado/terminado.test.ts
@@ -12,7 +12,7 @@ class MockTerminal {}
describe('terminado addon', () => {
describe('apply', () => {
it('should do register the `terminadoAttach` and `terminadoDetach` methods', () => {
- terminado.apply(MockTerminal);
+ terminado.apply(MockTerminal);
assert.equal(typeof (MockTerminal).prototype.terminadoAttach, 'function');
assert.equal(typeof (MockTerminal).prototype.terminadoDetach, 'function');
});
diff --git a/src/addons/terminado/terminado.ts b/src/addons/terminado/terminado.ts
index e703198fe..d5cf72d1b 100644
--- a/src/addons/terminado/terminado.ts
+++ b/src/addons/terminado/terminado.ts
@@ -6,106 +6,107 @@
* WebSocket stream.
*/
+///
+
+import { Terminal } from 'xterm';
+import { ITerminadoAddonTerminal } from './Intefaces';
+
/**
* Attaches the given terminal to the given socket.
*
- * @param {Terminal} term - The terminal to be attached to the given socket.
- * @param {WebSocket} socket - The socket to attach the current terminal.
- * @param {boolean} bidirectional - Whether the terminal should send data
- * to the socket as well.
- * @param {boolean} buffered - Whether the rendering of incoming data
- * should happen instantly or at a maximum
- * frequency of 1 rendering per 10ms.
+ * @param term The terminal to be attached to the given socket.
+ * @param socket The socket to attach the current terminal.
+ * @param bidirectional Whether the terminal should send data to the socket as well.
+ * @param buffered Whether the rendering of incoming data should happen instantly or at a maximum
+ * frequency of 1 rendering per 10ms.
*/
-export function terminadoAttach(term: any, socket: WebSocket, bidirectional: boolean, buffered: boolean): void {
+export function terminadoAttach(term: Terminal, socket: WebSocket, bidirectional: boolean, buffered: boolean): void {
+ const addonTerminal = term;
bidirectional = (typeof bidirectional === 'undefined') ? true : bidirectional;
- term.socket = socket;
+ addonTerminal.__socket = socket;
- term._flushBuffer = () => {
- term.write(term._attachSocketBuffer);
- term._attachSocketBuffer = null;
+ addonTerminal.__flushBuffer = () => {
+ addonTerminal.write(addonTerminal.__attachSocketBuffer);
+ addonTerminal.__attachSocketBuffer = null;
};
- term._pushToBuffer = (data) => {
- if (term._attachSocketBuffer) {
- term._attachSocketBuffer += data;
+ addonTerminal.__pushToBuffer = (data: string) => {
+ if (addonTerminal.__attachSocketBuffer) {
+ addonTerminal.__attachSocketBuffer += data;
} else {
- term._attachSocketBuffer = data;
- setTimeout(term._flushBuffer, 10);
+ addonTerminal.__attachSocketBuffer = data;
+ setTimeout(addonTerminal.__flushBuffer, 10);
}
};
- term._getMessage = (ev: MessageEvent) => {
+ addonTerminal.__getMessage = (ev: MessageEvent) => {
const data = JSON.parse(ev.data);
if (data[0] === 'stdout') {
if (buffered) {
- term._pushToBuffer(data[1]);
+ addonTerminal.__pushToBuffer(data[1]);
} else {
- term.write(data[1]);
+ addonTerminal.write(data[1]);
}
}
};
- term._sendData = (data: string) => {
+ addonTerminal.__sendData = (data: string) => {
socket.send(JSON.stringify(['stdin', data]));
};
- term._setSize = (size: {rows: number, cols: number}) => {
+ addonTerminal.__setSize = (size: {rows: number, cols: number}) => {
socket.send(JSON.stringify(['set_size', size.rows, size.cols]));
};
- socket.addEventListener('message', term._getMessage);
+ socket.addEventListener('message', addonTerminal.__getMessage);
if (bidirectional) {
- term.on('data', term._sendData);
+ addonTerminal.on('data', addonTerminal.__sendData);
}
- term.on('resize', term._setSize);
+ addonTerminal.on('resize', addonTerminal.__setSize);
- socket.addEventListener('close', term.terminadoDetach.bind(term, socket));
- socket.addEventListener('error', term.terminadoDetach.bind(term, socket));
+ socket.addEventListener('close', () => terminadoDetach(addonTerminal, socket));
+ socket.addEventListener('error', () => terminadoDetach(addonTerminal, socket));
}
/**
* Detaches the given terminal from the given socket
*
- * @param {Xterm} term - The terminal to be detached from the given socket.
- * @param {WebSocket} socket - The socket from which to detach the current
- * terminal.
+ * @param term The terminal to be detached from the given socket.
+ * @param socket The socket from which to detach the current terminal.
*/
-export function terminadoDetach(term: any, socket: WebSocket): void {
- term.off('data', term._sendData);
+export function terminadoDetach(term: Terminal, socket: WebSocket): void {
+ const addonTerminal = term;
+ addonTerminal.off('data', addonTerminal.__sendData);
- socket = (typeof socket === 'undefined') ? term.socket : socket;
+ socket = (typeof socket === 'undefined') ? addonTerminal.__socket : socket;
if (socket) {
- socket.removeEventListener('message', term._getMessage);
+ socket.removeEventListener('message', addonTerminal.__getMessage);
}
- delete term.socket;
+ delete addonTerminal.__socket;
}
-export function apply(terminalConstructor: any): void {
+export function apply(terminalConstructor: typeof Terminal): void {
/**
* Attaches the current terminal to the given socket
*
- * @param {WebSocket} socket - The socket to attach the current terminal.
- * @param {boolean} bidirectional - Whether the terminal should send data
- * to the socket as well.
- * @param {boolean} buffered - Whether the rendering of incoming data
- * should happen instantly or at a maximum
- * frequency of 1 rendering per 10ms.
+ * @param socket - The socket to attach the current terminal.
+ * @param bidirectional - Whether the terminal should send data to the socket as well.
+ * @param buffered - Whether the rendering of incoming data should happen instantly or at a
+ * maximum frequency of 1 rendering per 10ms.
*/
- terminalConstructor.prototype.terminadoAttach = function(socket: WebSocket, bidirectional: boolean, buffered: boolean): void {
+ (terminalConstructor.prototype).terminadoAttach = function (socket: WebSocket, bidirectional: boolean, buffered: boolean): void {
return terminadoAttach(this, socket, bidirectional, buffered);
};
/**
* Detaches the current terminal from the given socket.
*
- * @param {WebSocket} socket - The socket from which to detach the current
- * terminal.
+ * @param socket The socket from which to detach the current terminal.
*/
- terminalConstructor.prototype.terminadoDetach = function(socket: WebSocket): void {
+ (terminalConstructor.prototype).terminadoDetach = function (socket: WebSocket): void {
return terminadoDetach(this, socket);
};
}
diff --git a/src/addons/winptyCompat/Interfaces.ts b/src/addons/winptyCompat/Interfaces.ts
new file mode 100644
index 000000000..8e02c64b5
--- /dev/null
+++ b/src/addons/winptyCompat/Interfaces.ts
@@ -0,0 +1,10 @@
+/**
+ * Copyright (c) 2018 The xterm.js authors. All rights reserved.
+ * @license MIT
+ */
+
+import { Terminal } from 'xterm';
+
+export interface IWinptyCompatAddonTerminal extends Terminal {
+ buffer: any;
+}
diff --git a/src/addons/winptyCompat/winptyCompat.test.ts b/src/addons/winptyCompat/winptyCompat.test.ts
index 73761fc90..0c9269edc 100644
--- a/src/addons/winptyCompat/winptyCompat.test.ts
+++ b/src/addons/winptyCompat/winptyCompat.test.ts
@@ -12,7 +12,7 @@ class MockTerminal {}
describe('winptyCompat addon', () => {
describe('apply', () => {
it('should do register the `winptyCompatInit` method', () => {
- winptyCompat.apply(MockTerminal);
+ winptyCompat.apply(MockTerminal);
assert.equal(typeof (MockTerminal).prototype.winptyCompatInit, 'function');
});
});
diff --git a/src/addons/winptyCompat/winptyCompat.ts b/src/addons/winptyCompat/winptyCompat.ts
index b594355bc..61524e125 100644
--- a/src/addons/winptyCompat/winptyCompat.ts
+++ b/src/addons/winptyCompat/winptyCompat.ts
@@ -3,36 +3,43 @@
* @license MIT
*/
-export function winptyCompatInit(terminal: any): void {
- // Don't do anything when the platform is not Windows
- const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0;
- if (!isWindows) {
- return;
+///
+
+import { Terminal } from 'xterm';
+import { IWinptyCompatAddonTerminal } from './Interfaces';
+
+export function winptyCompatInit(terminal: Terminal): void {
+ const addonTerminal = terminal;
+
+ // Don't do anything when the platform is not Windows
+ const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0;
+ if (!isWindows) {
+ return;
+ }
+
+ // Winpty does not support wraparound mode which means that lines will never
+ // be marked as wrapped. This causes issues for things like copying a line
+ // retaining the wrapped new line characters or if consumers are listening
+ // in on the data stream.
+ //
+ // The workaround for this is to listen to every incoming line feed and mark
+ // the line as wrapped if the last character in the previous line is not a
+ // space. This is certainly not without its problems, but generally on
+ // Windows when text reaches the end of the terminal it's likely going to be
+ // wrapped.
+ addonTerminal.on('linefeed', () => {
+ const line = addonTerminal.buffer.lines.get(addonTerminal.buffer.ybase + addonTerminal.buffer.y - 1);
+ const lastChar = line[addonTerminal.cols - 1];
+
+ if (lastChar[3] !== 32 /* ' ' */) {
+ const nextLine = addonTerminal.buffer.lines.get(addonTerminal.buffer.ybase + addonTerminal.buffer.y);
+ (nextLine).isWrapped = true;
}
-
- // Winpty does not support wraparound mode which means that lines will never
- // be marked as wrapped. This causes issues for things like copying a line
- // retaining the wrapped new line characters or if consumers are listening
- // in on the data stream.
- //
- // The workaround for this is to listen to every incoming line feed and mark
- // the line as wrapped if the last character in the previous line is not a
- // space. This is certainly not without its problems, but generally on
- // Windows when text reaches the end of the terminal it's likely going to be
- // wrapped.
- terminal.on('linefeed', () => {
- const line = terminal.buffer.lines.get(terminal.buffer.ybase + terminal.buffer.y - 1);
- const lastChar = line[terminal.cols - 1];
-
- if (lastChar[3] !== 32 /* ' ' */) {
- const nextLine = terminal.buffer.lines.get(terminal.buffer.ybase + terminal.buffer.y);
- (nextLine).isWrapped = true;
- }
- });
+ });
}
-export function apply(terminalConstructor: any): void {
- terminalConstructor.prototype.winptyCompatInit = function(): void {
+export function apply(terminalConstructor: typeof Terminal): void {
+ (terminalConstructor.prototype).winptyCompatInit = function (): void {
winptyCompatInit(this);
};
}
diff --git a/src/addons/zmodem/zmodem.test.ts b/src/addons/zmodem/zmodem.test.ts
index 7646b7ccb..682e62c80 100644
--- a/src/addons/zmodem/zmodem.test.ts
+++ b/src/addons/zmodem/zmodem.test.ts
@@ -12,7 +12,7 @@ class MockTerminal {}
describe('zmodem addon', () => {
describe('apply', () => {
it('should do register the `zmodemAttach` method and `zmodemBrowser` attribute', () => {
- zmodem.apply(MockTerminal);
+ zmodem.apply(MockTerminal);
assert.equal(typeof (MockTerminal).prototype.zmodemAttach, 'function');
assert.equal(typeof (MockTerminal).prototype.zmodemBrowser, 'object');
});
diff --git a/src/addons/zmodem/zmodem.ts b/src/addons/zmodem/zmodem.ts
index 4713f111c..e8a7824d4 100644
--- a/src/addons/zmodem/zmodem.ts
+++ b/src/addons/zmodem/zmodem.ts
@@ -1,3 +1,12 @@
+/**
+ * Copyright (c) 2017 The xterm.js authors. All rights reserved.
+ * @license MIT
+ */
+
+///
+
+import { Terminal } from 'xterm';
+
/**
*
* Allow xterm.js to handle ZMODEM uploads and downloads.
@@ -33,7 +42,7 @@ export interface IZModemOptions {
noTerminalWriteOutsideSession?: boolean;
}
-export function zmodemAttach(term: any, ws: WebSocket, opts: IZModemOptions = {}): void {
+export function zmodemAttach(term: Terminal, ws: WebSocket, opts: IZModemOptions = {}): void {
const senderFunc = (octets: ArrayLike) => ws.send(new Uint8Array(octets));
let zsentry;
@@ -51,8 +60,8 @@ export function zmodemAttach(term: any, ws: WebSocket, opts: IZModemOptions = {}
}
},
sender: senderFunc,
- on_retract: () => term.emit('zmodemRetract'),
- on_detect: (detection: any) => term.emit('zmodemDetect', detection)
+ on_retract: () => (term).emit('zmodemRetract'),
+ on_detect: (detection: any) => (term).emit('zmodemDetect', detection)
});
function handleWSMessage(evt: MessageEvent): void {
@@ -75,9 +84,9 @@ export function zmodemAttach(term: any, ws: WebSocket, opts: IZModemOptions = {}
ws.addEventListener('message', handleWSMessage);
}
-export function apply(terminalConstructor: any): void {
+export function apply(terminalConstructor: typeof Terminal): void {
zmodem = (typeof window === 'object') ? (window).ZModem : {Browser: null}; // Nullify browser for tests
- terminalConstructor.prototype.zmodemAttach = zmodemAttach.bind(this, this);
- terminalConstructor.prototype.zmodemBrowser = zmodem.Browser;
+ (terminalConstructor.prototype).zmodemAttach = zmodemAttach.bind(this, this);
+ (terminalConstructor.prototype).zmodemBrowser = zmodem.Browser;
}
diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts
index 3efa78890..7c8612cf6 100644
--- a/typings/xterm.d.ts
+++ b/typings/xterm.d.ts
@@ -460,7 +460,7 @@ declare module 'xterm' {
* @param key The option key.
* @param value The option value.
*/
- setOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell', value: boolean): void;
+ setOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell', value: boolean): void;
/**
* Sets an option on the terminal.
* @param key The option key.