Merge branch 'v3' into zmodem
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
<script src="/build/addons/fit/fit.js" ></script>
|
<script src="/build/addons/fit/fit.js" ></script>
|
||||||
<script src="/build/addons/fullscreen/fullscreen.js" ></script>
|
<script src="/build/addons/fullscreen/fullscreen.js" ></script>
|
||||||
<script src="/build/addons/search/search.js" ></script>
|
<script src="/build/addons/search/search.js" ></script>
|
||||||
|
<script src="/build/addons/winptyCompat/winptyCompat.js" ></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>xterm.js: xterm, in the browser</h1>
|
<h1>xterm.js: xterm, in the browser</h1>
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ function createTerminal() {
|
|||||||
|
|
||||||
term.open(terminalContainer);
|
term.open(terminalContainer);
|
||||||
term.fit();
|
term.fit();
|
||||||
|
term.winptyCompatInit();
|
||||||
|
|
||||||
// fit is called within a setTimeout, cols and rows need this.
|
// fit is called within a setTimeout, cols and rows need this.
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace static_methods {
|
|||||||
Terminal.loadAddon('fullscreen');
|
Terminal.loadAddon('fullscreen');
|
||||||
Terminal.loadAddon('search');
|
Terminal.loadAddon('search');
|
||||||
Terminal.loadAddon('terminado');
|
Terminal.loadAddon('terminado');
|
||||||
|
Terminal.loadAddon('winptyCompat');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+32
-4
@@ -20,7 +20,6 @@ const util = require('gulp-util');
|
|||||||
|
|
||||||
let buildDir = process.env.BUILD_DIR || 'build';
|
let buildDir = process.env.BUILD_DIR || 'build';
|
||||||
let tsProject = ts.createProject('tsconfig.json');
|
let tsProject = ts.createProject('tsconfig.json');
|
||||||
let tsProjectSearchAddon = ts.createProject('./src/addons/search/tsconfig.json');
|
|
||||||
let srcDir = tsProject.config.compilerOptions.rootDir;
|
let srcDir = tsProject.config.compilerOptions.rootDir;
|
||||||
let outDir = tsProject.config.compilerOptions.outDir;
|
let outDir = tsProject.config.compilerOptions.outDir;
|
||||||
|
|
||||||
@@ -47,16 +46,29 @@ gulp.task('tsc', function () {
|
|||||||
);
|
);
|
||||||
|
|
||||||
fs.emptyDirSync(`${outDir}/addons/search`);
|
fs.emptyDirSync(`${outDir}/addons/search`);
|
||||||
|
fs.emptyDirSync(`${outDir}/addons/winptyCompat`);
|
||||||
|
|
||||||
|
let tsProjectSearchAddon = ts.createProject('./src/addons/search/tsconfig.json');
|
||||||
let tsResultSearchAddon = tsProjectSearchAddon.src().pipe(sourcemaps.init()).pipe(tsProjectSearchAddon());
|
let tsResultSearchAddon = tsProjectSearchAddon.src().pipe(sourcemaps.init()).pipe(tsProjectSearchAddon());
|
||||||
let tscSearchAddon = tsResultSearchAddon.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(`${outDir}/addons/search`));
|
let tscSearchAddon = tsResultSearchAddon.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(`${outDir}/addons/search`));
|
||||||
|
|
||||||
|
let tsProjectWinptyCompatAddon = ts.createProject('./src/addons/winptyCompat/tsconfig.json');
|
||||||
|
let tsResultWinptyCompatAddon = tsProjectWinptyCompatAddon.src().pipe(sourcemaps.init()).pipe(tsProjectWinptyCompatAddon());
|
||||||
|
let tscWinptyCompatAddon = tsResultWinptyCompatAddon.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(`${outDir}/addons/winptyCompat`));
|
||||||
|
|
||||||
// Copy all addons from ${srcDir}/ to ${outDir}/
|
// Copy all addons from ${srcDir}/ to ${outDir}/
|
||||||
let copyAddons = gulp.src([`${srcDir}/addons/**/*`, `!${srcDir}/addons/search`, `!${srcDir}/addons/search/**`]).pipe(gulp.dest(`${outDir}/addons`));
|
let copyAddons = gulp.src([
|
||||||
|
`${srcDir}/addons/**/*`,
|
||||||
|
`!${srcDir}/addons/search`,
|
||||||
|
`!${srcDir}/addons/search/**`,
|
||||||
|
`!${srcDir}/addons/winptyCompat`,
|
||||||
|
`!${srcDir}/addons/winptyCompat/**`
|
||||||
|
]).pipe(gulp.dest(`${outDir}/addons`));
|
||||||
|
|
||||||
// Copy stylesheets from ${srcDir}/ to ${outDir}/
|
// Copy stylesheets from ${srcDir}/ to ${outDir}/
|
||||||
let copyStylesheets = gulp.src(`${srcDir}/**/*.css`).pipe(gulp.dest(outDir));
|
let copyStylesheets = gulp.src(`${srcDir}/**/*.css`).pipe(gulp.dest(outDir));
|
||||||
|
|
||||||
return merge(tsc, tscSearchAddon, copyAddons, copyStylesheets);
|
return merge(tsc, tscSearchAddon, tscWinptyCompatAddon, copyAddons, copyStylesheets);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,6 +128,22 @@ gulp.task('browserify-addons', ['tsc'], function() {
|
|||||||
`${outDir}/addons/zmodem/demo/**`,
|
`${outDir}/addons/zmodem/demo/**`,
|
||||||
]).pipe(gulp.dest(`${buildDir}/addons/zmodem/demo`));
|
]).pipe(gulp.dest(`${buildDir}/addons/zmodem/demo`));
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
// Copy all add-ons from outDir to buildDir
|
// Copy all add-ons from outDir to buildDir
|
||||||
let copyAddons = gulp.src([
|
let copyAddons = gulp.src([
|
||||||
// Copy JS addons
|
// Copy JS addons
|
||||||
@@ -126,7 +154,7 @@ gulp.task('browserify-addons', ['tsc'], function() {
|
|||||||
`!${outDir}/addons/zmodem/**`,
|
`!${outDir}/addons/zmodem/**`,
|
||||||
]).pipe(gulp.dest(`${buildDir}/addons`));
|
]).pipe(gulp.dest(`${buildDir}/addons`));
|
||||||
|
|
||||||
return merge(searchBundle, zmodemBundle, zmodemDemoBundle, copyAddons);
|
return merge(searchBundle, zmodemBundle, zmodemDemoBundle, winptyCompatBundle, copyAddons);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('instrument-test', function () {
|
gulp.task('instrument-test', function () {
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@
|
|||||||
"jsdoc": "3.4.3",
|
"jsdoc": "3.4.3",
|
||||||
"jsdom": "^11.1.0",
|
"jsdom": "^11.1.0",
|
||||||
"merge-stream": "^1.0.1",
|
"merge-stream": "^1.0.1",
|
||||||
"node-pty": "0.7.2",
|
"node-pty": "^0.7.2",
|
||||||
"nodemon": "1.10.2",
|
"nodemon": "1.10.2",
|
||||||
"sorcery": "^0.10.0",
|
"sorcery": "^0.10.0",
|
||||||
"tslint": "^4.0.2",
|
"tslint": "^4.0.2",
|
||||||
|
|||||||
+10
-3
@@ -307,6 +307,15 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
|
|||||||
return (offset / Math.abs(offset)) + Math.round(offset * (DRAG_SCROLL_MAX_SPEED - 1));
|
return (offset / Math.abs(offset)) + Math.round(offset * (DRAG_SCROLL_MAX_SPEED - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the selection manager should force selection, regardless of
|
||||||
|
* whether the terminal is in mouse events mode.
|
||||||
|
* @param event The mouse event.
|
||||||
|
*/
|
||||||
|
public shouldForceSelection(event: MouseEvent): boolean {
|
||||||
|
return Browser.isMac ? event.altKey : event.shiftKey;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles te mousedown event, setting up for a new selection.
|
* Handles te mousedown event, setting up for a new selection.
|
||||||
* @param event The mousedown event.
|
* @param event The mousedown event.
|
||||||
@@ -325,9 +334,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
|
|||||||
|
|
||||||
// Allow selection when using a specific modifier key, even when disabled
|
// Allow selection when using a specific modifier key, even when disabled
|
||||||
if (!this._enabled) {
|
if (!this._enabled) {
|
||||||
const shouldForceSelection = Browser.isMac ? event.altKey : event.shiftKey;
|
if (!this.shouldForceSelection(event)) {
|
||||||
|
|
||||||
if (!shouldForceSelection) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+36
-1
@@ -943,7 +943,12 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
|||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.focus();
|
this.focus();
|
||||||
|
|
||||||
if (!this.mouseEvents) return;
|
// Don't send the mouse button to the pty if mouse events are disabled or
|
||||||
|
// if the selection manager is having selection forced (ie. a modifier is
|
||||||
|
// held).
|
||||||
|
if (!this.mouseEvents || this.selectionManager.shouldForceSelection(ev)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// send the button
|
// send the button
|
||||||
sendButton(ev);
|
sendButton(ev);
|
||||||
@@ -1417,6 +1422,36 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
|||||||
};
|
};
|
||||||
const modifiers = (ev.shiftKey ? 1 : 0) | (ev.altKey ? 2 : 0) | (ev.ctrlKey ? 4 : 0) | (ev.metaKey ? 8 : 0);
|
const modifiers = (ev.shiftKey ? 1 : 0) | (ev.altKey ? 2 : 0) | (ev.ctrlKey ? 4 : 0) | (ev.metaKey ? 8 : 0);
|
||||||
switch (ev.keyCode) {
|
switch (ev.keyCode) {
|
||||||
|
case 0:
|
||||||
|
if (ev.key === 'UIKeyInputUpArrow') {
|
||||||
|
if (this.applicationCursor) {
|
||||||
|
result.key = C0.ESC + 'OA';
|
||||||
|
} else {
|
||||||
|
result.key = C0.ESC + '[A';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ev.key === 'UIKeyInputLeftArrow') {
|
||||||
|
if (this.applicationCursor) {
|
||||||
|
result.key = C0.ESC + 'OD';
|
||||||
|
} else {
|
||||||
|
result.key = C0.ESC + '[D';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ev.key === 'UIKeyInputRightArrow') {
|
||||||
|
if (this.applicationCursor) {
|
||||||
|
result.key = C0.ESC + 'OC';
|
||||||
|
} else {
|
||||||
|
result.key = C0.ESC + '[C';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ev.key === 'UIKeyInputDownArrow') {
|
||||||
|
if (this.applicationCursor) {
|
||||||
|
result.key = C0.ESC + 'OB';
|
||||||
|
} else {
|
||||||
|
result.key = C0.ESC + '[B';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
// backspace
|
// backspace
|
||||||
if (ev.shiftKey) {
|
if (ev.shiftKey) {
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es5",
|
||||||
|
"rootDir": ".",
|
||||||
|
"outDir": "../../../lib/addons/winptyCompat/",
|
||||||
|
"sourceMap": true,
|
||||||
|
"removeComments": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare var exports: any;
|
||||||
|
declare var define: any;
|
||||||
|
|
||||||
|
(function (addon) {
|
||||||
|
if (typeof window !== 'undefined' && 'Terminal' in window) {
|
||||||
|
/**
|
||||||
|
* Plain browser environment
|
||||||
|
*/
|
||||||
|
addon((<any>window).Terminal);
|
||||||
|
} else if (typeof exports === 'object' && typeof module === 'object') {
|
||||||
|
/**
|
||||||
|
* CommonJS environment
|
||||||
|
*/
|
||||||
|
module.exports = addon(require('../../Terminal').Terminal);
|
||||||
|
} else if (typeof define === 'function') {
|
||||||
|
/**
|
||||||
|
* Require.js is available
|
||||||
|
*/
|
||||||
|
define(['../../xterm'], addon);
|
||||||
|
}
|
||||||
|
})((Terminal: any) => {
|
||||||
|
Terminal.prototype.winptyCompatInit = function(): void {
|
||||||
|
// 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.
|
||||||
|
this.on('lineFeed', () => {
|
||||||
|
const line = this.buffer.lines.get(this.buffer.ybase + this.buffer.y - 1);
|
||||||
|
const lastChar = line[this.cols - 1];
|
||||||
|
if (lastChar[3] !== 32 /* ' ' */) {
|
||||||
|
const nextLine = this.buffer.lines.get(this.buffer.ybase + this.buffer.y);
|
||||||
|
(<any>nextLine).isWrapped = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -15,12 +15,12 @@ const DIM_OPACITY = 0.5;
|
|||||||
export abstract class BaseRenderLayer implements IRenderLayer {
|
export abstract class BaseRenderLayer implements IRenderLayer {
|
||||||
private _canvas: HTMLCanvasElement;
|
private _canvas: HTMLCanvasElement;
|
||||||
protected _ctx: CanvasRenderingContext2D;
|
protected _ctx: CanvasRenderingContext2D;
|
||||||
private _scaledCharWidth: number;
|
private _scaledCharWidth: number = 0;
|
||||||
private _scaledCharHeight: number;
|
private _scaledCharHeight: number = 0;
|
||||||
private _scaledCellWidth: number;
|
private _scaledCellWidth: number = 0;
|
||||||
private _scaledCellHeight: number;
|
private _scaledCellHeight: number = 0;
|
||||||
private _scaledCharLeft: number;
|
private _scaledCharLeft: number = 0;
|
||||||
private _scaledCharTop: number;
|
private _scaledCharTop: number = 0;
|
||||||
|
|
||||||
private _charAtlas: HTMLCanvasElement | ImageBitmap;
|
private _charAtlas: HTMLCanvasElement | ImageBitmap;
|
||||||
|
|
||||||
|
|||||||
Vendored
+4
-2
@@ -290,7 +290,9 @@ declare module 'xterm' {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the terminal within an element.
|
* Opens the terminal within an element.
|
||||||
* @param parent The element to create the terminal within.
|
* @param parent The element to create the terminal within. This element
|
||||||
|
* must be visible (have dimensions) when `open` is called as several DOM-
|
||||||
|
* based measurements need to be performed when this function is called.
|
||||||
*/
|
*/
|
||||||
open(parent: HTMLElement): void;
|
open(parent: HTMLElement): void;
|
||||||
|
|
||||||
@@ -513,6 +515,6 @@ declare module 'xterm' {
|
|||||||
* available to all newly created Terminals.
|
* available to all newly created Terminals.
|
||||||
* @param addon The addon to load.
|
* @param addon The addon to load.
|
||||||
*/
|
*/
|
||||||
static loadAddon(addon: 'attach' | 'fit' | 'fullscreen' | 'search' | 'terminado'): void;
|
static loadAddon(addon: 'attach' | 'fit' | 'fullscreen' | 'search' | 'terminado' | 'winptyCompat'): void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user