diff --git a/.travis.yml b/.travis.yml index 1878c3a4..7a37af1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: node_js os: - linux - - osx node_js: - 6 before_install: diff --git a/README.md b/README.md index 1719efb2..93e7f262 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,8 @@ computational environment for Jupyter, supporting interactive data science and s - [**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. 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/gulpfile.js b/gulpfile.js index 804cad35..7a65d7f2 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -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,7 +47,6 @@ 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}`); @@ -108,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 () { @@ -194,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() { diff --git a/src/Terminal.ts b/src/Terminal.ts index f95cc0ea..6e4d1aa0 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -1573,6 +1573,8 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT // page up if (ev.shiftKey) { result.scrollLines = -(this.rows - 1); + } else if (modifiers) { + result.key = C0.ESC + '[5;' + (modifiers + 1) + '~'; } else { result.key = C0.ESC + '[5~'; } @@ -1581,6 +1583,8 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT // page down if (ev.shiftKey) { result.scrollLines = this.rows - 1; + } else if (modifiers) { + result.key = C0.ESC + '[6;' + (modifiers + 1) + '~'; } else { result.key = C0.ESC + '[6~'; } diff --git a/src/renderer/CursorRenderLayer.ts b/src/renderer/CursorRenderLayer.ts index 689d6914..f4e3c54f 100644 --- a/src/renderer/CursorRenderLayer.ts +++ b/src/renderer/CursorRenderLayer.ts @@ -108,9 +108,10 @@ export class CursorRenderLayer extends BaseRenderLayer { } public onGridChanged(terminal: ITerminal, startRow: number, endRow: number): void { - // Only render if the animation frame is not active if (!this._cursorBlinkStateManager || this._cursorBlinkStateManager.isPaused) { this._render(terminal, false); + } else { + this._cursorBlinkStateManager.restartBlinkAnimation(terminal); } } diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index 31547da4..680d9490 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -57,6 +57,7 @@ export class Renderer extends EventEmitter implements IRenderer { }; this._devicePixelRatio = window.devicePixelRatio; this._updateDimensions(); + this.onOptionsChanged(); this._screenDprMonitor = new ScreenDprMonitor(); this._screenDprMonitor.setListener(() => this.onWindowResize(window.devicePixelRatio));