- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq install g++-4.8 ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export CXX=g++-4.8 ; fi
+ - npm install -g npm@5.1.0
env:
matrix:
- NPM_COMMAND=lint
const source = require('vinyl-source-stream');
const sourcemaps = require('gulp-sourcemaps');
const ts = require('gulp-typescript');
-
+const util = require('gulp-util');
let buildDir = process.env.BUILD_DIR || 'build';
let tsProject = ts.createProject('tsconfig.json');
.pipe(istanbul.writeReports());
});
+/**
+ * Run single test file by file name(without file extension). Example of the command:
+ * gulp mocha-test --test InputHandler.test
+ */
+gulp.task('mocha-test', ['instrument-test'], function () {
+ let testName = util.env.test;
+ util.log("Run test by Name: " + testName);
+ return gulp.src([`${outDir}/${testName}.js`, `${outDir}/**/${testName}.js`], {read: false})
+ .pipe(mocha())
+ .once('error', () => process.exit(1))
+ .pipe(istanbul.writeReports());
+});
+
/**
* 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 ${outDir}/).
*/
gulp.task('sorcery', ['browserify'], function () {
- var chain = sorcery.loadSync(`${buildDir}/xterm.js`);
+ let chain = sorcery.loadSync(`${buildDir}/xterm.js`);
chain.apply();
chain.writeSync();
});
{
"name": "xterm",
- "version": "2.8.0",
+ "version": "2.8.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
+ "array-differ": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
+ "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=",
+ "dev": true
+ },
"array-each": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
"integrity": "sha1-5zA08A3MH0CHYAj9IP6ud71LfC8=",
"dev": true
},
+ "array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+ "dev": true
+ },
"asn1": {
"version": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
"tweetnacl": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz"
}
},
+ "beeper": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz",
+ "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=",
+ "dev": true
+ },
"boom": {
"version": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
"supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
}
},
+ "clone": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz",
+ "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=",
+ "dev": true
+ },
+ "clone-stats": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
+ "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=",
+ "dev": true
+ },
"combined-stream": {
"version": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
"is-plain-object": "2.0.3"
}
},
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
"cross-spawn-async": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz",
}
}
},
+ "dateformat": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.0.0.tgz",
+ "integrity": "sha1-J0Pjq7XD/CRi5SfcpEXgTp9N7hc=",
+ "dev": true
+ },
"deep-is": {
"version": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
"integrity": "sha1-BcOlDYMYmYFpnuDAdtOjlQ237AA=",
"dev": true
},
+ "duplexer2": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
+ "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "1.1.14"
+ }
+ },
"duplexer3": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
"integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=",
"dev": true
},
+ "fancy-log": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.0.tgz",
+ "integrity": "sha1-Rb4X0Cu5kX1gzP/UmVyZnmyMmUg=",
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3",
+ "time-stamp": "1.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "2.2.1",
+ "escape-string-regexp": "1.0.5",
+ "has-ansi": "2.0.0",
+ "strip-ansi": "3.0.1",
+ "supports-color": "2.0.0"
+ }
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
"fast-levenshtein": {
"version": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
}
}
},
+ "glogg": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz",
+ "integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=",
+ "dev": true,
+ "requires": {
+ "sparkles": "1.0.0"
+ }
+ },
"graceful-readlink": {
"version": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
}
}
},
+ "gulp-util": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz",
+ "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=",
+ "dev": true,
+ "requires": {
+ "array-differ": "1.0.0",
+ "array-uniq": "1.0.3",
+ "beeper": "1.1.1",
+ "chalk": "1.1.3",
+ "dateformat": "2.0.0",
+ "fancy-log": "1.3.0",
+ "gulplog": "1.0.0",
+ "has-gulplog": "0.1.0",
+ "lodash._reescape": "3.0.0",
+ "lodash._reevaluate": "3.0.0",
+ "lodash._reinterpolate": "3.0.0",
+ "lodash.template": "3.6.2",
+ "minimist": "1.2.0",
+ "multipipe": "0.1.2",
+ "object-assign": "3.0.0",
+ "replace-ext": "0.0.1",
+ "through2": "2.0.3",
+ "vinyl": "0.5.3"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "2.2.1",
+ "escape-string-regexp": "1.0.5",
+ "has-ansi": "2.0.0",
+ "strip-ansi": "3.0.1",
+ "supports-color": "2.0.0"
+ }
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "gulplog": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
+ "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=",
+ "dev": true,
+ "requires": {
+ "glogg": "1.0.0"
+ }
+ },
"har-validator": {
"version": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
"integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=",
"ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz"
}
},
+ "has-gulplog": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
+ "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=",
+ "dev": true,
+ "requires": {
+ "sparkles": "1.0.0"
+ }
+ },
"hash-base": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz",
"integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=",
"dev": true
},
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ },
"is-my-json-valid": {
"version": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz",
"integrity": "sha1-k27do8o8IR/ZjzstPgjaQ/eykVs=",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
"dev": true
},
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ },
"isstream": {
"version": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"type-check": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz"
}
},
+ "lodash._basecopy": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
+ "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=",
+ "dev": true
+ },
+ "lodash._basetostring": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz",
+ "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=",
+ "dev": true
+ },
+ "lodash._basevalues": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz",
+ "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=",
+ "dev": true
+ },
+ "lodash._getnative": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
+ "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=",
+ "dev": true
+ },
+ "lodash._isiterateecall": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
+ "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=",
+ "dev": true
+ },
+ "lodash._reescape": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz",
+ "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=",
+ "dev": true
+ },
+ "lodash._reevaluate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz",
+ "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=",
+ "dev": true
+ },
+ "lodash._reinterpolate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=",
+ "dev": true
+ },
+ "lodash._root": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz",
+ "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=",
+ "dev": true
+ },
+ "lodash.escape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
+ "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=",
+ "dev": true,
+ "requires": {
+ "lodash._root": "3.0.1"
+ }
+ },
+ "lodash.isarguments": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+ "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=",
+ "dev": true
+ },
+ "lodash.isarray": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
+ "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
+ "dev": true
+ },
+ "lodash.keys": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
+ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
+ "dev": true,
+ "requires": {
+ "lodash._getnative": "3.9.1",
+ "lodash.isarguments": "3.1.0",
+ "lodash.isarray": "3.0.4"
+ }
+ },
+ "lodash.restparam": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
+ "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=",
+ "dev": true
+ },
"lodash.sortby": {
"version": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
"dev": true
},
+ "lodash.template": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
+ "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=",
+ "dev": true,
+ "requires": {
+ "lodash._basecopy": "3.0.1",
+ "lodash._basetostring": "3.0.1",
+ "lodash._basevalues": "3.0.0",
+ "lodash._isiterateecall": "3.0.9",
+ "lodash._reinterpolate": "3.0.0",
+ "lodash.escape": "3.2.0",
+ "lodash.keys": "3.1.2",
+ "lodash.restparam": "3.6.1",
+ "lodash.templatesettings": "3.1.1"
+ }
+ },
+ "lodash.templatesettings": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz",
+ "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=",
+ "dev": true,
+ "requires": {
+ "lodash._reinterpolate": "3.0.0",
+ "lodash.escape": "3.2.0"
+ }
+ },
"make-dir": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.0.0.tgz",
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
"dev": true
},
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ },
"mocha": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-3.4.2.tgz",
}
}
},
+ "multipipe": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
+ "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=",
+ "dev": true,
+ "requires": {
+ "duplexer2": "0.0.2"
+ }
+ },
"node-pty": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-0.4.1.tgz",
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
"dev": true
},
+ "object-assign": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
+ "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=",
+ "dev": true
+ },
"object.defaults": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
"dev": true
},
+ "process-nextick-args": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+ "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
+ "dev": true
+ },
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
"dev": true
},
+ "readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+ "dev": true,
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ }
+ },
"remove-trailing-separator": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz",
"integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=",
"dev": true
},
+ "replace-ext": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
+ "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=",
+ "dev": true
+ },
"request": {
"version": "https://registry.npmjs.org/request/-/request-2.79.0.tgz",
"integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=",
"integrity": "sha1-/YYxojvHgmvvXYcb24c3jJVkeCg=",
"dev": true
},
- "sleep": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/sleep/-/sleep-3.0.1.tgz",
- "integrity": "sha1-vk0XxXk2DgfgTtgXK6KxCmkFTfM=",
- "dev": true,
- "requires": {
- "nan": "2.6.2"
- },
- "dependencies": {
- "nan": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz",
- "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=",
- "dev": true
- }
- }
- },
"sntp": {
"version": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
}
}
},
+ "sparkles": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz",
+ "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=",
+ "dev": true
+ },
"sshpk": {
"version": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.2.tgz",
"integrity": "sha1-1agEziJpVRVjjnmNviMnPeBwpfo=",
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
"dev": true
},
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ },
"stringstream": {
"version": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
"execa": "0.4.0"
}
},
+ "through2": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "2.3.3",
+ "xtend": "4.0.1"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
+ "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "1.0.0",
+ "process-nextick-args": "1.0.7",
+ "safe-buffer": "5.1.1",
+ "string_decoder": "1.0.3",
+ "util-deprecate": "1.0.2"
+ }
+ },
+ "string_decoder": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.1.1"
+ }
+ },
+ "xtend": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
+ "dev": true
+ }
+ }
+ },
+ "time-stamp": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
+ "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=",
+ "dev": true
+ },
"tough-cookie": {
"version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",
"integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=",
"crypto-random-string": "1.0.0"
}
},
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
"verror": {
"version": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz",
"integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=",
"extsprintf": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"
}
},
+ "vinyl": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
+ "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=",
+ "dev": true,
+ "requires": {
+ "clone": "1.0.2",
+ "clone-stats": "0.0.1",
+ "replace-ext": "0.0.1"
+ }
+ },
"vinyl-buffer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/vinyl-buffer/-/vinyl-buffer-1.0.0.tgz",
"express-ws": "2.0.0-rc.1",
"fs-extra": "^1.0.0",
"glob": "^7.0.5",
- "gulp": "^3.9.1",
+ "gulp": "3.9.1",
"gulp-cli": "^1.2.2",
"gulp-coveralls": "^0.1.4",
"gulp-istanbul": "^1.1.1",
"gulp-mocha": "^3.0.1",
"gulp-sourcemaps": "1.9.1",
"gulp-typescript": "^3.1.3",
+ "gulp-util": "3.0.8",
"jsdoc": "3.4.3",
"jsdom": "^11.1.0",
"merge-stream": "^1.0.1",
--- /dev/null
+/**
+ * @license MIT
+ */
+import { assert } from 'chai';
+import { ITerminal } from './Interfaces';
+import { Buffer } from './Buffer';
+import { CircularList } from './utils/CircularList';
+
+describe('Buffer', () => {
+ let terminal: ITerminal;
+ let buffer: Buffer;
+
+ beforeEach(() => {
+ terminal = <any>{
+ cols: 80,
+ rows: 24,
+ scrollback: 1000
+ };
+ buffer = new Buffer(terminal);
+ });
+
+ describe('constructor', () => {
+ it('should create a CircularList with max length equal to scrollback, for its lines', () => {
+ assert.instanceOf(buffer.lines, CircularList);
+ assert.equal(buffer.lines.maxLength, terminal.scrollback);
+ });
+ it('should set the Buffer\'s scrollBottom value equal to the terminal\'s rows -1', () => {
+ assert.equal(buffer.scrollBottom, terminal.rows - 1);
+ });
+ });
+});
--- /dev/null
+/**
+ * @license MIT
+ */
+
+import { ITerminal } from './Interfaces';
+import { CircularList } from './utils/CircularList';
+
+/**
+ * This class represents a terminal buffer (an internal state of the terminal), where the
+ * following information is stored (in high-level):
+ * - text content of this particular buffer
+ * - cursor position
+ * - scroll position
+ */
+export class Buffer {
+ public lines: CircularList<[number, string, number][]>;
+
+ /**
+ * Create a new Buffer.
+ * @param {Terminal} terminal - The terminal the Buffer will belong to
+ * @param {number} ydisp - The scroll position of the Buffer in the viewport
+ * @param {number} ybase - The scroll position of the y cursor (ybase + y = the y position within the Buffer)
+ * @param {number} y - The cursor's y position after ybase
+ * @param {number} x - The cursor's x position after ybase
+ */
+ constructor(
+ private terminal: ITerminal,
+ public ydisp: number = 0,
+ public ybase: number = 0,
+ public y: number = 0,
+ public x: number = 0,
+ public scrollBottom: number = 0,
+ public scrollTop: number = 0,
+ public tabs: any = {},
+ ) {
+ this.lines = new CircularList<[number, string, number][]>(this.terminal.scrollback);
+ this.scrollBottom = this.terminal.rows - 1;
+ }
+}
--- /dev/null
+/**
+ * @license MIT
+ */
+import { assert } from 'chai';
+import { ITerminal } from './Interfaces';
+import { BufferSet } from './BufferSet';
+import { Buffer } from './Buffer';
+
+describe('BufferSet', () => {
+ let terminal: ITerminal;
+ let bufferSet: BufferSet;
+
+ beforeEach(() => {
+ terminal = <any>{
+ cols: 80,
+ rows: 24,
+ scrollback: 1000
+ };
+ bufferSet = new BufferSet(terminal);
+ });
+
+ describe('constructor', () => {
+ it('should create two different buffers: alt and normal', () => {
+ assert.instanceOf(bufferSet.normal, Buffer);
+ assert.instanceOf(bufferSet.alt, Buffer);
+ assert.notEqual(bufferSet.normal, bufferSet.alt);
+ });
+ });
+
+ describe('activateNormalBuffer', () => {
+ beforeEach(() => {
+ bufferSet.activateNormalBuffer();
+ });
+
+ it('should set the normal buffer as the currently active buffer', () => {
+ assert.equal(bufferSet.active, bufferSet.normal);
+ });
+ });
+
+ describe('activateAltBuffer', () => {
+ beforeEach(() => {
+ bufferSet.activateAltBuffer();
+ });
+
+ it('should set the alt buffer as the currently active buffer', () => {
+ assert.equal(bufferSet.active, bufferSet.alt);
+ });
+ });
+});
--- /dev/null
+/**
+ * @license MIT
+ */
+
+import { ITerminal, IBufferSet } from './Interfaces';
+import { Buffer } from './Buffer';
+import { EventEmitter } from './EventEmitter';
+
+/**
+ * The BufferSet represents the set of two buffers used by xterm terminals (normal and alt) and
+ * provides also utilities for working with them.
+ */
+export class BufferSet extends EventEmitter implements IBufferSet {
+ private _normal: Buffer;
+ private _alt: Buffer;
+ private _activeBuffer: Buffer;
+
+ /**
+ * Create a new BufferSet for the given terminal.
+ * @param {Terminal} terminal - The terminal the BufferSet will belong to
+ */
+ constructor(private _terminal: ITerminal) {
+ super();
+ this._normal = new Buffer(this._terminal);
+ this._alt = new Buffer(this._terminal);
+ this._activeBuffer = this._normal;
+ }
+
+ /**
+ * Returns the alt Buffer of the BufferSet
+ * @returns {Buffer}
+ */
+ public get alt(): Buffer {
+ return this._alt;
+ }
+
+ /**
+ * Returns the normal Buffer of the BufferSet
+ * @returns {Buffer}
+ */
+ public get active(): Buffer {
+ return this._activeBuffer;
+ }
+
+ /**
+ * Returns the currently active Buffer of the BufferSet
+ * @returns {Buffer}
+ */
+ public get normal(): Buffer {
+ return this._normal;
+ }
+
+ /**
+ * Sets the normal Buffer of the BufferSet as its currently active Buffer
+ */
+ public activateNormalBuffer(): void {
+ this._activeBuffer = this._normal;
+ this.emit('activate', this._normal);
+ }
+
+ /**
+ * Sets the alt Buffer of the BufferSet as its currently active Buffer
+ */
+ public activateAltBuffer(): void {
+ this._activeBuffer = this._alt;
+ this.emit('activate', this._alt);
+ }
+}
* @license MIT
*/
+import { IEventEmitter } from './Interfaces';
+
interface ListenerType {
(): void;
listener?: () => void;
};
-export class EventEmitter {
+export class EventEmitter implements IEventEmitter {
private _events: {[type: string]: ListenerType[]};
constructor() {
char = this._terminal.charset[char];
}
- let row = this._terminal.y + this._terminal.ybase;
+ let row = this._terminal.buffer.y + this._terminal.buffer.ybase;
// insert combining char in last cell
// FIXME: needs handling after cursor jumps
- if (!ch_width && this._terminal.x) {
+ if (!ch_width && this._terminal.buffer.x) {
// dont overflow left
- if (this._terminal.lines.get(row)[this._terminal.x - 1]) {
- if (!this._terminal.lines.get(row)[this._terminal.x - 1][2]) {
+ if (this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1]) {
+ if (!this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1][2]) {
// found empty cell after fullwidth, need to go 2 cells back
- if (this._terminal.lines.get(row)[this._terminal.x - 2])
- this._terminal.lines.get(row)[this._terminal.x - 2][1] += char;
+ if (this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2])
+ this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2][1] += char;
} else {
- this._terminal.lines.get(row)[this._terminal.x - 1][1] += char;
+ this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1][1] += char;
}
- this._terminal.updateRange(this._terminal.y);
+ this._terminal.updateRange(this._terminal.buffer.y);
}
return;
}
// goto next line if ch would overflow
// TODO: needs a global min terminal width of 2
- if (this._terminal.x + ch_width - 1 >= this._terminal.cols) {
+ if (this._terminal.buffer.x + ch_width - 1 >= this._terminal.cols) {
// autowrap - DECAWM
if (this._terminal.wraparoundMode) {
- this._terminal.x = 0;
- this._terminal.y++;
- if (this._terminal.y > this._terminal.scrollBottom) {
- // Insert a new line, scroll and mark as a wrapped line
- this._terminal.y--;
+ this._terminal.buffer.x = 0;
+ this._terminal.buffer.y++;
+ if (this._terminal.buffer.y > this._terminal.buffer.scrollBottom) {
+ this._terminal.buffer.y--;
this._terminal.scroll(true);
} else {
// The line already exists (eg. the initial viewport), mark it as a
// wrapped line
- this._terminal.lines.get(this._terminal.y).isWrapped = true;
+ this._terminal.buffer.lines.get(this._terminal.buffer.y).isWrapped = true;
}
} else {
if (ch_width === 2) // FIXME: check for xterm behavior
return;
}
}
- row = this._terminal.y + this._terminal.ybase;
+ row = this._terminal.buffer.y + this._terminal.buffer.ybase;
// insert mode: move characters to right
if (this._terminal.insertMode) {
for (let moves = 0; moves < ch_width; ++moves) {
// remove last cell, if it's width is 0
// we have to adjust the second last cell as well
- const removed = this._terminal.lines.get(this._terminal.y + this._terminal.ybase).pop();
+ const removed = this._terminal.buffer.lines.get(this._terminal.buffer.y + this._terminal.buffer.ybase).pop();
if (removed[2] === 0
- && this._terminal.lines.get(row)[this._terminal.cols - 2]
- && this._terminal.lines.get(row)[this._terminal.cols - 2][2] === 2) {
- this._terminal.lines.get(row)[this._terminal.cols - 2] = [this._terminal.curAttr, ' ', 1];
+ && this._terminal.buffer.lines.get(row)[this._terminal.cols - 2]
+ && this._terminal.buffer.lines.get(row)[this._terminal.cols - 2][2] === 2) {
+ this._terminal.buffer.lines.get(row)[this._terminal.cols - 2] = [this._terminal.curAttr, ' ', 1];
}
// insert empty cell at cursor
- this._terminal.lines.get(row).splice(this._terminal.x, 0, [this._terminal.curAttr, ' ', 1]);
+ this._terminal.buffer.lines.get(row).splice(this._terminal.buffer.x, 0, [this._terminal.curAttr, ' ', 1]);
}
}
- this._terminal.lines.get(row)[this._terminal.x] = [this._terminal.curAttr, char, ch_width];
- this._terminal.x++;
- this._terminal.updateRange(this._terminal.y);
+ this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, char, ch_width];
+ 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) {
- this._terminal.lines.get(row)[this._terminal.x] = [this._terminal.curAttr, '', 0];
- this._terminal.x++;
+ this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, '', 0];
+ this._terminal.buffer.x++;
}
}
}
*/
public lineFeed(): void {
if (this._terminal.convertEol) {
- this._terminal.x = 0;
+ this._terminal.buffer.x = 0;
}
- this._terminal.y++;
- if (this._terminal.y > this._terminal.scrollBottom) {
- this._terminal.y--;
+ this._terminal.buffer.y++;
+ if (this._terminal.buffer.y > this._terminal.buffer.scrollBottom) {
+ this._terminal.buffer.y--;
this._terminal.scroll();
}
// If the end of the line is hit, prevent this action from wrapping around to the next line.
- if (this._terminal.x >= this._terminal.cols) {
- this._terminal.x--;
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x--;
}
}
* Carriage Return (Ctrl-M).
*/
public carriageReturn(): void {
- this._terminal.x = 0;
+ this._terminal.buffer.x = 0;
}
/**
* Backspace (Ctrl-H).
*/
public backspace(): void {
- if (this._terminal.x > 0) {
- this._terminal.x--;
+ if (this._terminal.buffer.x > 0) {
+ this._terminal.buffer.x--;
}
}
* Horizontal Tab (HT) (Ctrl-I).
*/
public tab(): void {
- this._terminal.x = this._terminal.nextStop();
+ this._terminal.buffer.x = this._terminal.nextStop();
}
/**
param = params[0];
if (param < 1) param = 1;
- row = this._terminal.y + this._terminal.ybase;
- j = this._terminal.x;
+ row = this._terminal.buffer.y + this._terminal.buffer.ybase;
+ j = this._terminal.buffer.x;
ch = [this._terminal.eraseAttr(), ' ', 1]; // xterm
while (param-- && j < this._terminal.cols) {
- this._terminal.lines.get(row).splice(j++, 0, ch);
- this._terminal.lines.get(row).pop();
+ this._terminal.buffer.lines.get(row).splice(j++, 0, ch);
+ this._terminal.buffer.lines.get(row).pop();
}
}
if (param < 1) {
param = 1;
}
- this._terminal.y -= param;
- if (this._terminal.y < 0) {
- this._terminal.y = 0;
+ this._terminal.buffer.y -= param;
+ if (this._terminal.buffer.y < 0) {
+ this._terminal.buffer.y = 0;
}
}
if (param < 1) {
param = 1;
}
- this._terminal.y += param;
- if (this._terminal.y >= this._terminal.rows) {
- this._terminal.y = this._terminal.rows - 1;
+ this._terminal.buffer.y += param;
+ if (this._terminal.buffer.y >= this._terminal.rows) {
+ this._terminal.buffer.y = this._terminal.rows - 1;
}
// If the end of the line is hit, prevent this action from wrapping around to the next line.
- if (this._terminal.x >= this._terminal.cols) {
- this._terminal.x--;
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x--;
}
}
if (param < 1) {
param = 1;
}
- this._terminal.x += param;
- if (this._terminal.x >= this._terminal.cols) {
- this._terminal.x = this._terminal.cols - 1;
+ this._terminal.buffer.x += param;
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x = this._terminal.cols - 1;
}
}
param = 1;
}
// If the end of the line is hit, prevent this action from wrapping around to the next line.
- if (this._terminal.x >= this._terminal.cols) {
- this._terminal.x--;
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x--;
}
- this._terminal.x -= param;
- if (this._terminal.x < 0) {
- this._terminal.x = 0;
+ this._terminal.buffer.x -= param;
+ if (this._terminal.buffer.x < 0) {
+ this._terminal.buffer.x = 0;
}
}
if (param < 1) {
param = 1;
}
- this._terminal.y += param;
- if (this._terminal.y >= this._terminal.rows) {
- this._terminal.y = this._terminal.rows - 1;
+ this._terminal.buffer.y += param;
+ if (this._terminal.buffer.y >= this._terminal.rows) {
+ this._terminal.buffer.y = this._terminal.rows - 1;
}
- this._terminal.x = 0;
+ this._terminal.buffer.x = 0;
};
if (param < 1) {
param = 1;
}
- this._terminal.y -= param;
- if (this._terminal.y < 0) {
- this._terminal.y = 0;
+ this._terminal.buffer.y -= param;
+ if (this._terminal.buffer.y < 0) {
+ this._terminal.buffer.y = 0;
}
- this._terminal.x = 0;
+ this._terminal.buffer.x = 0;
};
if (param < 1) {
param = 1;
}
- this._terminal.x = param - 1;
+ this._terminal.buffer.x = param - 1;
}
/**
col = this._terminal.cols - 1;
}
- this._terminal.x = col;
- this._terminal.y = row;
+ this._terminal.buffer.x = col;
+ this._terminal.buffer.y = row;
}
/**
public cursorForwardTab(params: number[]): void {
let param = params[0] || 1;
while (param--) {
- this._terminal.x = this._terminal.nextStop();
+ this._terminal.buffer.x = this._terminal.nextStop();
}
}
let j;
switch (params[0]) {
case 0:
- this._terminal.eraseRight(this._terminal.x, this._terminal.y);
- j = this._terminal.y + 1;
+ this._terminal.eraseRight(this._terminal.buffer.x, this._terminal.buffer.y);
+ j = this._terminal.buffer.y + 1;
for (; j < this._terminal.rows; j++) {
this._terminal.eraseLine(j);
}
break;
case 1:
- this._terminal.eraseLeft(this._terminal.x, this._terminal.y);
- j = this._terminal.y;
+ this._terminal.eraseLeft(this._terminal.buffer.x, this._terminal.buffer.y);
+ j = this._terminal.buffer.y;
while (j--) {
this._terminal.eraseLine(j);
}
break;
case 3:
// Clear scrollback (everything not in viewport)
- const scrollBackSize = this._terminal.lines.length - this._terminal.rows;
+ const scrollBackSize = this._terminal.buffer.lines.length - this._terminal.rows;
if (scrollBackSize > 0) {
- this._terminal.lines.trimStart(scrollBackSize);
- this._terminal.ybase = Math.max(this._terminal.ybase - scrollBackSize, 0);
- this._terminal.ydisp = Math.max(this._terminal.ydisp - scrollBackSize, 0);
+ this._terminal.buffer.lines.trimStart(scrollBackSize);
+ this._terminal.buffer.ybase = Math.max(this._terminal.buffer.ybase - scrollBackSize, 0);
+ this._terminal.buffer.ydisp = Math.max(this._terminal.buffer.ydisp - scrollBackSize, 0);
// Force a scroll event to refresh viewport
this._terminal.emit('scroll', 0);
}
public eraseInLine(params: number[]): void {
switch (params[0]) {
case 0:
- this._terminal.eraseRight(this._terminal.x, this._terminal.y);
+ this._terminal.eraseRight(this._terminal.buffer.x, this._terminal.buffer.y);
break;
case 1:
- this._terminal.eraseLeft(this._terminal.x, this._terminal.y);
+ this._terminal.eraseLeft(this._terminal.buffer.x, this._terminal.buffer.y);
break;
case 2:
- this._terminal.eraseLine(this._terminal.y);
+ this._terminal.eraseLine(this._terminal.buffer.y);
break;
}
}
if (param < 1) {
param = 1;
}
- row = this._terminal.y + this._terminal.ybase;
+ row = this._terminal.buffer.y + this._terminal.buffer.ybase;
- j = this._terminal.rows - 1 - this._terminal.scrollBottom;
- j = this._terminal.rows - 1 + this._terminal.ybase - j + 1;
+ j = this._terminal.rows - 1 - this._terminal.buffer.scrollBottom;
+ j = this._terminal.rows - 1 + this._terminal.buffer.ybase - j + 1;
while (param--) {
- if (this._terminal.lines.length === this._terminal.lines.maxLength) {
+ if (this._terminal.buffer.lines.length === this._terminal.buffer.lines.maxLength) {
// Trim the start of lines to make room for the new line
- this._terminal.lines.trimStart(1);
- this._terminal.ybase--;
- this._terminal.ydisp--;
+ this._terminal.buffer.lines.trimStart(1);
+ this._terminal.buffer.ybase--;
+ this._terminal.buffer.ydisp--;
row--;
j--;
}
// test: echo -e '\e[44m\e[1L\e[0m'
// blankLine(true) - xterm/linux behavior
- this._terminal.lines.splice(row, 0, this._terminal.blankLine(true));
- this._terminal.lines.splice(j, 1);
+ this._terminal.buffer.lines.splice(row, 0, this._terminal.blankLine(true));
+ this._terminal.buffer.lines.splice(j, 1);
}
// this.maxRange();
- this._terminal.updateRange(this._terminal.y);
- this._terminal.updateRange(this._terminal.scrollBottom);
+ this._terminal.updateRange(this._terminal.buffer.y);
+ this._terminal.updateRange(this._terminal.buffer.scrollBottom);
}
/**
if (param < 1) {
param = 1;
}
- row = this._terminal.y + this._terminal.ybase;
+ row = this._terminal.buffer.y + this._terminal.buffer.ybase;
- j = this._terminal.rows - 1 - this._terminal.scrollBottom;
- j = this._terminal.rows - 1 + this._terminal.ybase - j;
+ j = this._terminal.rows - 1 - this._terminal.buffer.scrollBottom;
+ j = this._terminal.rows - 1 + this._terminal.buffer.ybase - j;
while (param--) {
- if (this._terminal.lines.length === this._terminal.lines.maxLength) {
+ if (this._terminal.buffer.lines.length === this._terminal.buffer.lines.maxLength) {
// Trim the start of lines to make room for the new line
- this._terminal.lines.trimStart(1);
- this._terminal.ybase -= 1;
- this._terminal.ydisp -= 1;
+ this._terminal.buffer.lines.trimStart(1);
+ this._terminal.buffer.ybase -= 1;
+ this._terminal.buffer.ydisp -= 1;
}
// test: echo -e '\e[44m\e[1M\e[0m'
// blankLine(true) - xterm/linux behavior
- this._terminal.lines.splice(j + 1, 0, this._terminal.blankLine(true));
- this._terminal.lines.splice(row, 1);
+ this._terminal.buffer.lines.splice(j + 1, 0, this._terminal.blankLine(true));
+ this._terminal.buffer.lines.splice(row, 1);
}
// this.maxRange();
- this._terminal.updateRange(this._terminal.y);
- this._terminal.updateRange(this._terminal.scrollBottom);
+ this._terminal.updateRange(this._terminal.buffer.y);
+ this._terminal.updateRange(this._terminal.buffer.scrollBottom);
}
/**
param = 1;
}
- row = this._terminal.y + this._terminal.ybase;
+ row = this._terminal.buffer.y + this._terminal.buffer.ybase;
ch = [this._terminal.eraseAttr(), ' ', 1]; // xterm
while (param--) {
- this._terminal.lines.get(row).splice(this._terminal.x, 1);
- this._terminal.lines.get(row).push(ch);
+ this._terminal.buffer.lines.get(row).splice(this._terminal.buffer.x, 1);
+ this._terminal.buffer.lines.get(row).push(ch);
}
}
public scrollUp(params: number[]): void {
let param = params[0] || 1;
while (param--) {
- this._terminal.lines.splice(this._terminal.ybase + this._terminal.scrollTop, 1);
- this._terminal.lines.splice(this._terminal.ybase + this._terminal.scrollBottom, 0, this._terminal.blankLine());
+ this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollTop, 1);
+ this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollBottom, 0, this._terminal.blankLine());
}
// this.maxRange();
- this._terminal.updateRange(this._terminal.scrollTop);
- this._terminal.updateRange(this._terminal.scrollBottom);
+ this._terminal.updateRange(this._terminal.buffer.scrollTop);
+ this._terminal.updateRange(this._terminal.buffer.scrollBottom);
}
/**
public scrollDown(params: number[]): void {
let param = params[0] || 1;
while (param--) {
- this._terminal.lines.splice(this._terminal.ybase + this._terminal.scrollBottom, 1);
- this._terminal.lines.splice(this._terminal.ybase + this._terminal.scrollTop, 0, this._terminal.blankLine());
+ this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollBottom, 1);
+ this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollTop, 0, this._terminal.blankLine());
}
// this.maxRange();
- this._terminal.updateRange(this._terminal.scrollTop);
- this._terminal.updateRange(this._terminal.scrollBottom);
+ this._terminal.updateRange(this._terminal.buffer.scrollTop);
+ this._terminal.updateRange(this._terminal.buffer.scrollBottom);
}
/**
param = 1;
}
- row = this._terminal.y + this._terminal.ybase;
- j = this._terminal.x;
+ row = this._terminal.buffer.y + this._terminal.buffer.ybase;
+ j = this._terminal.buffer.x;
ch = [this._terminal.eraseAttr(), ' ', 1]; // xterm
while (param-- && j < this._terminal.cols) {
- this._terminal.lines.get(row)[j++] = ch;
+ this._terminal.buffer.lines.get(row)[j++] = ch;
}
}
public cursorBackwardTab(params: number[]): void {
let param = params[0] || 1;
while (param--) {
- this._terminal.x = this._terminal.prevStop();
+ this._terminal.buffer.x = this._terminal.prevStop();
}
}
if (param < 1) {
param = 1;
}
- this._terminal.x = param - 1;
- if (this._terminal.x >= this._terminal.cols) {
- this._terminal.x = this._terminal.cols - 1;
+ this._terminal.buffer.x = param - 1;
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x = this._terminal.cols - 1;
}
}
if (param < 1) {
param = 1;
}
- this._terminal.x += param;
- if (this._terminal.x >= this._terminal.cols) {
- this._terminal.x = this._terminal.cols - 1;
+ this._terminal.buffer.x += param;
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x = this._terminal.cols - 1;
}
}
*/
public repeatPrecedingCharacter(params: number[]): void {
let param = params[0] || 1
- , line = this._terminal.lines.get(this._terminal.ybase + this._terminal.y)
- , ch = line[this._terminal.x - 1] || [this._terminal.defAttr, ' ', 1];
+ , line = this._terminal.buffer.lines.get(this._terminal.buffer.ybase + this._terminal.buffer.y)
+ , ch = line[this._terminal.buffer.x - 1] || [this._terminal.defAttr, ' ', 1];
while (param--) {
- line[this._terminal.x++] = ch;
+ line[this._terminal.buffer.x++] = ch;
}
}
if (param < 1) {
param = 1;
}
- this._terminal.y = param - 1;
- if (this._terminal.y >= this._terminal.rows) {
- this._terminal.y = this._terminal.rows - 1;
+ this._terminal.buffer.y = param - 1;
+ if (this._terminal.buffer.y >= this._terminal.rows) {
+ this._terminal.buffer.y = this._terminal.rows - 1;
}
}
if (param < 1) {
param = 1;
}
- this._terminal.y += param;
- if (this._terminal.y >= this._terminal.rows) {
- this._terminal.y = this._terminal.rows - 1;
+ this._terminal.buffer.y += param;
+ if (this._terminal.buffer.y >= this._terminal.rows) {
+ this._terminal.buffer.y = this._terminal.rows - 1;
}
// If the end of the line is hit, prevent this action from wrapping around to the next line.
- if (this._terminal.x >= this._terminal.cols) {
- this._terminal.x--;
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x--;
}
}
if (params[0] < 1) params[0] = 1;
if (params[1] < 1) params[1] = 1;
- this._terminal.y = params[0] - 1;
- if (this._terminal.y >= this._terminal.rows) {
- this._terminal.y = this._terminal.rows - 1;
+ this._terminal.buffer.y = params[0] - 1;
+ if (this._terminal.buffer.y >= this._terminal.rows) {
+ this._terminal.buffer.y = this._terminal.rows - 1;
}
- this._terminal.x = params[1] - 1;
- if (this._terminal.x >= this._terminal.cols) {
- this._terminal.x = this._terminal.cols - 1;
+ this._terminal.buffer.x = params[1] - 1;
+ if (this._terminal.buffer.x >= this._terminal.cols) {
+ this._terminal.buffer.x = this._terminal.cols - 1;
}
}
public tabClear(params: number[]): void {
let param = params[0];
if (param <= 0) {
- delete this._terminal.tabs[this._terminal.x];
+ delete this._terminal.buffer.tabs[this._terminal.buffer.x];
} else if (param === 3) {
- this._terminal.tabs = {};
+ this._terminal.buffer.tabs = {};
}
}
this._terminal.cursorHidden = false;
break;
case 1049: // alt screen buffer cursor
- // this._terminal.saveCursor();
- ; // FALL-THROUGH
+ this.saveCursor(params);
+ // FALL-THROUGH
case 47: // alt screen buffer
case 1047: // alt screen buffer
- if (!this._terminal.normal) {
- let normal = {
- lines: this._terminal.lines,
- ybase: this._terminal.ybase,
- ydisp: this._terminal.ydisp,
- x: this._terminal.x,
- y: this._terminal.y,
- scrollTop: this._terminal.scrollTop,
- scrollBottom: this._terminal.scrollBottom,
- tabs: this._terminal.tabs
- // XXX save charset(s) here?
- // charset: this._terminal.charset,
- // glevel: this._terminal.glevel,
- // charsets: this._terminal.charsets
- };
- this._terminal.reset();
- this._terminal.viewport.syncScrollArea();
- this._terminal.normal = normal;
- this._terminal.showCursor();
- }
+ this._terminal.buffers.activateAltBuffer();
+ this._terminal.reset();
+ this._terminal.viewport.syncScrollArea();
+ this._terminal.showCursor();
break;
}
}
; // FALL-THROUGH
case 47: // normal screen buffer
case 1047: // normal screen buffer - clearing it first
- if (this._terminal.normal) {
- this._terminal.lines = this._terminal.normal.lines;
- this._terminal.ybase = this._terminal.normal.ybase;
- this._terminal.ydisp = this._terminal.normal.ydisp;
- this._terminal.x = this._terminal.normal.x;
- this._terminal.y = this._terminal.normal.y;
- this._terminal.scrollTop = this._terminal.normal.scrollTop;
- this._terminal.scrollBottom = this._terminal.normal.scrollBottom;
- this._terminal.tabs = this._terminal.normal.tabs;
- this._terminal.normal = null;
- // Ensure the selection manager has the correct buffer
- this._terminal.selectionManager.setBuffer(this._terminal.lines);
- // if (params === 1049) {
- // this.x = this.savedX;
- // this.y = this.savedY;
- // }
- this._terminal.refresh(0, this._terminal.rows - 1);
- this._terminal.viewport.syncScrollArea();
- this._terminal.showCursor();
+ // Ensure the selection manager has the correct buffer
+ this._terminal.buffers.activateNormalBuffer();
+ if (params[0] === 1049) {
+ this.restoreCursor(params);
}
+ this._terminal.selectionManager.setBuffer(this._terminal.buffer.lines);
+ this._terminal.refresh(0, this._terminal.rows - 1);
+ this._terminal.viewport.syncScrollArea();
+ this._terminal.showCursor();
break;
}
}
case 6:
// cursor position
this._terminal.send(C0.ESC + '['
- + (this._terminal.y + 1)
+ + (this._terminal.buffer.y + 1)
+ ';'
- + (this._terminal.x + 1)
+ + (this._terminal.buffer.x + 1)
+ 'R');
break;
}
case 6:
// cursor position
this._terminal.send(C0.ESC + '[?'
- + (this._terminal.y + 1)
+ + (this._terminal.buffer.y + 1)
+ ';'
- + (this._terminal.x + 1)
+ + (this._terminal.buffer.x + 1)
+ 'R');
break;
case 15:
this._terminal.applicationKeypad = false; // ?
this._terminal.viewport.syncScrollArea();
this._terminal.applicationCursor = false;
- this._terminal.scrollTop = 0;
- this._terminal.scrollBottom = this._terminal.rows - 1;
+ this._terminal.buffer.scrollTop = 0;
+ this._terminal.buffer.scrollBottom = this._terminal.rows - 1;
this._terminal.curAttr = this._terminal.defAttr;
- this._terminal.x = this._terminal.y = 0; // ?
+ this._terminal.buffer.x = this._terminal.buffer.y = 0; // ?
this._terminal.charset = null;
this._terminal.glevel = 0; // ??
this._terminal.charsets = [null]; // ??
*/
public setScrollRegion(params: number[]): void {
if (this._terminal.prefix) return;
- this._terminal.scrollTop = (params[0] || 1) - 1;
- this._terminal.scrollBottom = (params[1] && params[1] <= this._terminal.rows ? params[1] : this._terminal.rows) - 1;
- this._terminal.x = 0;
- this._terminal.y = 0;
+ this._terminal.buffer.scrollTop = (params[0] || 1) - 1;
+ this._terminal.buffer.scrollBottom = (params[1] && params[1] <= this._terminal.rows ? params[1] : this._terminal.rows) - 1;
+ this._terminal.buffer.x = 0;
+ this._terminal.buffer.y = 0;
}
* Save cursor (ANSI.SYS).
*/
public saveCursor(params: number[]): void {
- this._terminal.savedX = this._terminal.x;
- this._terminal.savedY = this._terminal.y;
+ this._terminal.buffers.active.x = this._terminal.buffer.x;
+ this._terminal.buffers.active.y = this._terminal.buffer.y;
}
* Restore cursor (ANSI.SYS).
*/
public restoreCursor(params: number[]): void {
- this._terminal.x = this._terminal.savedX || 0;
- this._terminal.y = this._terminal.savedY || 0;
+ this._terminal.buffer.x = this._terminal.buffers.active.x || 0;
+ this._terminal.buffer.y = this._terminal.buffers.active.y || 0;
}
}
selectionManager: ISelectionManager;
charMeasure: ICharMeasure;
textarea: HTMLTextAreaElement;
- ybase: number;
- ydisp: number;
- lines: ICircularList<string>;
rows: number;
cols: number;
browser: IBrowser;
children: HTMLElement[];
cursorHidden: boolean;
cursorState: number;
- x: number;
- y: number;
defAttr: number;
+ scrollback: number;
+ buffers: IBufferSet;
+ buffer: IBuffer;
/**
* Emit the 'data' event and populate the given data.
cancel(ev: Event, force?: boolean);
log(text: string): void;
emit(event: string, data: any);
+ reset(): void;
+ showCursor(): void;
+}
+
+export interface IBuffer {
+ lines: ICircularList<[number, string, number][]>;
+ ydisp: number;
+ ybase: number;
+ y: number;
+ x: number;
+ tabs: any;
+}
+
+export interface IBufferSet {
+ alt: IBuffer;
+ normal: IBuffer;
+ active: IBuffer;
+
+ activateNormalBuffer(): void;
+ activateAltBuffer(): void;
}
export interface ISelectionManager {
deregisterLinkMatcher(matcherId: number): boolean;
}
-interface ICircularList<T> {
+export interface ICircularList<T> extends IEventEmitter {
length: number;
maxLength: number;
shiftElements(start: number, count: number, offset: number): void;
}
+export interface IEventEmitter {
+ on(type, listener): void;
+ off(type, listener): void;
+}
+
export interface LinkMatcherOptions {
/**
* The index of the link from the regex.match(text) call. This defaults to 0
};
escapedStateHandler['E'] = (parser, terminal) => {
// ESC E Next Line ( NEL is 0x85).
- terminal.x = 0;
+ terminal.buffer.x = 0;
terminal.index();
parser.setState(ParserState.NORMAL);
};
// DECSTBM
case 'r':
pt = ''
- + (this._terminal.scrollTop + 1)
+ + (this._terminal.buffer.scrollTop + 1)
+ ';'
- + (this._terminal.scrollBottom + 1)
+ + (this._terminal.buffer.scrollBottom + 1)
+ 'r';
break;
}
for (; y <= end; y++) {
- let row = y + this._terminal.ydisp;
+ let row = y + this._terminal.buffer.ydisp;
- let line = this._terminal.lines.get(row);
+ let line = this._terminal.buffer.lines.get(row);
let x;
- if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp) &&
+ if (this._terminal.buffer.y === y - (this._terminal.buffer.ybase - this._terminal.buffer.ydisp) &&
this._terminal.cursorState &&
!this._terminal.cursorHidden) {
- x = this._terminal.x;
+ x = this._terminal.buffer.x;
} else {
x = -1;
}
}
// Translate from buffer position to viewport position
- const viewportStartRow = start[1] - this._terminal.ydisp;
- const viewportEndRow = end[1] - this._terminal.ydisp;
+ const viewportStartRow = start[1] - this._terminal.buffer.ydisp;
+ const viewportEndRow = end[1] - this._terminal.buffer.ydisp;
const viewportCappedStartRow = Math.max(viewportStartRow, 0);
const viewportCappedEndRow = Math.min(viewportEndRow, this._terminal.rows - 1);
*/
import jsdom = require('jsdom');
import { assert } from 'chai';
-import { ITerminal } from './Interfaces';
+import { ITerminal, ICircularList } from './Interfaces';
import { CharMeasure } from './utils/CharMeasure';
import { CircularList } from './utils/CircularList';
import { SelectionManager } from './SelectionManager';
import { SelectionModel } from './SelectionModel';
+import { BufferSet } from './BufferSet';
class TestSelectionManager extends SelectionManager {
constructor(
terminal: ITerminal,
- buffer: CircularList<any>,
+ buffer: ICircularList<[number, string, number][]>,
rowContainer: HTMLElement,
charMeasure: CharMeasure
) {
let document: Document;
let terminal: ITerminal;
- let buffer: CircularList<any>;
+ let bufferLines: ICircularList<[number, string, number][]>;
let rowContainer: HTMLElement;
let selectionManager: TestSelectionManager;
dom = new jsdom.JSDOM('');
window = dom.window;
document = window.document;
- buffer = new CircularList<any>(100);
terminal = <any>{ cols: 80, rows: 2 };
- selectionManager = new TestSelectionManager(terminal, buffer, rowContainer, null);
+ terminal.scrollback = 100;
+ terminal.buffers = new BufferSet(terminal);
+ terminal.buffer = terminal.buffers.active;
+ bufferLines = terminal.buffer.lines;
+ selectionManager = new TestSelectionManager(terminal, bufferLines, rowContainer, null);
});
function stringToRow(text: string): [number, string, number][] {
describe('_selectWordAt', () => {
it('should expand selection for normal width chars', () => {
- buffer.push(stringToRow('foo bar'));
+ bufferLines.push(stringToRow('foo bar'));
selectionManager.selectWordAt([0, 0]);
assert.equal(selectionManager.selectionText, 'foo');
selectionManager.selectWordAt([1, 0]);
assert.equal(selectionManager.selectionText, 'bar');
});
it('should expand selection for whitespace', () => {
- buffer.push(stringToRow('a b'));
+ bufferLines.push(stringToRow('a b'));
selectionManager.selectWordAt([0, 0]);
assert.equal(selectionManager.selectionText, 'a');
selectionManager.selectWordAt([1, 0]);
});
it('should expand selection for wide characters', () => {
// Wide characters use a special format
- buffer.push([
+ bufferLines.push([
[null, 'ä¸', 2],
[null, '', 0],
[null, 'æ–‡', 2],
assert.equal(selectionManager.selectionText, 'foo');
});
it('should select up to non-path characters that are commonly adjacent to paths', () => {
- buffer.push(stringToRow('(cd)[ef]{gh}\'ij"'));
+ bufferLines.push(stringToRow('(cd)[ef]{gh}\'ij"'));
selectionManager.selectWordAt([0, 0]);
assert.equal(selectionManager.selectionText, '(cd');
selectionManager.selectWordAt([1, 0]);
describe('_selectLineAt', () => {
it('should select the entire line', () => {
- buffer.push(stringToRow('foo bar'));
+ bufferLines.push(stringToRow('foo bar'));
selectionManager.selectLineAt(0);
assert.equal(selectionManager.selectionText, 'foo bar', 'The selected text is correct');
assert.deepEqual(selectionManager.model.finalSelectionStart, [0, 0]);
describe('selectAll', () => {
it('should select the entire buffer, beyond the viewport', () => {
- buffer.push(stringToRow('1'));
- buffer.push(stringToRow('2'));
- buffer.push(stringToRow('3'));
- buffer.push(stringToRow('4'));
- buffer.push(stringToRow('5'));
+ bufferLines.push(stringToRow('1'));
+ bufferLines.push(stringToRow('2'));
+ bufferLines.push(stringToRow('3'));
+ bufferLines.push(stringToRow('4'));
+ bufferLines.push(stringToRow('5'));
selectionManager.selectAll();
- terminal.ybase = buffer.length - terminal.rows;
+ terminal.buffer.ybase = bufferLines.length - terminal.rows;
assert.equal(selectionManager.selectionText, '1\n2\n3\n4\n5');
});
});
import { CharMeasure } from './utils/CharMeasure';
import { CircularList } from './utils/CircularList';
import { EventEmitter } from './EventEmitter';
-import { ITerminal } from './Interfaces';
+import { ITerminal, ICircularList } from './Interfaces';
import { SelectionModel } from './SelectionModel';
import { translateBufferLineToString } from './utils/BufferLine';
constructor(
private _terminal: ITerminal,
- private _buffer: CircularList<any>,
+ private _buffer: ICircularList<[number, string, number][]>,
private _rowContainer: HTMLElement,
private _charMeasure: CharMeasure
) {
* switched in or out.
* @param buffer The active buffer.
*/
- public setBuffer(buffer: CircularList<any>): void {
+ public setBuffer(buffer: ICircularList<[number, string, number][]>): void {
this._buffer = buffer;
this.clearSelection();
}
for (let i = start[1] + 1; i <= end[1] - 1; i++) {
const bufferLine = this._buffer.get(i);
const lineText = translateBufferLineToString(bufferLine, true);
- if (bufferLine.isWrapped) {
+ if ((<any>bufferLine).isWrapped) {
result[result.length - 1] += lineText;
} else {
result.push(lineText);
if (start[1] !== end[1]) {
const bufferLine = this._buffer.get(end[1]);
const lineText = translateBufferLineToString(bufferLine, true, 0, end[0]);
- if (bufferLine.isWrapped) {
+ if ((<any>bufferLine).isWrapped) {
result[result.length - 1] += lineText;
} else {
result.push(lineText);
coords[0]--;
coords[1]--;
// Convert viewport coords to buffer coords
- coords[1] += this._terminal.ydisp;
+ coords[1] += this._terminal.buffer.ydisp;
return coords;
}
this._terminal.scrollDisp(this._dragScrollAmount, false);
// Re-evaluate selection
if (this._dragScrollAmount > 0) {
- this._model.selectionEnd = [this._terminal.cols - 1, this._terminal.ydisp + this._terminal.rows];
+ this._model.selectionEnd = [this._terminal.cols - 1, this._terminal.buffer.ydisp + this._terminal.rows];
} else {
- this._model.selectionEnd = [0, this._terminal.ydisp];
+ this._model.selectionEnd = [0, this._terminal.buffer.ydisp];
}
this.refresh();
}
import { assert } from 'chai';
import { ITerminal } from './Interfaces';
import { SelectionModel } from './SelectionModel';
+import {BufferSet} from './BufferSet';
class TestSelectionModel extends SelectionModel {
constructor(
beforeEach(() => {
terminal = <any>{ cols: 80, rows: 2, ybase: 0 };
+ terminal.scrollback = 10;
+ terminal.buffers = new BufferSet(terminal);
+ terminal.buffer = terminal.buffers.active;
+
model = new TestSelectionModel(terminal);
});
*/
public get finalSelectionEnd(): [number, number] {
if (this.isSelectAllActive) {
- return [this._terminal.cols, this._terminal.ybase + this._terminal.rows - 1];
+ return [this._terminal.cols, this._terminal.buffer.ybase + this._terminal.rows - 1];
}
if (!this.selectionStart) {
import { assert } from 'chai';
import { Viewport } from './Viewport';
+import {BufferSet} from './BufferSet';
describe('Viewport', () => {
let terminal;
let viewportElement;
- let selectionContainer;
let charMeasure;
let viewport;
let scrollAreaElement;
beforeEach(() => {
terminal = {
- lines: [],
rows: 0,
ydisp: 0,
on: () => {},
style: {
height: 0
}
- }
+ },
+ scrollback: 10
};
+ terminal.buffers = new BufferSet(terminal);
+ terminal.buffer = terminal.buffers.active;
viewportElement = {
addEventListener: () => {},
style: {
}, 0);
});
it('should set the height of the viewport when the line-height changed', () => {
- terminal.lines.push('');
- terminal.lines.push('');
+ terminal.buffer.lines.push('');
+ terminal.buffer.lines.push('');
terminal.rows = 1;
viewport.refresh();
assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px');
- charMeasure.height = 20;
+ charMeasure.height = 2 * CHARACTER_HEIGHT;
viewport.refresh();
- assert.equal(viewportElement.style.height, 20 + 'px');
+ assert.equal(viewportElement.style.height, 2 * CHARACTER_HEIGHT + 'px');
});
});
it('should sync the scroll area', done => {
// Allow CharMeasure to be initialized
setTimeout(() => {
- terminal.lines.push('');
+ terminal.buffer.lines.push('');
terminal.rows = 1;
assert.equal(scrollAreaElement.style.height, 0 * CHARACTER_HEIGHT + 'px');
viewport.syncScrollArea();
assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px');
assert.equal(scrollAreaElement.style.height, 1 * CHARACTER_HEIGHT + 'px');
- terminal.lines.push('');
+ terminal.buffer.lines.push('');
viewport.syncScrollArea();
assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px');
assert.equal(scrollAreaElement.style.height, 2 * CHARACTER_HEIGHT + 'px');
* @param terminal The terminal this viewport belongs to.
* @param viewportElement The DOM element acting as the viewport.
* @param scrollArea The DOM element acting as the scroll area.
- * @param charMeasureElement A DOM element used to measure the character size of. the terminal.
+ * @param charMeasure A DOM element used to measure the character size of. the terminal.
*/
constructor(
private terminal: ITerminal,
/**
* Refreshes row height, setting line-height, viewport height and scroll area height if
* necessary.
- * @param charSize A character size measurement bounding rect object, if it doesn't exist it will
- * be created.
*/
private refresh(): void {
if (this.charMeasure.height > 0) {
* Updates dimensions and synchronizes the scroll area if necessary.
*/
public syncScrollArea(): void {
- if (this.lastRecordedBufferLength !== this.terminal.lines.length) {
+ if (this.lastRecordedBufferLength !== this.terminal.buffer.lines.length) {
// If buffer height changed
- this.lastRecordedBufferLength = this.terminal.lines.length;
+ this.lastRecordedBufferLength = this.terminal.buffer.lines.length;
this.refresh();
} else if (this.lastRecordedViewportHeight !== this.terminal.rows) {
// If viewport height changed
}
// Sync scrollTop
- const scrollTop = this.terminal.ydisp * this.currentRowHeight;
+ const scrollTop = this.terminal.buffer.ydisp * this.currentRowHeight;
if (this.viewportElement.scrollTop !== scrollTop) {
this.viewportElement.scrollTop = scrollTop;
}
*/
private onScroll(ev: Event) {
const newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight);
- const diff = newRow - this.terminal.ydisp;
+ const diff = newRow - this.terminal.buffer.ydisp;
this.terminal.scrollDisp(diff, true);
}
function terminalToString(term) {
var result = '';
var line_s = '';
- for (var line = term.ybase; line < term.ybase + term.rows; line++) {
+ for (var line = term.buffer.ybase; line < term.buffer.ybase + term.rows; line++) {
line_s = '';
for (var cell=0; cell<term.cols; ++cell) {
- line_s += term.lines.get(line)[cell][1];
+ line_s += term.buffer.lines.get(line)[cell][1];
}
// rtrim empty cells as xterm does
line_s = line_s.replace(/\s+$/, '');
describe('clear', function() {
it('should clear a buffer equal to rows', function() {
- var promptLine = xterm.lines.get(xterm.ybase + xterm.y);
+ var promptLine = xterm.buffer.lines.get(xterm.buffer.ybase + xterm.buffer.y);
xterm.clear();
- assert.equal(xterm.y, 0);
- assert.equal(xterm.ybase, 0);
- assert.equal(xterm.ydisp, 0);
- assert.equal(xterm.lines.length, xterm.rows);
- assert.deepEqual(xterm.lines.get(0), promptLine);
+ assert.equal(xterm.buffer.y, 0);
+ assert.equal(xterm.buffer.ybase, 0);
+ assert.equal(xterm.buffer.ydisp, 0);
+ assert.equal(xterm.buffer.lines.length, xterm.rows);
+ assert.deepEqual(xterm.buffer.lines.get(0), promptLine);
for (var i = 1; i < xterm.rows; i++) {
- assert.deepEqual(xterm.lines.get(i), xterm.blankLine());
+ assert.deepEqual(xterm.buffer.lines.get(i), xterm.blankLine());
}
});
it('should clear a buffer larger than rows', function() {
xterm.write('test\n');
}
- var promptLine = xterm.lines.get(xterm.ybase + xterm.y);
+ var promptLine = xterm.buffer.lines.get(xterm.buffer.ybase + xterm.buffer.y);
xterm.clear();
- assert.equal(xterm.y, 0);
- assert.equal(xterm.ybase, 0);
- assert.equal(xterm.ydisp, 0);
- assert.equal(xterm.lines.length, xterm.rows);
- assert.deepEqual(xterm.lines.get(0), promptLine);
+ assert.equal(xterm.buffer.y, 0);
+ assert.equal(xterm.buffer.ybase, 0);
+ assert.equal(xterm.buffer.ydisp, 0);
+ assert.equal(xterm.buffer.lines.length, xterm.rows);
+ assert.deepEqual(xterm.buffer.lines.get(0), promptLine);
for (var i = 1; i < xterm.rows; i++) {
- assert.deepEqual(xterm.lines.get(i), xterm.blankLine());
+ assert.deepEqual(xterm.buffer.lines.get(i), xterm.blankLine());
}
});
it('should not break the prompt when cleared twice', function() {
- var promptLine = xterm.lines.get(xterm.ybase + xterm.y);
+ var promptLine = xterm.buffer.lines.get(xterm.buffer.ybase + xterm.buffer.y);
xterm.clear();
xterm.clear();
- assert.equal(xterm.y, 0);
- assert.equal(xterm.ybase, 0);
- assert.equal(xterm.ydisp, 0);
- assert.equal(xterm.lines.length, xterm.rows);
- assert.deepEqual(xterm.lines.get(0), promptLine);
+ assert.equal(xterm.buffer.y, 0);
+ assert.equal(xterm.buffer.ybase, 0);
+ assert.equal(xterm.buffer.ydisp, 0);
+ assert.equal(xterm.buffer.lines.length, xterm.rows);
+ assert.deepEqual(xterm.buffer.lines.get(0), promptLine);
for (var i = 1; i < xterm.rows; i++) {
- assert.deepEqual(xterm.lines.get(i), xterm.blankLine());
+ assert.deepEqual(xterm.buffer.lines.get(i), xterm.blankLine());
}
});
});
startYDisp = xterm.rows + 1;
});
it('should scroll a single line', function() {
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
xterm.scrollDisp(-1);
- assert.equal(xterm.ydisp, startYDisp - 1);
+ assert.equal(xterm.buffer.ydisp, startYDisp - 1);
xterm.scrollDisp(1);
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
});
it('should scroll multiple lines', function() {
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
xterm.scrollDisp(-5);
- assert.equal(xterm.ydisp, startYDisp - 5);
+ assert.equal(xterm.buffer.ydisp, startYDisp - 5);
xterm.scrollDisp(5);
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
});
it('should not scroll beyond the bounds of the buffer', function() {
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
xterm.scrollDisp(1);
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
for (var i = 0; i < startYDisp; i++) {
xterm.scrollDisp(-1);
}
- assert.equal(xterm.ydisp, 0);
+ assert.equal(xterm.buffer.ydisp, 0);
xterm.scrollDisp(-1);
- assert.equal(xterm.ydisp, 0);
+ assert.equal(xterm.buffer.ydisp, 0);
});
});
startYDisp = (xterm.rows * 2) + 1;
});
it('should scroll a single page', function() {
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
xterm.scrollPages(-1);
- assert.equal(xterm.ydisp, startYDisp - (xterm.rows - 1));
+ assert.equal(xterm.buffer.ydisp, startYDisp - (xterm.rows - 1));
xterm.scrollPages(1);
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
});
it('should scroll a multiple pages', function() {
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
xterm.scrollPages(-2);
- assert.equal(xterm.ydisp, startYDisp - (xterm.rows - 1) * 2);
+ assert.equal(xterm.buffer.ydisp, startYDisp - (xterm.rows - 1) * 2);
xterm.scrollPages(2);
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
});
});
}
});
it('should scroll to the top', function() {
- assert.notEqual(xterm.ydisp, 0);
+ assert.notEqual(xterm.buffer.ydisp, 0);
xterm.scrollToTop();
- assert.equal(xterm.ydisp, 0);
+ assert.equal(xterm.buffer.ydisp, 0);
});
});
it('should scroll to the bottom', function() {
xterm.scrollDisp(-1);
xterm.scrollToBottom();
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
xterm.scrollPages(-1);
xterm.scrollToBottom();
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
xterm.scrollToTop();
xterm.scrollToBottom();
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
});
});
stopPropagation: function(){}
};
- xterm.ydisp = 0;
- xterm.ybase = 40;
- assert.notEqual(xterm.ydisp, xterm.ybase);
+ xterm.buffer.ydisp = 0;
+ xterm.buffer.ybase = 40;
+ assert.notEqual(xterm.buffer.ydisp, xterm.buffer.ybase);
xterm.keyDown(event);
// Ensure that now the terminal is scrolled to bottom
- assert.equal(xterm.ydisp, xterm.ybase);
+ assert.equal(xterm.buffer.ydisp, xterm.buffer.ybase);
});
it('should not scroll down, when a custom keydown handler prevents the event', function () {
return false;
});
- assert.equal(xterm.ydisp, startYDisp);
+ assert.equal(xterm.buffer.ydisp, startYDisp);
xterm.scrollDisp(-1);
- assert.equal(xterm.ydisp, startYDisp - 1);
+ assert.equal(xterm.buffer.ydisp, startYDisp - 1);
xterm.keyDown({ keyCode: 0 });
- assert.equal(xterm.ydisp, startYDisp - 1);
+ assert.equal(xterm.buffer.ydisp, startYDisp - 1);
});
});
});
var high = String.fromCharCode(0xD800);
for (var i=0xDC00; i<=0xDCFF; ++i) {
xterm.write(high + String.fromCharCode(i));
- var tchar = xterm.lines.get(0)[0];
+ var tchar = xterm.buffer.lines.get(0)[0];
expect(tchar[1]).eql(high + String.fromCharCode(i));
expect(tchar[1].length).eql(2);
expect(tchar[2]).eql(1);
- expect(xterm.lines.get(0)[1][1]).eql(' ');
+ expect(xterm.buffer.lines.get(0)[1][1]).eql(' ');
xterm.reset();
}
});
it('2 characters at last cell', function() {
var high = String.fromCharCode(0xD800);
for (var i=0xDC00; i<=0xDCFF; ++i) {
- xterm.x = xterm.cols - 1;
+ xterm.buffer.x = xterm.cols - 1;
xterm.write(high + String.fromCharCode(i));
- expect(xterm.lines.get(0)[xterm.x-1][1]).eql(high + String.fromCharCode(i));
- expect(xterm.lines.get(0)[xterm.x-1][1].length).eql(2);
- expect(xterm.lines.get(1)[0][1]).eql(' ');
+ expect(xterm.buffer.lines.get(0)[xterm.buffer.x-1][1]).eql(high + String.fromCharCode(i));
+ expect(xterm.buffer.lines.get(0)[xterm.buffer.x-1][1].length).eql(2);
+ expect(xterm.buffer.lines.get(1)[0][1]).eql(' ');
xterm.reset();
}
});
it('2 characters per cell over line end with autowrap', function() {
var high = String.fromCharCode(0xD800);
for (var i=0xDC00; i<=0xDCFF; ++i) {
- xterm.x = xterm.cols - 1;
+ xterm.buffer.x = xterm.cols - 1;
xterm.wraparoundMode = true;
xterm.write('a' + high + String.fromCharCode(i));
- expect(xterm.lines.get(0)[xterm.cols-1][1]).eql('a');
- expect(xterm.lines.get(1)[0][1]).eql(high + String.fromCharCode(i));
- expect(xterm.lines.get(1)[0][1].length).eql(2);
- expect(xterm.lines.get(1)[1][1]).eql(' ');
+ expect(xterm.buffer.lines.get(0)[xterm.cols-1][1]).eql('a');
+ expect(xterm.buffer.lines.get(1)[0][1]).eql(high + String.fromCharCode(i));
+ expect(xterm.buffer.lines.get(1)[0][1].length).eql(2);
+ expect(xterm.buffer.lines.get(1)[1][1]).eql(' ');
xterm.reset();
}
});
it('2 characters per cell over line end without autowrap', function() {
var high = String.fromCharCode(0xD800);
for (var i=0xDC00; i<=0xDCFF; ++i) {
- xterm.x = xterm.cols - 1;
+ xterm.buffer.x = xterm.cols - 1;
xterm.wraparoundMode = false;
xterm.write('a' + high + String.fromCharCode(i));
// auto wraparound mode should cut off the rest of the line
- expect(xterm.lines.get(0)[xterm.cols-1][1]).eql('a');
- expect(xterm.lines.get(0)[xterm.cols-1][1].length).eql(1);
- expect(xterm.lines.get(1)[1][1]).eql(' ');
+ expect(xterm.buffer.lines.get(0)[xterm.cols-1][1]).eql('a');
+ expect(xterm.buffer.lines.get(0)[xterm.cols-1][1].length).eql(1);
+ expect(xterm.buffer.lines.get(1)[1][1]).eql(' ');
xterm.reset();
}
});
for (var i=0xDC00; i<=0xDCFF; ++i) {
xterm.write(high);
xterm.write(String.fromCharCode(i));
- var tchar = xterm.lines.get(0)[0];
+ var tchar = xterm.buffer.lines.get(0)[0];
expect(tchar[1]).eql(high + String.fromCharCode(i));
expect(tchar[1].length).eql(2);
expect(tchar[2]).eql(1);
- expect(xterm.lines.get(0)[1][1]).eql(' ');
+ expect(xterm.buffer.lines.get(0)[1][1]).eql(' ');
xterm.reset();
}
});
describe('unicode - combining characters', function() {
it('café', function () {
xterm.write('cafe\u0301');
- expect(xterm.lines.get(0)[3][1]).eql('e\u0301');
- expect(xterm.lines.get(0)[3][1].length).eql(2);
- expect(xterm.lines.get(0)[3][2]).eql(1);
+ expect(xterm.buffer.lines.get(0)[3][1]).eql('e\u0301');
+ expect(xterm.buffer.lines.get(0)[3][1].length).eql(2);
+ expect(xterm.buffer.lines.get(0)[3][2]).eql(1);
});
it('café - end of line', function() {
- xterm.x = xterm.cols - 1 - 3;
+ xterm.buffer.x = xterm.cols - 1 - 3;
xterm.write('cafe\u0301');
- expect(xterm.lines.get(0)[xterm.cols-1][1]).eql('e\u0301');
- expect(xterm.lines.get(0)[xterm.cols-1][1].length).eql(2);
- expect(xterm.lines.get(0)[xterm.cols-1][2]).eql(1);
- expect(xterm.lines.get(0)[1][1]).eql(' ');
- expect(xterm.lines.get(0)[1][1].length).eql(1);
- expect(xterm.lines.get(0)[1][2]).eql(1);
+ expect(xterm.buffer.lines.get(0)[xterm.cols-1][1]).eql('e\u0301');
+ expect(xterm.buffer.lines.get(0)[xterm.cols-1][1].length).eql(2);
+ expect(xterm.buffer.lines.get(0)[xterm.cols-1][2]).eql(1);
+ expect(xterm.buffer.lines.get(0)[1][1]).eql(' ');
+ expect(xterm.buffer.lines.get(0)[1][1].length).eql(1);
+ expect(xterm.buffer.lines.get(0)[1][2]).eql(1);
});
it('multiple combined é', function() {
xterm.wraparoundMode = true;
xterm.write(Array(100).join('e\u0301'));
for (var i=0; i<xterm.cols; ++i) {
- var tchar = xterm.lines.get(0)[i];
+ var tchar = xterm.buffer.lines.get(0)[i];
expect(tchar[1]).eql('e\u0301');
expect(tchar[1].length).eql(2);
expect(tchar[2]).eql(1);
}
- tchar = xterm.lines.get(1)[0];
+ tchar = xterm.buffer.lines.get(1)[0];
expect(tchar[1]).eql('e\u0301');
expect(tchar[1].length).eql(2);
expect(tchar[2]).eql(1);
xterm.wraparoundMode = true;
xterm.write(Array(100).join('\uD800\uDC00\u0301'));
for (var i=0; i<xterm.cols; ++i) {
- var tchar = xterm.lines.get(0)[i];
+ var tchar = xterm.buffer.lines.get(0)[i];
expect(tchar[1]).eql('\uD800\uDC00\u0301');
expect(tchar[1].length).eql(3);
expect(tchar[2]).eql(1);
}
- tchar = xterm.lines.get(1)[0];
+ tchar = xterm.buffer.lines.get(1)[0];
expect(tchar[1]).eql('\uD800\uDC00\u0301');
expect(tchar[1].length).eql(3);
expect(tchar[2]).eql(1);
describe('unicode - fullwidth characters', function() {
it('cursor movement even', function() {
- expect(xterm.x).eql(0);
+ expect(xterm.buffer.x).eql(0);
xterm.write('ï¿¥');
- expect(xterm.x).eql(2);
+ expect(xterm.buffer.x).eql(2);
});
it('cursor movement odd', function() {
- xterm.x = 1;
- expect(xterm.x).eql(1);
+ xterm.buffer.x = 1;
+ expect(xterm.buffer.x).eql(1);
xterm.write('ï¿¥');
- expect(xterm.x).eql(3);
+ expect(xterm.buffer.x).eql(3);
});
it('line of ï¿¥ even', function() {
xterm.wraparoundMode = true;
xterm.write(Array(50).join('ï¿¥'));
for (var i=0; i<xterm.cols; ++i) {
- var tchar = xterm.lines.get(0)[i];
+ var tchar = xterm.buffer.lines.get(0)[i];
if (i % 2) {
expect(tchar[1]).eql('');
expect(tchar[1].length).eql(0);
expect(tchar[2]).eql(2);
}
}
- tchar = xterm.lines.get(1)[0];
+ tchar = xterm.buffer.lines.get(1)[0];
expect(tchar[1]).eql('ï¿¥');
expect(tchar[1].length).eql(1);
expect(tchar[2]).eql(2);
});
it('line of ï¿¥ odd', function() {
xterm.wraparoundMode = true;
- xterm.x = 1;
+ xterm.buffer.x = 1;
xterm.write(Array(50).join('ï¿¥'));
for (var i=1; i<xterm.cols-1; ++i) {
- var tchar = xterm.lines.get(0)[i];
+ var tchar = xterm.buffer.lines.get(0)[i];
if (!(i % 2)) {
expect(tchar[1]).eql('');
expect(tchar[1].length).eql(0);
expect(tchar[2]).eql(2);
}
}
- tchar = xterm.lines.get(0)[xterm.cols-1];
+ tchar = xterm.buffer.lines.get(0)[xterm.cols-1];
expect(tchar[1]).eql(' ');
expect(tchar[1].length).eql(1);
expect(tchar[2]).eql(1);
- tchar = xterm.lines.get(1)[0];
+ tchar = xterm.buffer.lines.get(1)[0];
expect(tchar[1]).eql('ï¿¥');
expect(tchar[1].length).eql(1);
expect(tchar[2]).eql(2);
});
it('line of ï¿¥ with combining odd', function() {
xterm.wraparoundMode = true;
- xterm.x = 1;
+ xterm.buffer.x = 1;
xterm.write(Array(50).join('ï¿¥\u0301'));
for (var i=1; i<xterm.cols-1; ++i) {
- var tchar = xterm.lines.get(0)[i];
+ var tchar = xterm.buffer.lines.get(0)[i];
if (!(i % 2)) {
expect(tchar[1]).eql('');
expect(tchar[1].length).eql(0);
expect(tchar[2]).eql(2);
}
}
- tchar = xterm.lines.get(0)[xterm.cols-1];
+ tchar = xterm.buffer.lines.get(0)[xterm.cols-1];
expect(tchar[1]).eql(' ');
expect(tchar[1].length).eql(1);
expect(tchar[2]).eql(1);
- tchar = xterm.lines.get(1)[0];
+ tchar = xterm.buffer.lines.get(1)[0];
expect(tchar[1]).eql('ï¿¥\u0301');
expect(tchar[1].length).eql(2);
expect(tchar[2]).eql(2);
xterm.wraparoundMode = true;
xterm.write(Array(50).join('ï¿¥\u0301'));
for (var i=0; i<xterm.cols; ++i) {
- var tchar = xterm.lines.get(0)[i];
+ var tchar = xterm.buffer.lines.get(0)[i];
if (i % 2) {
expect(tchar[1]).eql('');
expect(tchar[1].length).eql(0);
expect(tchar[2]).eql(2);
}
}
- tchar = xterm.lines.get(1)[0];
+ tchar = xterm.buffer.lines.get(1)[0];
expect(tchar[1]).eql('ï¿¥\u0301');
expect(tchar[1].length).eql(2);
expect(tchar[2]).eql(2);
});
it('line of surrogate fullwidth with combining odd', function() {
xterm.wraparoundMode = true;
- xterm.x = 1;
+ xterm.buffer.x = 1;
xterm.write(Array(50).join('\ud843\ude6d\u0301'));
for (var i=1; i<xterm.cols-1; ++i) {
- var tchar = xterm.lines.get(0)[i];
+ var tchar = xterm.buffer.lines.get(0)[i];
if (!(i % 2)) {
expect(tchar[1]).eql('');
expect(tchar[1].length).eql(0);
expect(tchar[2]).eql(2);
}
}
- tchar = xterm.lines.get(0)[xterm.cols-1];
+ tchar = xterm.buffer.lines.get(0)[xterm.cols-1];
expect(tchar[1]).eql(' ');
expect(tchar[1].length).eql(1);
expect(tchar[2]).eql(1);
- tchar = xterm.lines.get(1)[0];
+ tchar = xterm.buffer.lines.get(1)[0];
expect(tchar[1]).eql('\ud843\ude6d\u0301');
expect(tchar[1].length).eql(3);
expect(tchar[2]).eql(2);
xterm.wraparoundMode = true;
xterm.write(Array(50).join('\ud843\ude6d\u0301'));
for (var i=0; i<xterm.cols; ++i) {
- var tchar = xterm.lines.get(0)[i];
+ var tchar = xterm.buffer.lines.get(0)[i];
if (i % 2) {
expect(tchar[1]).eql('');
expect(tchar[1].length).eql(0);
expect(tchar[2]).eql(2);
}
}
- tchar = xterm.lines.get(1)[0];
+ tchar = xterm.buffer.lines.get(1)[0];
expect(tchar[1]).eql('\ud843\ude6d\u0301');
expect(tchar[1].length).eql(3);
expect(tchar[2]).eql(2);
describe('insert mode', function() {
it('halfwidth - all', function () {
xterm.write(Array(9).join('0123456789').slice(-80));
- xterm.x = 10;
- xterm.y = 0;
+ xterm.buffer.x = 10;
+ xterm.buffer.y = 0;
xterm.insertMode = true;
xterm.write('abcde');
- expect(xterm.lines.get(0).length).eql(xterm.cols);
- expect(xterm.lines.get(0)[10][1]).eql('a');
- expect(xterm.lines.get(0)[14][1]).eql('e');
- expect(xterm.lines.get(0)[15][1]).eql('0');
- expect(xterm.lines.get(0)[79][1]).eql('4');
+ expect(xterm.buffer.lines.get(0).length).eql(xterm.cols);
+ expect(xterm.buffer.lines.get(0)[10][1]).eql('a');
+ expect(xterm.buffer.lines.get(0)[14][1]).eql('e');
+ expect(xterm.buffer.lines.get(0)[15][1]).eql('0');
+ expect(xterm.buffer.lines.get(0)[79][1]).eql('4');
});
it('fullwidth - insert', function() {
xterm.write(Array(9).join('0123456789').slice(-80));
- xterm.x = 10;
- xterm.y = 0;
+ xterm.buffer.x = 10;
+ xterm.buffer.y = 0;
xterm.insertMode = true;
xterm.write('¥¥¥');
- expect(xterm.lines.get(0).length).eql(xterm.cols);
- expect(xterm.lines.get(0)[10][1]).eql('ï¿¥');
- expect(xterm.lines.get(0)[11][1]).eql('');
- expect(xterm.lines.get(0)[14][1]).eql('ï¿¥');
- expect(xterm.lines.get(0)[15][1]).eql('');
- expect(xterm.lines.get(0)[79][1]).eql('3');
+ expect(xterm.buffer.lines.get(0).length).eql(xterm.cols);
+ expect(xterm.buffer.lines.get(0)[10][1]).eql('ï¿¥');
+ expect(xterm.buffer.lines.get(0)[11][1]).eql('');
+ expect(xterm.buffer.lines.get(0)[14][1]).eql('ï¿¥');
+ expect(xterm.buffer.lines.get(0)[15][1]).eql('');
+ expect(xterm.buffer.lines.get(0)[79][1]).eql('3');
});
it('fullwidth - right border', function() {
xterm.write(Array(41).join('ï¿¥'));
- xterm.x = 10;
- xterm.y = 0;
+ xterm.buffer.x = 10;
+ xterm.buffer.y = 0;
xterm.insertMode = true;
xterm.write('a');
- expect(xterm.lines.get(0).length).eql(xterm.cols);
- expect(xterm.lines.get(0)[10][1]).eql('a');
- expect(xterm.lines.get(0)[11][1]).eql('ï¿¥');
- expect(xterm.lines.get(0)[79][1]).eql(' '); // fullwidth char got replaced
+ expect(xterm.buffer.lines.get(0).length).eql(xterm.cols);
+ expect(xterm.buffer.lines.get(0)[10][1]).eql('a');
+ expect(xterm.buffer.lines.get(0)[11][1]).eql('ï¿¥');
+ expect(xterm.buffer.lines.get(0)[79][1]).eql(' '); // fullwidth char got replaced
xterm.write('b');
- expect(xterm.lines.get(0).length).eql(xterm.cols);
- expect(xterm.lines.get(0)[11][1]).eql('b');
- expect(xterm.lines.get(0)[12][1]).eql('ï¿¥');
- expect(xterm.lines.get(0)[79][1]).eql(''); // empty cell after fullwidth
+ expect(xterm.buffer.lines.get(0).length).eql(xterm.cols);
+ expect(xterm.buffer.lines.get(0)[11][1]).eql('b');
+ expect(xterm.buffer.lines.get(0)[12][1]).eql('ï¿¥');
+ expect(xterm.buffer.lines.get(0)[79][1]).eql(''); // empty cell after fullwidth
});
});
});
* @license MIT
*/
+import { BufferSet } from './BufferSet';
import { CompositionHelper } from './CompositionHelper';
import { EventEmitter } from './EventEmitter';
import { Viewport } from './Viewport';
this.on('data', options.handler);
}
- /**
- * The scroll position of the y cursor, ie. ybase + y = the y position within the entire
- * buffer
- */
- this.ybase = 0;
-
- /**
- * The scroll position of the viewport
- */
- this.ydisp = 0;
-
- /**
- * The cursor's x position after ybase
- */
- this.x = 0;
-
- /**
- * The cursor's y position after ybase
- */
- this.y = 0;
-
this.cursorState = 0;
this.cursorHidden = false;
this.convertEol;
this.queue = '';
- this.scrollTop = 0;
- this.scrollBottom = this.rows - 1;
this.customKeyEventHandler = null;
this.cursorBlinkInterval = null;
this.originMode = false;
this.insertMode = false;
this.wraparoundMode = true; // defaults: xterm - true, vt100 - false
- this.normal = null;
// charset
this.charset = null;
// leftover surrogate high from previous write invocation
this.surrogate_high = '';
- /**
- * An array of all lines in the entire buffer, including the prompt. The lines are array of
- * characters which are 2-length arrays where [0] is an attribute and [1] is the character.
- */
- this.lines = new CircularList(this.scrollback);
+ // Create the terminal's buffers and set the current buffer
+ this.buffers = new BufferSet(this);
+ this.buffer = this.buffers.active; // Convenience shortcut;
+ this.buffers.on('activate', function (buffer) {
+ this._terminal.buffer = buffer;
+ });
+
var i = this.rows;
+
while (i--) {
- this.lines.push(this.blankLine());
+ this.buffer.lines.push(this.blankLine());
}
// Ensure the selection manager has the correct buffer
if (this.selectionManager) {
- this.selectionManager.setBuffer(this.lines);
+ this.selectionManager.setBuffer(this.buffer.lines);
}
- this.tabs;
this.setupStops();
// Store if user went browsing history in 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 (this.buffer.lines.length > value) {
+ const amountToTrim = this.buffer.lines.length - value;
+ const needsRefresh = (this.buffer.ydisp - amountToTrim < 0);
+ this.buffer.lines.trimStart(amountToTrim);
+ this.buffer.ybase = Math.max(this.buffer.ybase - amountToTrim, 0);
+ this.buffer.ydisp = Math.max(this.buffer.ydisp - amountToTrim, 0);
if (needsRefresh) {
this.refresh(0, this.rows - 1);
}
}
- this.lines.maxLength = value;
+ this.buffer.lines.maxLength = value;
this.viewport.syncScrollArea();
}
break;
*/
Terminal.bindBlur = function (term) {
on(term.textarea, 'blur', function (ev) {
- term.refresh(term.y, term.y);
+ term.refresh(term.buffer.y, term.buffer.y);
if (term.sendFocus) {
term.send(C0.ESC + '[O');
}
this.viewport = new Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasure);
this.renderer = new Renderer(this);
- this.selectionManager = new SelectionManager(this, this.lines, this.rowContainer, this.charMeasure);
+ this.selectionManager = new SelectionManager(
+ this, this.buffer.lines, this.rowContainer, this.charMeasure
+ );
this.selectionManager.on('refresh', data => {
this.renderer.refreshSelection(data.start, data.end);
});
Terminal.prototype.showCursor = function() {
if (!this.cursorState) {
this.cursorState = 1;
- this.refresh(this.y, this.y);
+ this.refresh(this.buffer.y, this.buffer.y);
}
};
var row;
// Make room for the new row in lines
- if (this.lines.length === this.lines.maxLength) {
- this.lines.trimStart(1);
- this.ybase--;
- if (this.ydisp !== 0) {
- this.ydisp--;
+ if (this.buffer.lines.length === this.buffer.lines.maxLength) {
+ this.buffer.lines.trimStart(1);
+ this.buffer.ybase--;
+ if (this.buffer.ydisp !== 0) {
+ this.buffer.ydisp--;
}
}
- this.ybase++;
+ this.buffer.ybase++;
// TODO: Why is this done twice?
if (!this.userScrolling) {
- this.ydisp = this.ybase;
+ this.buffer.ydisp = this.buffer.ybase;
}
// last line
- row = this.ybase + this.rows - 1;
+ row = this.buffer.ybase + this.rows - 1;
// subtract the bottom scroll region
- row -= this.rows - 1 - this.scrollBottom;
+ row -= this.rows - 1 - this.buffer.scrollBottom;
- if (row === this.lines.length) {
+ if (row === this.buffer.lines.length) {
// Optimization: pushing is faster than splicing when they amount to the same behavior
- this.lines.push(this.blankLine(undefined, isWrapped));
+ this.buffer.lines.push(this.blankLine(undefined, isWrapped));
} else {
// add our new line
- this.lines.splice(row, 0, this.blankLine(undefined, isWrapped));
+ this.buffer.lines.splice(row, 0, this.blankLine(undefined, isWrapped));
}
- if (this.scrollTop !== 0) {
- if (this.ybase !== 0) {
- this.ybase--;
+ if (this.buffer.scrollTop !== 0) {
+ if (this.buffer.ybase !== 0) {
+ this.buffer.ybase--;
if (!this.userScrolling) {
- this.ydisp = this.ybase;
+ this.buffer.ydisp = this.buffer.ybase;
}
}
- this.lines.splice(this.ybase + this.scrollTop, 1);
+ this.buffer.lines.splice(this.buffer.ybase + this.buffer.scrollTop, 1);
}
// this.maxRange();
- this.updateRange(this.scrollTop);
- this.updateRange(this.scrollBottom);
+ this.updateRange(this.buffer.scrollTop);
+ this.updateRange(this.buffer.scrollBottom);
/**
* This event is emitted whenever the terminal is scrolled.
*
* @event scroll
*/
- this.emit('scroll', this.ydisp);
+ this.emit('scroll', this.buffer.ydisp);
};
/**
*/
Terminal.prototype.scrollDisp = function(disp, suppressScrollEvent) {
if (disp < 0) {
- if (this.ydisp === 0) {
+ if (this.buffer.ydisp === 0) {
return;
}
this.userScrolling = true;
- } else if (disp + this.ydisp >= this.ybase) {
+ } else if (disp + this.buffer.ydisp >= this.buffer.ybase) {
this.userScrolling = false;
}
- const oldYdisp = this.ydisp;
- this.ydisp = Math.max(Math.min(this.ydisp + disp, this.ybase), 0);
+ const oldYdisp = this.buffer.ydisp;
+ this.buffer.ydisp = Math.max(Math.min(this.buffer.ydisp + disp, this.buffer.ybase), 0);
// No change occurred, don't trigger scroll/refresh
- if (oldYdisp === this.ydisp) {
+ if (oldYdisp === this.buffer.ydisp) {
return;
}
if (!suppressScrollEvent) {
- this.emit('scroll', this.ydisp);
+ this.emit('scroll', this.buffer.ydisp);
}
this.refresh(0, this.rows - 1);
* Scrolls the display of the terminal to the top.
*/
Terminal.prototype.scrollToTop = function() {
- this.scrollDisp(-this.ydisp);
+ this.scrollDisp(-this.buffer.ydisp);
};
/**
* Scrolls the display of the terminal to the bottom.
*/
Terminal.prototype.scrollToBottom = function() {
- this.scrollDisp(this.ybase - this.ydisp);
+ this.scrollDisp(this.buffer.ybase - this.buffer.ydisp);
};
/**
this.xoffSentToCatchUp = false;
}
- this.refreshStart = this.y;
- this.refreshEnd = this.y;
+ this.refreshStart = this.buffer.y;
+ this.refreshEnd = this.buffer.y;
// HACK: Set the parser state based on it's state at the time of return.
// This works around the bug #662 which saw the parser state reset in the
var state = this.parser.parse(data);
this.parser.setState(state);
- this.updateRange(this.y);
+ this.updateRange(this.buffer.y);
this.refresh(this.refreshStart, this.refreshEnd);
}
if (this.writeBuffer.length > 0) {
this.restartCursorBlinking();
if (!this.compositionHelper.keydown.bind(this.compositionHelper)(ev)) {
- if (this.ybase !== this.ydisp) {
+ if (this.buffer.ybase !== this.buffer.ydisp) {
this.scrollToBottom();
}
return false;
j = this.cols;
if (j < x) {
ch = [this.defAttr, ' ', 1]; // does xterm use the default attr?
- i = this.lines.length;
+ i = this.buffer.lines.length;
while (i--) {
- while (this.lines.get(i).length < x) {
- this.lines.get(i).push(ch);
+ while (this.buffer.lines.get(i).length < x) {
+ this.buffer.lines.get(i).push(ch);
}
}
}
if (j < y) {
el = this.element;
while (j++ < y) {
- // y is rows, not this.y
- if (this.lines.length < y + this.ybase) {
- if (this.ybase > 0 && this.lines.length <= this.ybase + this.y + addToY + 1) {
+ // y is rows, not this.buffer.y
+ if (this.buffer.lines.length < y + this.buffer.ybase) {
+ if (this.buffer.ybase > 0 && this.buffer.lines.length <= this.buffer.ybase + this.buffer.y + addToY + 1) {
// There is room above the buffer and there are no empty elements below the line,
// scroll up
- this.ybase--;
+ this.buffer.ybase--;
addToY++;
- if (this.ydisp > 0) {
+ if (this.buffer.ydisp > 0) {
// Viewport is at the top of the buffer, must increase downwards
- this.ydisp--;
+ this.buffer.ydisp--;
}
} else {
// Add a blank line if there is no buffer left at the top to scroll to, or if there
// are blank lines after the cursor
- this.lines.push(this.blankLine());
+ this.buffer.lines.push(this.blankLine());
}
}
if (this.children.length < y) {
}
} else { // (j > y)
while (j-- > y) {
- if (this.lines.length > y + this.ybase) {
- if (this.lines.length > this.ybase + this.y + 1) {
+ if (this.buffer.lines.length > y + this.buffer.ybase) {
+ if (this.buffer.lines.length > this.buffer.ybase + this.buffer.y + 1) {
// The line is a blank line below the cursor, remove it
- this.lines.pop();
+ this.buffer.lines.pop();
} else {
// The line is the cursor, scroll down
- this.ybase++;
- this.ydisp++;
+ this.buffer.ybase++;
+ this.buffer.ydisp++;
}
}
if (this.children.length > y) {
this.rows = y;
// Make sure that the cursor stays on screen
- if (this.y >= y) {
- this.y = y - 1;
+ if (this.buffer.y >= y) {
+ this.buffer.y = y - 1;
}
if (addToY) {
- this.y += addToY;
+ this.buffer.y += addToY;
}
- if (this.x >= x) {
- this.x = x - 1;
+ if (this.buffer.x >= x) {
+ this.buffer.x = x - 1;
}
- this.scrollTop = 0;
- this.scrollBottom = y - 1;
+ this.buffer.scrollTop = 0;
+ this.buffer.scrollBottom = y - 1;
this.charMeasure.measure();
this.refresh(0, this.rows - 1);
- this.normal = null;
-
this.geometry = [this.cols, this.rows];
this.emit('resize', {terminal: this, cols: x, rows: y});
};
*/
Terminal.prototype.setupStops = function(i) {
if (i != null) {
- if (!this.tabs[i]) {
+ if (!this.buffer.tabs[i]) {
i = this.prevStop(i);
}
} else {
- this.tabs = {};
+ this.buffer.tabs = {};
i = 0;
}
for (; i < this.cols; i += this.getOption('tabStopWidth')) {
- this.tabs[i] = true;
+ this.buffer.tabs[i] = true;
}
};
* @param {number} x The position to move the cursor to the previous tab stop.
*/
Terminal.prototype.prevStop = function(x) {
- if (x == null) x = this.x;
- while (!this.tabs[--x] && x > 0);
+ if (x == null) x = this.buffer.x;
+ while (!this.buffer.tabs[--x] && x > 0);
return x >= this.cols
? this.cols - 1
: x < 0 ? 0 : x;
* @param {number} x The position to move the cursor one tab stop forward.
*/
Terminal.prototype.nextStop = function(x) {
- if (x == null) x = this.x;
- while (!this.tabs[++x] && x < this.cols);
+ if (x == null) x = this.buffer.x;
+ while (!this.buffer.tabs[++x] && x < this.cols);
return x >= this.cols
? this.cols - 1
: x < 0 ? 0 : x;
* @param {number} y The line in which to operate.
*/
Terminal.prototype.eraseRight = function(x, y) {
- var line = this.lines.get(this.ybase + y);
+ var line = this.buffer.lines.get(this.buffer.ybase + y);
if (!line) {
return;
}
* @param {number} y The line in which to operate.
*/
Terminal.prototype.eraseLeft = function(x, y) {
- var line = this.lines.get(this.ybase + y);
+ var line = this.buffer.lines.get(this.buffer.ybase + y);
if (!line) {
return;
}
* Clears the entire buffer, making the prompt line the new first line.
*/
Terminal.prototype.clear = function() {
- if (this.ybase === 0 && this.y === 0) {
+ if (this.buffer.ybase === 0 && this.buffer.y === 0) {
// Don't clear if it's already clear
return;
}
- this.lines.set(0, this.lines.get(this.ybase + this.y));
- this.lines.length = 1;
- this.ydisp = 0;
- this.ybase = 0;
- this.y = 0;
+ this.buffer.lines.set(0, this.buffer.lines.get(this.buffer.ybase + this.buffer.y));
+ this.buffer.lines.length = 1;
+ this.buffer.ydisp = 0;
+ this.buffer.ybase = 0;
+ this.buffer.y = 0;
for (var i = 1; i < this.rows; i++) {
- this.lines.push(this.blankLine());
+ this.buffer.lines.push(this.blankLine());
}
this.refresh(0, this.rows - 1);
- this.emit('scroll', this.ydisp);
+ this.emit('scroll', this.buffer.ydisp);
};
/**
}
// Input is being sent to the terminal, the terminal should focus the prompt.
- if (this.ybase !== this.ydisp) {
+ if (this.buffer.ybase !== this.buffer.ydisp) {
this.scrollToBottom();
}
this.emit('data', data);
* ESC D Index (IND is 0x84).
*/
Terminal.prototype.index = function() {
- this.y++;
- if (this.y > this.scrollBottom) {
- this.y--;
+ this.buffer.y++;
+ if (this.buffer.y > this.buffer.scrollBottom) {
+ this.buffer.y--;
this.scroll();
}
// If the end of the line is hit, prevent this action from wrapping around to the next line.
- if (this.x >= this.cols) {
- this.x--;
+ if (this.buffer.x >= this.cols) {
+ this.buffer.x--;
}
};
*/
Terminal.prototype.reverseIndex = function() {
var j;
- if (this.y === this.scrollTop) {
+ if (this.buffer.y === this.buffer.scrollTop) {
// possibly move the code below to term.reverseScroll();
// test: echo -ne '\e[1;1H\e[44m\eM\e[0m'
// blankLine(true) is xterm/linux behavior
- this.lines.shiftElements(this.y + this.ybase, this.rows - 1, 1);
- this.lines.set(this.y + this.ybase, this.blankLine(true));
- this.updateRange(this.scrollTop);
- this.updateRange(this.scrollBottom);
+ this.buffer.lines.shiftElements(this.buffer.y + this.buffer.ybase, this.rows - 1, 1);
+ this.buffer.lines.set(this.buffer.y + this.buffer.ybase, this.blankLine(true));
+ this.updateRange(this.buffer.scrollTop);
+ this.updateRange(this.buffer.scrollBottom);
} else {
- this.y--;
+ this.buffer.y--;
}
};
this.options.cols = this.cols;
var customKeyEventHandler = this.customKeyEventHandler;
var cursorBlinkInterval = this.cursorBlinkInterval;
+ var inputHandler = this.inputHandler;
+ var buffers = this.buffers;
Terminal.call(this, this.options);
this.customKeyEventHandler = customKeyEventHandler;
this.cursorBlinkInterval = cursorBlinkInterval;
+ this.inputHandler = inputHandler;
+ this.buffers = buffers;
this.refresh(0, this.rows - 1);
this.viewport.syncScrollArea();
};
* ESC H Tab Set (HTS is 0x88).
*/
Terminal.prototype.tabSet = function() {
- this.tabs[this.x] = true;
+ this.buffer.tabs[this.buffer.x] = true;
};
/**