From 2e4147b4fa72c10a7f5864616b76516bfb5f384c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 1 Jan 2017 16:24:52 -0800 Subject: [PATCH 01/12] Use Tyriar/pty.js for Windows support Fixes #441 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 734bb6fb..6df2314a 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "jsdoc": "3.4.3", "mocha": "2.5.3", "nodemon": "1.10.2", - "pty.js": "0.3.1", + "pty.js": "https://github.com/Tyriar/pty.js/tarball/c75c2dcb6dcad83b0cb3ef2ae42d0448fb912642", "sleep": "^3.0.1", "sorcery": "^0.10.0", "tslint": "^4.0.2", From bebe43e5e108b081a8ead57b881e7ea1504164d7 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 8 Jan 2017 13:33:51 -0800 Subject: [PATCH 02/12] Use node-pty as it's been published --- demo/app.js | 2 +- package.json | 2 +- src/test/escape-sequences-test.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/demo/app.js b/demo/app.js index a4122ace..3439ea99 100644 --- a/demo/app.js +++ b/demo/app.js @@ -2,7 +2,7 @@ var express = require('express'); var app = express(); var expressWs = require('express-ws')(app); var os = require('os'); -var pty = require('pty.js'); +var pty = require('node-pty'); var terminals = {}, logs = {}; diff --git a/package.json b/package.json index 6df2314a..74ba3e00 100644 --- a/package.json +++ b/package.json @@ -44,8 +44,8 @@ "glob": "^7.0.5", "jsdoc": "3.4.3", "mocha": "2.5.3", + "node-pty": "^0.4.1", "nodemon": "1.10.2", - "pty.js": "https://github.com/Tyriar/pty.js/tarball/c75c2dcb6dcad83b0cb3ef2ae42d0448fb912642", "sleep": "^3.0.1", "sorcery": "^0.10.0", "tslint": "^4.0.2", diff --git a/src/test/escape-sequences-test.js b/src/test/escape-sequences-test.js index ace2c3cb..7dcefd95 100644 --- a/src/test/escape-sequences-test.js +++ b/src/test/escape-sequences-test.js @@ -1,6 +1,6 @@ var glob = require('glob'); var fs = require('fs'); -var pty = require('pty.js'); +var pty = require('node-pty'); var sleep = require('sleep'); var Terminal = require('../xterm'); From 081fe3f301a9146ae7bc20e4392a7f012496314e Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sat, 31 Dec 2016 11:52:26 +0200 Subject: [PATCH 03/12] Fix #359 - Introduce build system based on Gulp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Gulp and new dependencies to `package.json` - Add `gulpfile.js` with four tasks: - `tsc`: For building TypeScript sources - `bundle`: For bundling JavaScript modules in a monolith - `sorcery`: For resolving the source map chains back to the original TypeScript files - `build` (`default`): Runs the whole `tsc` → `bundle` → `sorcery` chain - Clean up `Dockerfile`, since `cpio` is not needed any more - Clean up not needed dependencies from `package.json` - Remove `bin/build` - Update `bin/release` to use `npm run build` instead of `./bin/build` --- Dockerfile | 5 --- bin/build | 36 ------------------- bin/prepare-release | 2 +- gulpfile.js | 87 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 14 ++++++-- src/xterm.js | 12 +++---- tsconfig.json | 8 +++-- 7 files changed, 111 insertions(+), 53 deletions(-) delete mode 100755 bin/build create mode 100644 gulpfile.js diff --git a/Dockerfile b/Dockerfile index 36e821bd..1f0db1f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,6 @@ FROM node:6.9 MAINTAINER Paris Kasidiaris -# Install cpio, used for building -RUN apt-get update \ - && apt-get install -y --no-install-recommends cpio \ - && rm -rf /var/lib/apt/lists/* - # Set the working directory WORKDIR /usr/src/app diff --git a/bin/build b/bin/build deleted file mode 100755 index a01a1b9f..00000000 --- a/bin/build +++ /dev/null @@ -1,36 +0,0 @@ -#! /usr/bin/env bash - -set -e - -# $BUILD_DIR should default to "build" -BUILD_DIR=${BUILD_DIR:=build} - -# Create the build directory -mkdir -p $BUILD_DIR - - -# Clean lib/* to prevent confusion if files were deleted in src/ -rm -rf lib/* - -# Build all TypeScript files (including tests) to lib/ -tsc - -# Concat all xterm.js files into a single file and output as a UMD to $BUILD_DIR/xterm.js -browserify ./lib/xterm.js --standalone Terminal --debug --outfile ./$BUILD_DIR/xterm.js -cat ./$BUILD_DIR/xterm.js | exorcist ./$BUILD_DIR/xterm.js.map -b ./$BUILD_DIR > ./$BUILD_DIR/xterm.temp.js -rm ./$BUILD_DIR/xterm.js -mv ./$BUILD_DIR/xterm.temp.js ./$BUILD_DIR/xterm.js - -# Resolve the chain of sourcemaps so that ./$BUILD_DIR/xterm.js.map points at ./src -sorcery -i $BUILD_DIR/xterm.js - -# Copy all CSS files from src/ to $BUILD_DIR/ and lib/ -cd src -find . -name '*.css' | cpio -pdm ../$BUILD_DIR -find . -name '*.css' | cpio -pdm ../lib -cd .. - -# Copy addons from lib/ to $BUILD_DIR/ -cd lib/addons -find . -name '*.js' | cpio -pdm ../../$BUILD_DIR/addons -cd ../.. diff --git a/bin/prepare-release b/bin/prepare-release index 6bd39d3d..464e65b4 100755 --- a/bin/prepare-release +++ b/bin/prepare-release @@ -21,7 +21,7 @@ CURRENT_BOWER_JSON_VERSION=$(cat bower.json \ # Build xterm.js into `dist` export BUILD_DIR=dist -./bin/build +npm run build # Update AUTHORS file sh bin/generate-authors diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 00000000..144b8831 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,87 @@ +const browserify = require('browserify'); +const buffer = require('vinyl-buffer'); +const fs = require('fs-extra'); +const gulp = require('gulp'); +const merge = require('merge-stream'); +const sorcery = require('sorcery'); +const source = require('vinyl-source-stream'); +const sourcemaps = require('gulp-sourcemaps'); +const ts = require('gulp-typescript'); +const tsify = require('tsify'); + + +let buildDir = process.env.BUILD_DIR || 'build'; + + +/** + * Compile TypeScript sources to JavaScript files and create a source map file for each TypeScript + * file compiled. + */ +gulp.task('tsc', function () { + // Remove the lib/ directory to prevent confusion if files were deleted in src/ + fs.emptyDirSync('lib'); + + // Build all TypeScript files (including tests) to lib/, based on the configuration defined in + // `tsconfig.json`. + let tsProject = ts.createProject('tsconfig.json'); + let tsResult = tsProject.src().pipe(sourcemaps.init()).pipe(tsProject()); + let tsc = tsResult.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest('lib')); + + // Copy all addons from src/ to lib/ + let copyAddons = gulp.src('src/addons/**/*').pipe(gulp.dest('lib/addons')); + + // Copy stylesheets from src/ to lib/ + let copyStylesheets = gulp.src('src/**/*.css').pipe(gulp.dest('lib')); + + return merge(tsc, copyAddons, copyStylesheets); +}); + +/** + * Bundle JavaScript files produced by the `tsc` task, into a single file named `xterm.js` with + * Browserify. + */ +gulp.task('browserify', ['tsc'], function() { + // Ensure that the build directory exists + fs.ensureDirSync(buildDir); + + let browserifyOptions = { + basedir: buildDir, + debug: true, + entries: ['../lib/xterm.js'], + standalone: 'Terminal', + cache: {}, + packageCache: {} + }; + let bundleStream = browserify(browserifyOptions) + .plugin(tsify) + .bundle() + .pipe(source('xterm.js')) + .pipe(buffer()) + .pipe(sourcemaps.init({loadMaps: true, sourceRoot: '..'})) + .pipe(sourcemaps.write('./')) + .pipe(gulp.dest(buildDir)); + + // Copy all add-ons from lib/ to buildDir + let copyAddons = gulp.src('lib/addons/**/*').pipe(gulp.dest(`${buildDir}/addons`)); + + // Copy stylesheets from src/ to lib/ + let copyStylesheets = gulp.src('lib/**/*.css').pipe(gulp.dest(buildDir)); + + return merge(bundleStream, copyAddons, copyStylesheets); +}); + + +/** + * Use `sorcery` to resolve the source map chain and point back to the TypeScript files. + * (Without this task the source maps produced for the JavaScript bundle points into the + * compiled JavaScript files in lib/). + */ +gulp.task('sorcery', ['browserify'], function () { + var chain = sorcery.loadSync(`${buildDir}/xterm.js`); + var map = chain.apply(); + chain.writeSync(); +}); + +gulp.task('build', ['sorcery']); + +gulp.task('default', ['build']); diff --git a/package.json b/package.json index 734bb6fb..d5071a70 100644 --- a/package.json +++ b/package.json @@ -38,18 +38,26 @@ "browserify": "^13.1.0", "chai": "3.5.0", "docdash": "0.4.0", - "exorcist": "^0.4.0", "express": "4.13.4", "express-ws": "2.0.0-rc.1", + "fs-extra": "^1.0.0", "glob": "^7.0.5", + "gulp": "^3.9.1", + "gulp-cli": "^1.2.2", + "gulp-sourcemaps": "^1.9.1", + "gulp-typescript": "^3.1.3", "jsdoc": "3.4.3", + "merge-stream": "^1.0.1", "mocha": "2.5.3", "nodemon": "1.10.2", "pty.js": "0.3.1", "sleep": "^3.0.1", "sorcery": "^0.10.0", + "tsify": "^3.0.0", "tslint": "^4.0.2", - "typescript": "^2.0.3" + "typescript": "^2.0.3", + "vinyl-buffer": "^1.0.0", + "vinyl-source-stream": "^1.1.0" }, "scripts": { "prestart": "npm run build", @@ -58,7 +66,7 @@ "lint": "tslint src/**/*.ts", "test": "mocha --recursive ./lib", "build:docs": "jsdoc -c jsdoc.json", - "build": "./bin/build", + "build": "gulp build", "prepublish": "npm run build" } } diff --git a/src/xterm.js b/src/xterm.js index b6c659c3..2fcf5073 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -10,13 +10,13 @@ * @license MIT */ -import { CompositionHelper } from './CompositionHelper.js'; -import { EventEmitter } from './EventEmitter.js'; -import { Viewport } from './Viewport.js'; -import { rightClickHandler, pasteHandler, copyHandler } from './handlers/Clipboard.js'; -import { CircularList } from './utils/CircularList.js'; +import { CompositionHelper } from './CompositionHelper'; +import { EventEmitter } from './EventEmitter'; +import { Viewport } from './Viewport'; +import { rightClickHandler, pasteHandler, copyHandler } from './handlers/Clipboard'; +import { CircularList } from './utils/CircularList'; import { C0 } from './EscapeSequences'; -import { CharMeasure } from './utils/CharMeasure.js'; +import { CharMeasure } from './utils/CharMeasure'; import * as Browser from './utils/Browser'; import * as Keyboard from './utils/Keyboard'; diff --git a/tsconfig.json b/tsconfig.json index f4a5a1b2..f5a7d66c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,13 +7,17 @@ "outDir": "lib", "sourceMap": true }, + "include": [ + "src/**/*" + ], "exclude": [ - "addons", + "src/addons/**/*", "build", "demo", "dist", "out", "test", - "node_modules" + "node_modules", + "docs" ] } From 0f5f34e8f5367f10dc9fcf5a489f62f209f066cb Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 12 Jan 2017 10:47:57 -0800 Subject: [PATCH 04/12] Move CharMeasure element to the helper container Fixes #470 --- src/xterm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xterm.js b/src/xterm.js index b6c659c3..b92736a9 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -614,7 +614,7 @@ Terminal.prototype.open = function(parent) { } this.parent.appendChild(this.element); - this.charMeasure = new CharMeasure(this.rowContainer); + this.charMeasure = new CharMeasure(this.helperContainer); this.charMeasure.on('charsizechanged', function () { self.updateCharSizeCSS(); }); From 23169e89c8c65464c8bf16374e07b4e7669b843c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 12 Jan 2017 11:14:14 -0800 Subject: [PATCH 05/12] Add null checks to refresh line and character fetches Fixes #473 --- src/xterm.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/xterm.js b/src/xterm.js index b6c659c3..a46d0152 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -1139,6 +1139,10 @@ Terminal.prototype.refresh = function(start, end) { row = y + this.ydisp; line = this.lines.get(row); + if (!line) { + // Continue if the line is not available, this means a resize is currently in progress + continue; + } out = ''; if (this.y === y - (this.ybase - this.ydisp) @@ -1153,6 +1157,10 @@ Terminal.prototype.refresh = function(start, end) { i = 0; for (; i < width; i++) { + if (!line[i]) { + // Continue if the character is not available, this means a resize is currently in progress + continue; + } data = line[i][0]; ch = line[i][1]; ch_width = line[i][2]; From 3de3912b96dce8ef1d900108cd64412ea19eb11a Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 12 Jan 2017 11:23:17 -0800 Subject: [PATCH 06/12] Add another null check on children[y] --- src/xterm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xterm.js b/src/xterm.js index a46d0152..b01421b1 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -1139,7 +1139,7 @@ Terminal.prototype.refresh = function(start, end) { row = y + this.ydisp; line = this.lines.get(row); - if (!line) { + if (!line || !this.children[y]) { // Continue if the line is not available, this means a resize is currently in progress continue; } From 5a932b2a20db211cc687776d4431e60ffc083c05 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 Jan 2017 21:27:19 -0800 Subject: [PATCH 07/12] Apply scrollback via setOption Fixes #476 --- demo/index.html | 7 ++++++- demo/main.js | 10 +++++++--- src/xterm.js | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/demo/index.html b/demo/index.html index 285fe002..764c8442 100644 --- a/demo/index.html +++ b/demo/index.html @@ -16,7 +16,12 @@

