From 081fe3f301a9146ae7bc20e4392a7f012496314e Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sat, 31 Dec 2016 11:52:26 +0200 Subject: [PATCH 1/6] 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 2/6] 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 3/6] 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 4/6] 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 5/6] 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 ac6faf3dd892314ee56ee416219ba8620c41e544 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sat, 14 Jan 2017 19:52:07 +0200 Subject: [PATCH 6/6] 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",