Merge branch 'master' into pr/1148

This commit is contained in:
Daniel Imms
2018-01-23 08:33:55 -08:00
committed by GitHub
66 changed files with 1058 additions and 1254 deletions
-1
View File
@@ -1,7 +1,6 @@
language: node_js
os:
- linux
- osx
node_js:
- 6
before_install:
+6
View File
@@ -119,6 +119,12 @@ computational environment for Jupyter, supporting interactive data science and s
- [**Whack Whack Terminal**](https://github.com/Microsoft/WhackWhackTerminal): Terminal emulator for Visual Studio 2017.
- [**VTerm**](https://github.com/vterm/vterm): Extensible terminal emulator based on Electron and React.
- [**electerm**](http://electerm.html5beta.com): electerm is a terminal/ssh/sftp client(mac, win, linux) based on electron/node-pty/xterm.
- [**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.
+3
View File
@@ -23,6 +23,9 @@
<p>
<label><input type="checkbox" id="option-cursor-blink"> cursorBlink</label>
</p>
<p>
<label><input type="checkbox" id="option-mac-option-is-meta"> macOptionIsMeta</label>
</p>
<p>
<label>
cursorStyle
+5
View File
@@ -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)
+9 -2
View File
@@ -144,7 +144,10 @@ namespace methods_core {
const r20: string = t.getOption('bellStyle');
const r21: boolean = t.getOption('enableBold');
const r22: number = t.getOption('letterSpacing');
const r23: boolean = t.getOption('allowTransparency');
const r23: boolean = t.getOption('macOptionIsMeta');
const r24: string = t.getOption('fontWeight');
const r25: string = t.getOption('fontWeightBold');
const r26: boolean = t.getOption('allowTransparency');
}
{
const t: Terminal = new Terminal();
@@ -157,7 +160,10 @@ namespace methods_core {
t.setOption('cursorBlink', true);
t.setOption('debug', true);
t.setOption('disableStdin', true);
t.setOption('enableBold', true);
t.setOption('fontWeight', 'normal');
t.setOption('fontWeight', 'bold');
t.setOption('fontWeightBold', 'normal');
t.setOption('fontWeightBold', 'bold');
t.setOption('popOnBell', true);
t.setOption('screenKeys', true);
t.setOption('useFlowControl', true);
@@ -179,6 +185,7 @@ namespace methods_core {
t.setOption('lineHeight', 1);
t.setOption('fontFamily', 'foo');
t.setOption('theme', {background: '#ff0000'});
t.setOption('macOptionIsMeta', true);
}
}
namespace scrolling {
+38 -46
View File
@@ -18,11 +18,13 @@ const ts = require('gulp-typescript');
const util = require('gulp-util');
const webpack = require('webpack-stream');
let buildDir = process.env.BUILD_DIR || 'build';
let tsProject = ts.createProject('tsconfig.json');
let srcDir = tsProject.config.compilerOptions.rootDir;
const buildDir = process.env.BUILD_DIR || 'build';
const tsProject = ts.createProject('tsconfig.json');
const srcDir = tsProject.config.compilerOptions.rootDir;
let outDir = tsProject.config.compilerOptions.outDir;
const addons = ['attach', 'fit', 'fullscreen', 'search', 'terminado', 'winptyCompat', 'zmodem'];
// Under some environments like TravisCI, this comes out at absolute which can
// break the build. This ensures that the outDir is absolute.
if (path.normalize(outDir).indexOf(__dirname) !== 0) {
@@ -45,15 +47,19 @@ gulp.task('tsc', function () {
tsResult.dts.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(outDir))
);
let addons = ['attach', 'fit', 'fullscreen', 'search', 'terminado', 'winptyCompat', 'zmodem'];
let addonStreams = addons.map(function(addon) {
fs.emptyDirSync(`${outDir}/addons/${addon}`);
let tsProjectAddon = ts.createProject(`./src/addons/${addon}/tsconfig.json`);
let tsResultAddon = tsProjectAddon.src().pipe(sourcemaps.init()).pipe(tsProjectAddon());
let tscAddon = tsResultAddon.js
.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''}))
.pipe(gulp.dest(`${outDir}/addons/${addon}`));
let tscAddon = merge(
tsResultAddon.js
.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''}))
.pipe(gulp.dest(`${outDir}/addons/${addon}`)),
tsResultAddon.dts
.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''}))
.pipe(gulp.dest(`${outDir}/addons/${addon}`))
)
return tscAddon;
});
@@ -103,45 +109,29 @@ gulp.task('browserify', ['tsc'], function() {
});
gulp.task('browserify-addons', ['tsc'], function() {
let searchOptions = {
basedir: `${buildDir}/addons/search`,
debug: true,
entries: [`${outDir}/addons/search/search.js`],
cache: {},
packageCache: {}
};
let searchBundle = browserify(searchOptions)
.external(path.join(outDir, 'Terminal.js'))
.bundle()
.pipe(source('./addons/search/search.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true, sourceRoot: ''}))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest(buildDir));
const bundles = addons.map((addon) => {
const addonOptions = {
basedir: `${buildDir}/addons/${addon}`,
debug: true,
entries: [`${outDir}/addons/${addon}/${addon}.js`],
standalone: addon,
cache: {},
packageCache: {}
};
let winptyCompatOptions = {
basedir: `${buildDir}/addons/winptyCompat`,
debug: true,
entries: [`${outDir}/addons/winptyCompat/winptyCompat.js`],
cache: {},
packageCache: {}
};
let winptyCompatBundle = browserify(winptyCompatOptions)
.external(path.join(outDir, 'Terminal.js'))
.bundle()
.pipe(source('./addons/winptyCompat/winptyCompat.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true, sourceRoot: ''}))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest(buildDir));
const addonBundle = browserify(addonOptions)
.external(path.join(outDir, 'Terminal.js'))
.bundle()
.pipe(source(`./addons/${addon}/${addon}.js`))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true, sourceRoot: ''}))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest(buildDir));
// Copy all add-ons from outDir to buildDir
let copyAddons = gulp.src([
// Copy JS addons
`${outDir}/addons/**/*`
]).pipe(gulp.dest(`${buildDir}/addons`));
return addonBundle;
});
return merge(searchBundle, winptyCompatBundle, copyAddons);
return merge(...bundles);
});
gulp.task('instrument-test', function () {
@@ -189,9 +179,11 @@ gulp.task('sorcery', ['browserify'], function () {
});
gulp.task('sorcery-addons', ['browserify-addons'], function () {
var chain = sorcery.loadSync(`${buildDir}/addons/search/search.js`);
chain.apply();
chain.writeSync();
addons.forEach((addon) => {
const chain = sorcery.loadSync(`${buildDir}/addons/${addon}/${addon}.js`);
chain.apply();
chain.writeSync();
})
});
gulp.task('webpack', ['build'], function() {
+251 -759
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -66,7 +66,7 @@
"node-pty": "^0.7.2",
"nodemon": "1.10.2",
"sorcery": "^0.10.0",
"tslint": "^4.0.2",
"tslint": "^5.9.1",
"typescript": "~2.4.0",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0",
-5
View File
@@ -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);
}
+14 -3
View File
@@ -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
});
}
/**
+3 -3
View File
@@ -3,19 +3,19 @@
* @license MIT
*/
import { Charset } from './Types';
import { ICharset } from './Interfaces';
/**
* The character sets supported by the terminal. These enable several languages
* to be represented within the terminal with only 8-bit encoding. See ISO 2022
* for a discussion on character sets. Only VT100 character sets are supported.
*/
export const CHARSETS: { [key: string]: Charset } = {};
export const CHARSETS: { [key: string]: ICharset } = {};
/**
* The default character set, US.
*/
export const DEFAULT_CHARSET: Charset = CHARSETS['B'];
export const DEFAULT_CHARSET: ICharset = CHARSETS['B'];
/**
* DEC Special Character and Line Drawing Set.
+2 -2
View File
@@ -217,7 +217,7 @@ export class CompositionHelper {
if (!dontRecurse) {
setTimeout(() => this.updateCompositionElements(true), 0);
}
};
}
/**
* Clears the textarea's position so that the cursor does not blink on IE.
@@ -226,5 +226,5 @@ export class CompositionHelper {
private clearTextareaPosition(): void {
this.textarea.style.left = '';
this.textarea.style.top = '';
};
}
}
+1 -1
View File
@@ -76,4 +76,4 @@ export namespace C0 {
export const SP = '\x20';
/** Delete (Caret = ^?) */
export const DEL = '\x7f';
};
}
+7 -9
View File
@@ -26,7 +26,7 @@ export class InputHandler implements IInputHandler {
if (char >= ' ') {
// calculate print space
// expensive call, therefore we save width in line buffer
const ch_width = wcwidth(code);
const chWidth = wcwidth(code);
if (this._terminal.charset && this._terminal.charset[char]) {
char = this._terminal.charset[char];
@@ -36,7 +36,7 @@ export class InputHandler implements IInputHandler {
// insert combining char in last cell
// FIXME: needs handling after cursor jumps
if (!ch_width && this._terminal.buffer.x) {
if (!chWidth && this._terminal.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]) {
@@ -56,7 +56,7 @@ export class InputHandler implements IInputHandler {
// goto next line if ch would overflow
// TODO: needs a global min terminal width of 2
if (this._terminal.buffer.x + ch_width - 1 >= this._terminal.cols) {
if (this._terminal.buffer.x + chWidth - 1 >= this._terminal.cols) {
// autowrap - DECAWM
if (this._terminal.wraparoundMode) {
this._terminal.buffer.x = 0;
@@ -70,7 +70,7 @@ export class InputHandler implements IInputHandler {
(<any>this._terminal.buffer.lines.get(this._terminal.buffer.y)).isWrapped = true;
}
} else {
if (ch_width === 2) // FIXME: check for xterm behavior
if (chWidth === 2) // FIXME: check for xterm behavior
return;
}
}
@@ -79,7 +79,7 @@ export class InputHandler implements IInputHandler {
// insert mode: move characters to right
if (this._terminal.insertMode) {
// do this twice for a fullwidth char
for (let moves = 0; moves < ch_width; ++moves) {
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();
@@ -94,12 +94,12 @@ export class InputHandler implements IInputHandler {
}
}
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, char, ch_width, char.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);
// fullwidth char - set next cell width to zero and advance cursor
if (ch_width === 2) {
if (chWidth === 2) {
this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, '', 0, undefined];
this._terminal.buffer.x++;
}
@@ -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();
+31 -9
View File
@@ -3,8 +3,8 @@
* @license MIT
*/
import { ILinkMatcherOptions } from './Interfaces';
import { LinkMatcherHandler, LinkMatcherValidationCallback, Charset, LineData } from './Types';
import { ICharset, ILinkMatcherOptions } from './Interfaces';
import { LinkMatcherHandler, LinkMatcherValidationCallback, LineData, FontWeight } from './Types';
import { IColorSet, IRenderer } from './renderer/Interfaces';
import { IMouseZoneManager } from './input/Interfaces';
@@ -74,10 +74,10 @@ export interface IInputHandlingTerminal extends IEventEmitter {
options: ITerminalOptions;
cols: number;
rows: number;
charset: Charset;
charset: ICharset;
gcharset: number;
glevel: number;
charsets: Charset[];
charsets: ICharset[];
applicationKeypad: boolean;
applicationCursor: boolean;
originMode: boolean;
@@ -116,7 +116,7 @@ export interface IInputHandlingTerminal extends IEventEmitter {
blankLine(cur?: boolean, isWrapped?: boolean): LineData;
is(term: string): boolean;
send(data: string): void;
setgCharset(g: number, charset: Charset): void;
setgCharset(g: number, charset: ICharset): void;
resize(x: number, y: number): void;
log(text: string, data?: any): void;
reset(): void;
@@ -137,12 +137,14 @@ export interface ITerminalOptions {
cursorStyle?: string;
debug?: boolean;
disableStdin?: boolean;
enableBold?: boolean;
fontSize?: number;
fontFamily?: string;
fontWeight?: FontWeight;
fontWeightBold?: FontWeight;
handler?: (data: string) => void;
letterSpacing?: number;
lineHeight?: number;
macOptionIsMeta?: boolean;
rows?: number;
screenKeys?: boolean;
scrollback?: number;
@@ -170,7 +172,7 @@ export interface IBuffer {
prevStop(x?: number): number;
}
export interface IBufferSet {
export interface IBufferSet extends IEventEmitter {
alt: IBuffer;
normal: IBuffer;
active: IBuffer;
@@ -199,7 +201,6 @@ export interface ISelectionManager {
disable(): void;
enable(): void;
setBuffer(buffer: IBuffer): void;
setSelection(row: number, col: number, length: number): void;
}
@@ -249,7 +250,7 @@ export interface IEventEmitter {
export interface IListenerType {
(data?: any): void;
listener?: (data?: any) => void;
};
}
export interface ILinkMatcherOptions {
/**
@@ -353,3 +354,24 @@ export interface ITheme {
brightCyan?: string;
brightWhite?: string;
}
export interface ILinkMatcher {
id: number;
regex: RegExp;
handler: LinkMatcherHandler;
hoverTooltipCallback?: LinkMatcherHandler;
hoverLeaveCallback?: () => void;
matchIndex?: number;
validationCallback?: LinkMatcherValidationCallback;
priority?: number;
}
export interface ICharset {
[key: string]: string;
}
export interface ILinkHoverEvent {
x: number;
y: number;
length: number;
}
+3 -3
View File
@@ -4,9 +4,9 @@
*/
import { assert } from 'chai';
import { ITerminal, ILinkifier, IBuffer, IBufferAccessor, IElementAccessor } from './Interfaces';
import { ITerminal, ILinkifier, ILinkMatcher, IBuffer, IBufferAccessor, IElementAccessor } from './Interfaces';
import { Linkifier } from './Linkifier';
import { LinkMatcher, LineData } from './Types';
import { LineData } from './Types';
import { IMouseZoneManager, IMouseZone } from './input/Interfaces';
import { MockBuffer } from './utils/TestUtils.test';
import { CircularList } from './utils/CircularList';
@@ -17,7 +17,7 @@ class TestLinkifier extends Linkifier {
Linkifier.TIME_BEFORE_LINKIFY = 0;
}
public get linkMatchers(): LinkMatcher[] { return this._linkMatchers; }
public get linkMatchers(): ILinkMatcher[] { return this._linkMatchers; }
public linkifyRows(): void { super.linkifyRows(0, this._terminal.buffer.lines.length - 1); }
}
+13 -13
View File
@@ -3,8 +3,8 @@
* @license MIT
*/
import { ILinkMatcherOptions, ITerminal, IBufferAccessor, ILinkifier, IElementAccessor } from './Interfaces';
import { LinkMatcher, LinkMatcherHandler, LinkMatcherValidationCallback, LineData, LinkHoverEvent, LinkHoverEventTypes } from './Types';
import { ILinkHoverEvent, ILinkMatcher, ILinkMatcherOptions, ITerminal, IBufferAccessor, ILinkifier, IElementAccessor } from './Interfaces';
import { LinkMatcherHandler, LinkMatcherValidationCallback, LineData, LinkHoverEventTypes } from './Types';
import { IMouseZoneManager } from './input/Interfaces';
import { MouseZone } from './input/MouseZoneManager';
import { EventEmitter } from './EventEmitter';
@@ -44,7 +44,7 @@ export class Linkifier extends EventEmitter implements ILinkifier {
*/
protected static TIME_BEFORE_LINKIFY = 200;
protected _linkMatchers: LinkMatcher[] = [];
protected _linkMatchers: ILinkMatcher[] = [];
private _mouseZoneManager: IMouseZoneManager;
private _rowsTimeoutId: number;
@@ -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
@@ -143,7 +143,7 @@ export class Linkifier extends EventEmitter implements ILinkifier {
if (this._nextLinkMatcherId !== HYPERTEXT_LINK_MATCHER_ID && !handler) {
throw new Error('handler must be defined');
}
const matcher: LinkMatcher = {
const matcher: ILinkMatcher = {
id: this._nextLinkMatcherId++,
regex,
handler,
@@ -163,7 +163,7 @@ export class Linkifier extends EventEmitter implements ILinkifier {
* considered after older link matchers.
* @param matcher The link matcher to be added.
*/
private _addLinkMatcherToList(matcher: LinkMatcher): void {
private _addLinkMatcherToList(matcher: ILinkMatcher): void {
if (this._linkMatchers.length === 0) {
this._linkMatchers.push(matcher);
return;
@@ -219,7 +219,7 @@ export class Linkifier extends EventEmitter implements ILinkifier {
* @param offset The how much of the row has already been linkified.
* @return The link element(s) that were added.
*/
private _doLinkifyRow(rowIndex: number, text: string, matcher: LinkMatcher, offset: number = 0): void {
private _doLinkifyRow(rowIndex: number, text: string, matcher: ILinkMatcher, offset: number = 0): void {
// Iterate over nodes as we want to consider text nodes
let result = [];
const isHttpLinkMatcher = matcher.id === HYPERTEXT_LINK_MATCHER_ID;
@@ -264,7 +264,7 @@ export class Linkifier extends EventEmitter implements ILinkifier {
* @param uri The URI of the link.
* @param matcher The link matcher for the link.
*/
private _addLink(x: number, y: number, uri: string, matcher: LinkMatcher): void {
private _addLink(x: number, y: number, uri: string, matcher: ILinkMatcher): void {
this._mouseZoneManager.add(new MouseZone(
x + 1,
x + 1 + uri.length,
@@ -276,17 +276,17 @@ export class Linkifier extends EventEmitter implements ILinkifier {
window.open(uri, '_blank');
},
e => {
this.emit(LinkHoverEventTypes.HOVER, <LinkHoverEvent>{ x, y, length: uri.length});
this.emit(LinkHoverEventTypes.HOVER, <ILinkHoverEvent>{ x, y, length: uri.length});
this._terminal.element.style.cursor = 'pointer';
},
e => {
this.emit(LinkHoverEventTypes.TOOLTIP, <LinkHoverEvent>{ x, y, length: uri.length});
this.emit(LinkHoverEventTypes.TOOLTIP, <ILinkHoverEvent>{ x, y, length: uri.length});
if (matcher.hoverTooltipCallback) {
matcher.hoverTooltipCallback(e, uri);
}
},
() => {
this.emit(LinkHoverEventTypes.LEAVE, <LinkHoverEvent>{ x, y, length: uri.length});
this.emit(LinkHoverEventTypes.LEAVE, <ILinkHoverEvent>{ x, y, length: uri.length});
this._terminal.element.style.cursor = '';
if (matcher.hoverLeaveCallback) {
matcher.hoverLeaveCallback();
+7
View File
@@ -286,36 +286,43 @@ export class Parser {
// Single Shift Select of G2 Character Set
// ( SS2 is 0x8e). This affects next character only.
case 'N':
this._state = ParserState.NORMAL;
break;
// ESC O
// Single Shift Select of G3 Character Set
// ( SS3 is 0x8f). This affects next character only.
case 'O':
this._state = ParserState.NORMAL;
break;
// ESC n
// Invoke the G2 Character Set as GL (LS2).
case 'n':
this._terminal.setgLevel(2);
this._state = ParserState.NORMAL;
break;
// ESC o
// Invoke the G3 Character Set as GL (LS3).
case 'o':
this._terminal.setgLevel(3);
this._state = ParserState.NORMAL;
break;
// ESC |
// Invoke the G3 Character Set as GR (LS3R).
case '|':
this._terminal.setgLevel(3);
this._state = ParserState.NORMAL;
break;
// ESC }
// Invoke the G2 Character Set as GR (LS2R).
case '}':
this._terminal.setgLevel(2);
this._state = ParserState.NORMAL;
break;
// ESC ~
// Invoke the G1 Character Set as GR (LS1R).
case '~':
this._terminal.setgLevel(1);
this._state = ParserState.NORMAL;
break;
// ESC 7 Save Cursor (DECSC).
+2 -3
View File
@@ -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 {
+23 -17
View File
@@ -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(<MouseEvent>event);
this._mouseUpListener = event => this._onMouseUp(<MouseEvent>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.

Some files were not shown because too many files have changed in this diff Show More