return this.on(type, on);
}
- public emit(type): void {
+ public emit(type: string, ...args: any[]): void {
if (!this._events[type]) {
return;
}
-
- let args = Array.prototype.slice.call(arguments, 1);
let obj = this._events[type];
-
for (let i = 0; i < obj.length; i++) {
obj[i].apply(this, args);
}
case ParserState.DCS:
if (ch === C0.ESC || ch === C0.BEL) {
if (ch === C0.ESC) this._position++;
+ let pt;
+ let valid;
switch (this._terminal.prefix) {
// User-Defined Keys (DECUDK).
// Request Status String (DECRQSS).
// test: echo -e '\eP$q"p\e\\'
case '$q':
- let pt = this._terminal.currentParam
- , valid = false;
+ pt = this._terminal.currentParam;
+ valid = false;
switch (pt) {
// DECSCA
// This can cause a small glitch in vim.
// test: echo -ne '\eP+q6b64\e\\'
case '+q':
- // TODO: Don't declare pt twice
- /*let*/ pt = this._terminal.currentParam
- , valid = false;
+ pt = this._terminal.currentParam;
+ valid = false;
this._terminal.send(C0.ESC + 'P' + +valid + '+r' + pt + C0.ESC + '\\');
break;
--- /dev/null
+/**
+ * @license MIT
+ */
+
+import { CharMeasure } from './utils/CharMeasure';
+import { CircularList } from './utils/CircularList';
+import * as Mouse from './utils/Mouse';
+
+export class SelectionManager {
+ private _selectionStart: [number, number];
+ private _selectionEnd: [number, number];
+
+ private _buffer: CircularList<any>;
+ private _rowContainer: HTMLElement;
+ private _charMeasure: CharMeasure;
+
+ private _mouseMoveListener: EventListener;
+
+ constructor(buffer: CircularList<any>, rowContainer: HTMLElement, charMeasure: CharMeasure) {
+ this._rowContainer = rowContainer;
+ this._buffer = buffer;
+ this._charMeasure = charMeasure;
+ this._attachListeners();
+ }
+
+ private _attachListeners() {
+ this._mouseMoveListener = event => this._onMouseMove(<MouseEvent>event);
+
+ this._buffer.on('trim', amount => this._onTrim(amount));
+ this._rowContainer.addEventListener('mousedown', event => this._onMouseDown(event));
+ this._rowContainer.addEventListener('mouseup', event => this._onMouseUp(event));
+ }
+
+ public get selectionText(): string {
+ if (!this._selectionStart || !this._selectionEnd) {
+ return null;
+ }
+ return '';
+ }
+
+ private _onTrim(amount: number) {
+ console.log('trimmed: ' + amount);
+ }
+
+ private _onMouseDown(event: MouseEvent) {
+ this._selectionStart = Mouse.getCoords(event, this._rowContainer, this._charMeasure);
+ if (this._selectionStart) {
+ this._rowContainer.addEventListener('mousemove', this._mouseMoveListener);
+ }
+ }
+
+ private _onMouseMove(event: MouseEvent) {
+ this._selectionEnd = Mouse.getCoords(event, this._rowContainer, this._charMeasure);
+ }
+
+ private _onMouseUp(event: MouseEvent) {
+ console.log('mouseup');
+ console.log('start', this._selectionStart);
+ console.log('end', this._selectionEnd);
+ if (!this._selectionStart) {
+ return;
+ }
+ this._rowContainer.removeEventListener('mousemove', this._mouseMoveListener);
+ }
+}
* @module xterm/utils/CircularList
* @license MIT
*/
-export class CircularList<T> {
+import { EventEmitter } from '../EventEmitter';
+
+export class CircularList<T> extends EventEmitter {
private _array: T[];
private _startIndex: number;
private _length: number;
constructor(maxLength: number) {
+ super();
this._array = new Array<T>(maxLength);
this._startIndex = 0;
this._length = 0;
if (this._startIndex === this.maxLength) {
this._startIndex = 0;
}
+ this.emit('trim', 1);
} else {
this._length++;
}
}
if (this._length + items.length > this.maxLength) {
- this._startIndex += (this._length + items.length) - this.maxLength;
+ const countToTrim = (this._length + items.length) - this.maxLength;
+ this._startIndex += countToTrim;
this._length = this.maxLength;
+ this.emit('trim', countToTrim);
} else {
this._length += items.length;
}
}
this._startIndex += count;
this._length -= count;
+ this.emit('trim', count);
}
public shiftElements(start: number, count: number, offset: number): void {
while (this._length > this.maxLength) {
this._length--;
this._startIndex++;
+ this.emit('trim', 1);
}
}
} else {
--- /dev/null
+/**
+ * @license MIT
+ */
+
+import { CharMeasure } from './CharMeasure';
+
+export function getCoords(event: MouseEvent, rowContainer: HTMLElement, charMeasure: CharMeasure): [number, number] {
+ // ignore browsers without pageX for now
+ if (event.pageX == null) {
+ return null;
+ }
+
+ let x = event.pageX;
+ let y = event.pageY;
+ let el = rowContainer;
+
+ // should probably check offsetParent
+ // but this is more portable
+ while (el && el !== self.document.documentElement) {
+ x -= el.offsetLeft;
+ y -= el.offsetTop;
+ el = 'offsetParent' in el ? <HTMLElement>el.offsetParent : <HTMLElement>el.parentElement;
+ }
+
+ // convert to cols/rows
+ x = Math.ceil(x / charMeasure.width);
+ y = Math.ceil(y / charMeasure.height);
+
+ return [x, y];
+}
font-family: courier-new, courier, monospace;
font-feature-settings: "liga" 0;
position: relative;
+ user-select: none;
}
.terminal.focus,
import { Parser } from './Parser';
import { Renderer } from './Renderer';
import { Linkifier } from './Linkifier';
+import { SelectionManager } from './SelectionManager';
import { CharMeasure } from './utils/CharMeasure';
import * as Browser from './utils/Browser';
-import * as Keyboard from './utils/Keyboard';
+import * as Mouse from './utils/Mouse';
import { CHARSETS } from './Charsets';
/**
this.parser = new Parser(this.inputHandler, this);
// Reuse renderer if the Terminal is being recreated via a Terminal.reset call.
this.renderer = this.renderer || null;
+ this.selectionManager = this.selectionManager || null;
this.linkifier = this.linkifier || new Linkifier();
// user input states
this.viewport = new Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasure);
this.renderer = new Renderer(this);
+ this.selectionManager = new SelectionManager(this.lines, this.rowContainer, this.charMeasure);
// Setup loop that draws to screen
this.refresh(0, this.rows - 1);
button = getButton(ev);
// get mouse coordinates
- pos = getCoords(ev);
+ pos = Mouse.getCoords(ev, this.rowContainer, this.charMeasure);
if (!pos) return;
sendEvent(button, pos);
var button = pressed
, pos;
- pos = getCoords(ev);
+ pos = Mouse.getCoords(ev, this.rowContainer, this.charMeasure);
if (!pos) return;
// buttons marked as motions
}
// mouse coordinates measured in cols/rows
- function getCoords(ev) {
- var x, y, w, h, el;
-
- // ignore browsers without pageX for now
- if (ev.pageX == null) return;
-
- x = ev.pageX;
- y = ev.pageY;
- el = self.element;
-
- // should probably check offsetParent
- // but this is more portable
- while (el && el !== self.document.documentElement) {
- x -= el.offsetLeft;
- y -= el.offsetTop;
- el = 'offsetParent' in el
- ? el.offsetParent
- : el.parentNode;
- }
+ // function getCoords(ev) {
+ // var x, y, w, h, el;
+
+ // // ignore browsers without pageX for now
+ // if (ev.pageX == null) return;
+
+ // x = ev.pageX;
+ // y = ev.pageY;
+ // el = self.rowContainer;
+
+ // // should probably check offsetParent
+ // // but this is more portable
+ // while (el && el !== self.document.documentElement) {
+ // x -= el.offsetLeft;
+ // y -= el.offsetTop;
+ // el = 'offsetParent' in el
+ // ? el.offsetParent
+ // : el.parentNode;
+ // }
- // convert to cols/rows
- x = Math.ceil(x / self.charMeasure.width);
- y = Math.ceil(y / self.charMeasure.height);
-
- // be sure to avoid sending
- // bad positions to the program
- if (x < 0) x = 0;
- if (x > self.cols) x = self.cols;
- if (y < 0) y = 0;
- if (y > self.rows) y = self.rows;
-
- // xterm sends raw bytes and
- // starts at 32 (SP) for each.
- x += 32;
- y += 32;
-
- return {
- x: x,
- y: y,
- type: 'wheel'
- };
- }
+ // // convert to cols/rows
+ // x = Math.ceil(x / self.charMeasure.width);
+ // y = Math.ceil(y / self.charMeasure.height);
+
+ // // be sure to avoid sending
+ // // bad positions to the program
+ // if (x < 0) x = 0;
+ // if (x > self.cols) x = self.cols;
+ // if (y < 0) y = 0;
+ // if (y > self.rows) y = self.rows;
+
+ // // xterm sends raw bytes and
+ // // starts at 32 (SP) for each.
+ // x += 32;
+ // y += 32;
+
+ // return {
+ // x: x,
+ // y: y,
+ // type: 'wheel'
+ // };
+ // }
on(el, 'mousedown', function(ev) {
if (!self.mouseEvents) return;