Options

- +

+ +

+

+ +

Size

diff --git a/demo/main.js b/demo/main.js index 86fbd314..52da2cef 100644 --- a/demo/main.js +++ b/demo/main.js @@ -8,7 +8,8 @@ var term, var terminalContainer = document.getElementById('terminal-container'), optionElements = { - cursorBlink: document.querySelector('#option-cursor-blink') + cursorBlink: document.querySelector('#option-cursor-blink'), + scrollback: document.querySelector('#option-scrollback') }, colsElement = document.getElementById('cols'), rowsElement = document.getElementById('rows'); @@ -28,6 +29,9 @@ colsElement.addEventListener('change', setTerminalSize); rowsElement.addEventListener('change', setTerminalSize); optionElements.cursorBlink.addEventListener('change', createTerminal); +optionElements.scrollback.addEventListener('change', function () { + terminal.setOption('scrollback', parseInt(optionElements.scrollback.value, 10)); +}); createTerminal(); @@ -37,7 +41,8 @@ function createTerminal() { terminalContainer.removeChild(terminalContainer.children[0]); } term = new Terminal({ - cursorBlink: optionElements.cursorBlink.checked + cursorBlink: optionElements.cursorBlink.checked, + scrollback: parseInt(optionElements.scrollback.value, 10) }); term.on('resize', function (size) { if (!pid) { @@ -78,7 +83,6 @@ function createTerminal() { }); } - function runRealTerminal() { term.attach(socket); term._initialized = true; diff --git a/src/xterm.js b/src/xterm.js index b6c659c3..5881e131 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -405,6 +405,24 @@ Terminal.prototype.setOption = function(key, value) { if (!(key in Terminal.defaults)) { throw new Error('No option with key "' + key + '"'); } + switch (key) { + case 'scrollback': + if (this.options[key] !== value) { + if (this.lines.length > value) { + const amountToTrim = this.lines.length - value; + const needsRefresh = (this.ydisp - amountToTrim < 0); + this.lines.trimStart(amountToTrim); + this.ybase = Math.max(this.ybase - amountToTrim, 0); + this.ydisp = Math.max(this.ydisp - amountToTrim, 0); + if (needsRefresh) { + this.refresh(0, this.rows - 1); + } + } + this.lines.maxLength = value; + this.viewport.syncScrollArea(); + } + break; + } this[key] = value; this.options[key] = value; }; From 7679475bfe0452446bb8eadaaa09dbe7e7d65b88 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 13 Jan 2017 21:31:31 -0800 Subject: [PATCH 08/12] Apply cursorBlink via setOption Fixes #478 --- demo/main.js | 4 +++- src/xterm.js | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/demo/main.js b/demo/main.js index 86fbd314..7425c051 100644 --- a/demo/main.js +++ b/demo/main.js @@ -27,7 +27,9 @@ function setTerminalSize () { colsElement.addEventListener('change', setTerminalSize); rowsElement.addEventListener('change', setTerminalSize); -optionElements.cursorBlink.addEventListener('change', createTerminal); +optionElements.cursorBlink.addEventListener('change', function () { + term.setOption('cursorBlink', optionElements.cursorBlink.checked); +}); createTerminal(); diff --git a/src/xterm.js b/src/xterm.js index b6c659c3..482d69a1 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -407,6 +407,9 @@ Terminal.prototype.setOption = function(key, value) { } this[key] = value; this.options[key] = value; + switch (key) { + case 'cursorBlink': this.refresh(this.y, this.y); break; + } }; /** From ac6faf3dd892314ee56ee416219ba8620c41e544 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sat, 14 Jan 2017 19:52:07 +0200 Subject: [PATCH 09/12] Stick gulp-sourcemaps to 1.9.1 Paths became absolute by default at https://github.com/floridoo/gulp-sourcemaps/commit/fb4027a496898b8b7992ea5af9b3d707f1d82d38 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d5071a70..2a043a85 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "glob": "^7.0.5", "gulp": "^3.9.1", "gulp-cli": "^1.2.2", - "gulp-sourcemaps": "^1.9.1", + "gulp-sourcemaps": "1.9.1", "gulp-typescript": "^3.1.3", "jsdoc": "3.4.3", "merge-stream": "^1.0.1", From d1dac57f7af5017b4b96696dc8722480fac2905e Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 14 Jan 2017 21:26:49 -0800 Subject: [PATCH 10/12] Move cursor blink style to class on .terminal --- src/xterm.css | 6 +++--- src/xterm.js | 9 +++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/xterm.css b/src/xterm.css index 3f4f4bbe..4ef61fdf 100644 --- a/src/xterm.css +++ b/src/xterm.css @@ -82,11 +82,11 @@ background-color: transparent; } -.terminal.focus .terminal-cursor.blinking { - animation: blink-cursor 1.2s infinite step-end; +.terminal.focus.xterm-cursor-blink .terminal-cursor { + animation: cursor-blink 1.2s infinite step-end; } -@keyframes blink-cursor { +@keyframes cursor-blink { 0% { background-color: #fff; color: #000; diff --git a/src/xterm.js b/src/xterm.js index 482d69a1..a62033dd 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -408,7 +408,7 @@ Terminal.prototype.setOption = function(key, value) { this[key] = value; this.options[key] = value; switch (key) { - case 'cursorBlink': this.refresh(this.y, this.y); break; + case 'cursorBlink': this.element.classList.toggle('xterm-cursor-blink', value); break; } }; @@ -566,6 +566,7 @@ Terminal.prototype.open = function(parent) { this.element.classList.add('terminal'); this.element.classList.add('xterm'); this.element.classList.add('xterm-theme-' + this.theme); + this.element.classList.toggle('xterm-cursor-blink', this.options.cursorBlink); this.element.style.height this.element.setAttribute('tabindex', 0); @@ -1170,11 +1171,7 @@ Terminal.prototype.refresh = function(start, end) { } if (data !== this.defAttr) { if (data === -1) { - out += ''; + out += ''; } else { var classNames = []; From 12160a50cbd7b9c46485fa69fc75cf53d2458aff Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 15 Jan 2017 02:27:34 -0800 Subject: [PATCH 11/12] Fake xterm.element in tests --- src/test/test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/test.js b/src/test/test.js index 7c716b2a..4f9342e5 100644 --- a/src/test/test.js +++ b/src/test/test.js @@ -23,6 +23,11 @@ describe('xterm.js', function() { xterm.writeBuffer.push(data); xterm.innerWrite(); }; + xterm.element = { + classList: { + toggle: function(){} + } + }; }); describe('getOption', function() { From a05bb5023043b08f0d4508a634f1527e6e653d7f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 15 Jan 2017 21:41:42 -0800 Subject: [PATCH 12/12] Don't drop selection on modifier keyup Fixes #348 --- src/xterm.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/xterm.js b/src/xterm.js index 6649a033..ed415b31 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -525,7 +525,11 @@ Terminal.bindKeys = function(term) { term.keyPress(ev); }, true); - on(term.element, 'keyup', term.focus.bind(term)); + on(term.element, 'keyup', function(ev) { + if (!wasMondifierKeyOnlyEvent(ev)) { + term.focus(term); + } + }, true); on(term.textarea, 'keydown', function(ev) { term.keyDown(ev); @@ -4984,6 +4988,12 @@ Terminal.prototype.deleteColumns = function() { this.maxRange(); }; +function wasMondifierKeyOnlyEvent(ev) { + return ev.keyCode === 16 || // Shift + ev.keyCode === 17 || // Ctrl + ev.keyCode === 18; // Alt +} + /** * Character Sets */