xterm.js-2.7.0/000077500000000000000000000000001311554223300132715ustar00rootroot00000000000000xterm.js-2.7.0/.dockerignore000066400000000000000000000002331311554223300157430ustar00rootroot00000000000000node_modules/ *.swp .lock-wscript lib/ Makefile.gyp *.Makefile *.target.gyp.mk *.node example/*.log docs/ npm-debug.log /.idea/ .env build/ .vscode/ .git/ xterm.js-2.7.0/.editorconfig000066400000000000000000000003471311554223300157520ustar00rootroot00000000000000root = true [*] indent_style = space indent_size = 2 insert_final_newline = true trim_trailing_whitespace = true end_of_line = lf [*.{j,t}s] max_line_length = 100 [*.css] indent_size = 4 [*.md] trim_trailing_whitespace = false xterm.js-2.7.0/.github/000077500000000000000000000000001311554223300146315ustar00rootroot00000000000000xterm.js-2.7.0/.github/ISSUE_TEMPLATE.md000066400000000000000000000002341311554223300173350ustar00rootroot00000000000000 ## Details - Browser and browser version: - OS version: - xterm.js version: ### Steps to reproduce 1. 2. xterm.js-2.7.0/.gitignore000066400000000000000000000003101311554223300152530ustar00rootroot00000000000000node_modules/ *.swp .lock-wscript lib/ Makefile.gyp *.Makefile *.target.gyp.mk *.node example/*.log docs/ npm-debug.log /.idea/ .env build/ .vscode/ # Directories needed for code coverage /coverage/ xterm.js-2.7.0/.mailmap000066400000000000000000000005521311554223300147140ustar00rootroot00000000000000Antonis Kalipetis Antonis Kalipetis Daniel Imms Paris Kasidiaris Paris Kasidiaris Thanasis Daglis Thanasis Daglis xterm.js-2.7.0/.npmignore000066400000000000000000000002611311554223300152670ustar00rootroot00000000000000node_modules/ *.swp .lock-wscript lib/*.test.js lib/*.test.js.map lib/test/ Makefile.gyp *.Makefile *.target.gyp.mk *.node example/*.log docs/ npm-debug.log /.idea/ .env build/ xterm.js-2.7.0/.travis.yml000066400000000000000000000004601311554223300154020ustar00rootroot00000000000000language: node_js node_js: - 6 env: global: - CXX=g++-4.8 matrix: - NPM_COMMAND=lint - NPM_COMMAND=test addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-4.8 notifications: email: false script: npm run $NPM_COMMAND after_success: npm run coveralls xterm.js-2.7.0/.vscode/000077500000000000000000000000001311554223300146325ustar00rootroot00000000000000xterm.js-2.7.0/.vscode/launch.json000066400000000000000000000011151311554223300167750ustar00rootroot00000000000000{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Mocha Tests", "cwd": "${workspaceRoot}", "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/mocha", "windows": { "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/mocha.cmd" }, "runtimeArgs": [ "--colors", "--recursive", "${workspaceRoot}/lib" ], "sourceMaps": true, "outFiles": [ "${workspaceRoot}/lib/**/*.js" ], "internalConsoleOptions": "openOnSessionStart" } ] } xterm.js-2.7.0/AUTHORS000066400000000000000000000040721311554223300143440ustar00rootroot00000000000000List of xterm.js contributors. Updated before every release. Aleksandr Andrienko Alessandro Nadalin Alexander Olsson Antonis Kalipetis Anton Skshidlevsky Anton Yurovskykh Austin Robertson ayapi Ben Hall Benjamin Fischer Bill Church Bob Reid bottleofwater Brian Mock Carson Anderson Christian Budde Christensen Christopher Jeffrey coderaiser Daniel Imms Daniel Risacher Dan Kaplun Darin Morrison Edgar Andrés Margffoy Tuay Elliot Saba Gary Ritchie hiro-su Ian Lewis imoses InDieTasten Jean Bruenn Jeremy Danyow Jörg Breitbart Justin Mecham Lucian Buzzo Maël Nison Martin Chloride Martin Wang Michael Irwin Mikko Karvonen Nicolas Ramz Paris Kasidiaris Paris Kasidiaris runarberg Saswat Das Saul Costa Shuanglei Tao Steven Silvester Thanasis Daglis Tine Jozelj Tyler Jewell Vincent Woo yutaka YuviPanda xterm.js-2.7.0/CONTRIBUTING.md000066400000000000000000000042721311554223300155270ustar00rootroot00000000000000# How to contribute to xterm.js - [Opening issues for bug reports or feature requests](#opening-issues) - [Contributing code](#contributing-code) ## Opening issues The preferred way to report bugs or request features is to use [GitHub issues](http://github.com/sourcelair/xterm.js/issues). Before opening an issue, read these pointers. ### Opening issues effectively - Include information about **the browser in which the problem occurred**. Even if you tested several browsers, and the problem occurred in all of them, mention this fact in the bug report. Also include browser version numbers and the operating system that you're on. - Mention which release of xterm.js you're using. Preferably, try also with the current HEAD of the master branch, to ensure the problem has not already been fixed. - Mention precisely what went wrong. What did you expect to happen? What happened instead? Describe the exact steps a maintainer has to take to make the problem occur. - If the problem can not be reproduced in the [demo of xterm.js](README.md#demo), please provide an HTML document that demonstrates the problem. - Be polite. Issues with an indignant or belligerent tone tend to be moved to the bottom of the pile. ## Contributing code - Make sure you have a [GitHub account](https://github.com/join) - Fork [xterm.js](https://github.com/sourcelair/xterm.js/) ([how to fork a repo](https://help.github.com/articles/fork-a-repo)) - Make your changes - If your changes are easy to test or likely to regress, add tests. Tests go into `test`, directory. - Follow the general code style of the rest of the project (see below). - Submit a pull request ([how to create a pull request](https://help.github.com/articles/fork-a-repo)). Don't put more than one feature/fix in a single pull request. By contributing code to xterm.js you - agree to license the contributed code under xterm.js' [MIT license](LICENSE). - confirm that you have the right to contribute and license the code in question. (Either you hold all rights on the code, or the rights holder has explicitly granted the right to use it like this, through a compatible open source license or through a direct agreement with you.) xterm.js-2.7.0/Dockerfile000066400000000000000000000010421311554223300152600ustar00rootroot00000000000000FROM node:6.9 MAINTAINER Paris Kasidiaris # Set the working directory WORKDIR /usr/src/app # Set an entrypoint, to automatically install node modules ENTRYPOINT ["/bin/bash", "-c", "if [[ ! -d node_modules ]]; then npm install; fi; exec \"${@:0}\";"] CMD ["npm", "run", "dev"] # First, install dependencies to improve layer caching COPY package.json /usr/src/app/ RUN npm install # Add the code COPY . /usr/src/app # Run the tests and build, to make sure everything is working nicely RUN npm run build && npm run test xterm.js-2.7.0/LICENSE000066400000000000000000000022311311554223300142740ustar00rootroot00000000000000Copyright (c) 2014-2016, SourceLair Private Company (https://www.sourcelair.com) Copyright (c) 2012-2013, Christopher Jeffrey (https://github.com/chjj/) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. xterm.js-2.7.0/Procfile000066400000000000000000000000171311554223300147550ustar00rootroot00000000000000web: npm start xterm.js-2.7.0/Procfile.dev000066400000000000000000000000211311554223300155250ustar00rootroot00000000000000web: npm run dev xterm.js-2.7.0/README.md000066400000000000000000000165121311554223300145550ustar00rootroot00000000000000# [![xterm.js logo](logo.png)](https://xtermjs.org) [![xterm.js build status](https://api.travis-ci.org/sourcelair/xterm.js.svg)](https://travis-ci.org/sourcelair/xterm.js) [![Coverage Status](https://coveralls.io/repos/github/sourcelair/xterm.js/badge.svg)](https://coveralls.io/github/sourcelair/xterm.js) [![Gitter](https://badges.gitter.im/sourcelair/xterm.js.svg)](https://gitter.im/sourcelair/xterm.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Xterm.js is a terminal front-end component written in JavaScript that works in the browser. It enables applications to provide fully featured terminals to their users and create great development experiences. ## Features - **Text-based application support**: Use xterm.js to work with applications like `bash`, `git` etc. - **Curses-based application support**: Use xterm.js to work with applications like `vim`, `tmux` etc. - **Mouse events support**: Xterm.js captures mouse events like click and scroll and passes them to the terminal's back-end controlling process - **CJK (Chinese, Japanese, Korean) character support**: Xterm.js renders CJK characters seamlessly - **IME support**: Insert international (including CJK) characters using IME input with your keyboard - **Self-contained library**: Xterm.js works on its own. It does not require any external libraries like jQuery or React to work - **Modular, event-based API**: Lets you build addons and themes with ease ## What xterm.js is not - Xterm.js is not a terminal application that you can download and use on your computer - Xterm.js is not `bash`. Xterm.js can be connected to processes like `bash` and let you interact with them (provide input, receive output) ## Real-world uses Xterm.js is used in several world-class applications to provide great terminal experiences. - [**SourceLair**](https://www.sourcelair.com/): In-browser IDE that provides its users with fully-featured Linux terminals based on xterm.js - [**Microsoft Visual Studio Code**](http://code.visualstudio.com/): Modern, versatile and powerful open source code editor that provides an integrated terminal based on xterm.js - [**ttyd**](https://github.com/tsl0922/ttyd): A command-line tool for sharing terminal over the web, with fully-featured terminal emulation based on xterm.js - [**Katacoda**](https://www.katacoda.com/): Katacoda is an Interactive Learning Platform for software developers, covering the latest Cloud Native technologies. - [**Eclipse Che**](http://www.eclipse.org/che): Developer workspace server, cloud IDE, and Eclipse next-generation IDE. - [**Codenvy**](http://www.codenvy.com): Cloud workspaces for development teams. - [**CoderPad**](https://coderpad.io): Online interviewing platform for programmers. Run code in many programming languages, with results displayed by `xterm.js`. - [**WebSSH2**](https://github.com/billchurch/WebSSH2): A web based SSH2 client using `xterm.js`, socket.io, and ssh2. - [**Spyder Terminal**](https://github.com/spyder-ide/spyder-terminal): A full fledged system terminal embedded on Spyder IDE. - [**Cloud Commander**](https://cloudcmd.io "Cloud Commander"): Orthodox web file manager with console and editor. - [**Codevolve**](https://www.codevolve.com "Codevolve"): Online platform for interactive coding and web development courses. Live container-backed terminal uses `xterm.js`. - [**RStudio**](https://www.rstudio.com/products/RStudio "RStudio"): RStudio is an integrated development environment (IDE) for R. - [**Terminal for Atom**](https://github.com/jsmecham/atom-terminal-tab): A simple terminal for the Atom text editor. - [**Eclipse Orion**](https://orionhub.org): A modern, open source software development environment that runs in the cloud. Code, deploy and run in the cloud. Do you use xterm.js in your application as well? Please [open a Pull Request](https://github.com/sourcelair/xterm.js/pulls) to include it here. We would love to have it in our list. ## Browser Support Since xterm.js is typically implemented as a developer tool, only modern browsers are supported officially. Here is a list of the versions we aim to support: - Chrome 48+ - Edge 13+ - Firefox 44+ - Internet Explorer 11+ - Opera 35+ - Safari 8+ Xterm.js works seamlessly in Electron apps and may even work on earlier versions of the browsers but these are the browsers we strive to keep working. ## Demo ### Linux or macOS Run the following commands: ``` $ npm install $ npm start ``` Then open http://0.0.0.0:3000 in a web browser. ### Windows First, ensure [node-gyp](https://github.com/nodejs/node-gyp) is installed and configured correctly, then run these commands. Note: Do not use ConEmu, as it seems to break the demo for some reason. ``` > npm install > npm start ``` Then open http://127.0.0.1:3000 in a web browser. ## Getting Started To start using xterm.js on your browser, add the `xterm.js` and `xterm.css` to the head of your html page. Then create a `
` onto which xterm can attach itself. ```html
``` Finally instantiate the `Terminal` object and then call the `open` function with the DOM object of the `div`. ## Addons Addons are JavaScript modules that attach functions to the `Terminal` prototype to extend its functionality. There are a handful available in the main repository in the `dist/addons` directory, you can even write your own (though they may break when the internals of xterm.js change across versions). To use an addon, just include the JavaScript file after xterm.js and before the `Terminal` object has been instantiated. The function should then be exposed on the `Terminal` object: ```html ``` ```js var xterm = new Terminal(); // init code... xterm.fit(); ``` ## Releases Xterm.js follows a monthly release cycle roughly. The existing releases are available at this GitHub repo's [Releases](https://github.com/sourcelair/xterm.js/releases), while the roadmap is available as [Milestones](https://github.com/sourcelair/xterm.js/milestones). ## Development and Contribution Xterm.js is maintained by [SourceLair](https://www.sourcelair.com/) and a few external contributors, but we would love to receive contributions from everyone! To contribute either code, documentation or issues to xterm.js please read the [Contributing document](CONTRIBUTING.md) beforehand. The development of xterm.js does not require any special tool. All you need is an editor that supports JavaScript/TypeScript and a browser. You will need Node.js installed locally to get all the features working in the demo. ## License Agreement If you contribute code to this project, you are implicitly allowing your code to be distributed under the MIT license. You are also implicitly verifying that all code is your original work. Copyright (c) 2014-2016, SourceLair, Private Company ([www.sourcelair.com](https://www.sourcelair.com/home)) (MIT License) Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) xterm.js-2.7.0/bin/000077500000000000000000000000001311554223300140415ustar00rootroot00000000000000xterm.js-2.7.0/bin/generate-authors000077500000000000000000000003471311554223300172500ustar00rootroot00000000000000#! /usr/bin/env sh tail --lines=+3 AUTHORS > AUTHORS.tmp git log --format='%aN <%aE>' >> AUTHORS.tmp echo "List of xterm.js contributors. Updated before every release.\n" > AUTHORS sort -u AUTHORS.tmp >> AUTHORS rm -f AUTHORS.tmp xterm.js-2.7.0/bin/prepare-release000077500000000000000000000015511311554223300170450ustar00rootroot00000000000000#! /usr/bin/env sh # Usage: ./bin/prepare-release x.y.z # x.y.z should be semver (e.g. 1.0.0) set -e NEW_VERSION=$1 CURRENT_PACKAGE_JSON_VERSION=$(cat package.json \ | grep version \ | head -1 \ | awk -F: '{ print $2 }' \ | sed 's/[",]//g' \ | tr -d '[[:space:]]') CURRENT_BOWER_JSON_VERSION=$(cat bower.json \ | grep version \ | head -1 \ | awk -F: '{ print $2 }' \ | sed 's/[",]//g' \ | tr -d '[[:space:]]') # Build xterm.js into `dist` export BUILD_DIR=dist npm run build # Update AUTHORS file sh bin/generate-authors # Update version in package.json and bower.json sed -i "s/\"version\": \"$CURRENT_PACKAGE_JSON_VERSION\"/\"version\": \"$NEW_VERSION\"/g" package.json sed -i "s/\"version\": \"$CURRENT_BOWER_JSON_VERSION\"/\"version\": \"$NEW_VERSION\"/g" bower.json git commit -S -s -a -m "Bump version to $NEW_VERSION" git tag $NEW_VERSION xterm.js-2.7.0/bin/release000077500000000000000000000005371311554223300154140ustar00rootroot00000000000000#! /usr/bin/env sh # Usage: ./bin/release x.y.z # x.y.z should be semver (e.g. 1.0.0) set -e if [ -z "$1" ]; then echo "No version supplied. Please a version argument\n" echo "Usage: $0 VERSION\n" echo "Example: $0 1.0.0" exit fi NEW_VERSION=$1 ./bin/prepare-release $NEW_VERSION git push && \ git push --tags && \ npm publish xterm.js-2.7.0/bower.json000066400000000000000000000002261311554223300153020ustar00rootroot00000000000000{ "name": "xterm.js", "version": "2.7.0", "ignore": ["demo", "test", ".gitignore"], "main": [ "dist/xterm.js", "dist/xterm.css" ] } xterm.js-2.7.0/demo/000077500000000000000000000000001311554223300142155ustar00rootroot00000000000000xterm.js-2.7.0/demo/app.js000066400000000000000000000042031311554223300153320ustar00rootroot00000000000000var express = require('express'); var app = express(); var expressWs = require('express-ws')(app); var os = require('os'); var pty = require('node-pty'); var terminals = {}, logs = {}; app.use('/build', express.static(__dirname + '/../build')); app.get('/', function(req, res){ res.sendFile(__dirname + '/index.html'); }); app.get('/style.css', function(req, res){ res.sendFile(__dirname + '/style.css'); }); app.get('/main.js', function(req, res){ res.sendFile(__dirname + '/main.js'); }); app.post('/terminals', function (req, res) { var cols = parseInt(req.query.cols), rows = parseInt(req.query.rows), term = pty.spawn(process.platform === 'win32' ? 'cmd.exe' : 'bash', [], { name: 'xterm-color', cols: cols || 80, rows: rows || 24, cwd: process.env.PWD, env: process.env }); console.log('Created terminal with PID: ' + term.pid); terminals[term.pid] = term; logs[term.pid] = ''; term.on('data', function(data) { logs[term.pid] += data; }); res.send(term.pid.toString()); res.end(); }); app.post('/terminals/:pid/size', function (req, res) { var pid = parseInt(req.params.pid), cols = parseInt(req.query.cols), rows = parseInt(req.query.rows), term = terminals[pid]; term.resize(cols, rows); console.log('Resized terminal ' + pid + ' to ' + cols + ' cols and ' + rows + ' rows.'); res.end(); }); app.ws('/terminals/:pid', function (ws, req) { var term = terminals[parseInt(req.params.pid)]; console.log('Connected to terminal ' + term.pid); ws.send(logs[term.pid]); term.on('data', function(data) { try { ws.send(data); } catch (ex) { // The WebSocket is not open, ignore } }); ws.on('message', function(msg) { term.write(msg); }); ws.on('close', function () { term.kill(); console.log('Closed terminal ' + term.pid); // Clean things up delete terminals[term.pid]; delete logs[term.pid]; }); }); var port = process.env.PORT || 3000, host = os.platform() === 'win32' ? '127.0.0.1' : '0.0.0.0'; console.log('App listening to http://' + host + ':' + port); app.listen(port, host); xterm.js-2.7.0/demo/index.html000066400000000000000000000042751311554223300162220ustar00rootroot00000000000000 xterm.js demo

xterm.js: xterm, in the browser

Options

Size

Attention: The demo is a barebones implementation and is designed for xterm.js evaluation purposes only. Exposing the demo to the public as is would introduce security risks for the host.

xterm.js-2.7.0/demo/main.js000066400000000000000000000077741311554223300155160ustar00rootroot00000000000000var term, protocol, socketURL, socket, pid, charWidth, charHeight; var terminalContainer = document.getElementById('terminal-container'), optionElements = { cursorBlink: document.querySelector('#option-cursor-blink'), cursorStyle: document.querySelector('#option-cursor-style'), scrollback: document.querySelector('#option-scrollback'), tabstopwidth: document.querySelector('#option-tabstopwidth') }, colsElement = document.getElementById('cols'), rowsElement = document.getElementById('rows'); function setTerminalSize () { var cols = parseInt(colsElement.value, 10), rows = parseInt(rowsElement.value, 10), width = (cols * charWidth).toString() + 'px', height = (rows * charHeight).toString() + 'px'; terminalContainer.style.width = width; terminalContainer.style.height = height; term.resize(cols, rows); } colsElement.addEventListener('change', setTerminalSize); rowsElement.addEventListener('change', setTerminalSize); optionElements.cursorBlink.addEventListener('change', function () { term.setOption('cursorBlink', optionElements.cursorBlink.checked); }); optionElements.cursorStyle.addEventListener('change', function () { term.setOption('cursorStyle', optionElements.cursorStyle.value); }); optionElements.scrollback.addEventListener('change', function () { term.setOption('scrollback', parseInt(optionElements.scrollback.value, 10)); }); optionElements.tabstopwidth.addEventListener('change', function () { term.setOption('tabStopWidth', parseInt(optionElements.tabstopwidth.value, 10)); }); createTerminal(); function createTerminal() { // Clean terminal while (terminalContainer.children.length) { terminalContainer.removeChild(terminalContainer.children[0]); } term = new Terminal({ cursorBlink: optionElements.cursorBlink.checked, scrollback: parseInt(optionElements.scrollback.value, 10), tabStopWidth: parseInt(optionElements.tabstopwidth.value, 10) }); term.on('resize', function (size) { if (!pid) { return; } var cols = size.cols, rows = size.rows, url = '/terminals/' + pid + '/size?cols=' + cols + '&rows=' + rows; fetch(url, {method: 'POST'}); }); protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://'; socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/'; term.open(terminalContainer); term.fit(); var initialGeometry = term.proposeGeometry(), cols = initialGeometry.cols, rows = initialGeometry.rows; colsElement.value = cols; rowsElement.value = rows; fetch('/terminals?cols=' + cols + '&rows=' + rows, {method: 'POST'}).then(function (res) { charWidth = Math.ceil(term.element.offsetWidth / cols); charHeight = Math.ceil(term.element.offsetHeight / rows); res.text().then(function (pid) { window.pid = pid; socketURL += pid; socket = new WebSocket(socketURL); socket.onopen = runRealTerminal; socket.onclose = runFakeTerminal; socket.onerror = runFakeTerminal; }); }); } function runRealTerminal() { term.attach(socket); term._initialized = true; } function runFakeTerminal() { if (term._initialized) { return; } term._initialized = true; var shellprompt = '$ '; term.prompt = function () { term.write('\r\n' + shellprompt); }; term.writeln('Welcome to xterm.js'); term.writeln('This is a local terminal emulation, without a real terminal in the back-end.'); term.writeln('Type some keys and commands to play around.'); term.writeln(''); term.prompt(); term.on('key', function (key, ev) { var printable = ( !ev.altKey && !ev.altGraphKey && !ev.ctrlKey && !ev.metaKey ); if (ev.keyCode == 13) { term.prompt(); } else if (ev.keyCode == 8) { // Do not delete the prompt if (term.x > 2) { term.write('\b \b'); } } else if (printable) { term.write(key); } }); term.on('paste', function (data, ev) { term.write(data); }); } xterm.js-2.7.0/demo/style.css000066400000000000000000000005061311554223300160700ustar00rootroot00000000000000body { font-family: helvetica, sans-serif, arial; font-size: 1em; color: #111; } h1 { text-align: center; } #terminal-container { width: 800px; height: 450px; margin: 0 auto; padding: 2px; } #terminal-container .terminal { background-color: #111; color: #fafafa; padding: 2px; } xterm.js-2.7.0/docker-compose.yaml000066400000000000000000000001561311554223300170710ustar00rootroot00000000000000version: '2' services: web: build: ./ volumes: - ./:/usr/src/app ports: - 3000:3000 xterm.js-2.7.0/gulpfile.js000066400000000000000000000072351311554223300154450ustar00rootroot00000000000000const browserify = require('browserify'); const buffer = require('vinyl-buffer'); const coveralls = require('gulp-coveralls'); const fs = require('fs-extra'); const gulp = require('gulp'); const istanbul = require('gulp-istanbul'); const merge = require('merge-stream'); const mocha = require('gulp-mocha'); const sorcery = require('sorcery'); const source = require('vinyl-source-stream'); const sourcemaps = require('gulp-sourcemaps'); const ts = require('gulp-typescript'); let buildDir = process.env.BUILD_DIR || 'build'; let tsProject = ts.createProject('tsconfig.json'); let srcDir = tsProject.config.compilerOptions.rootDir; let outDir = tsProject.config.compilerOptions.outDir; /** * Compile TypeScript sources to JavaScript files and create a source map file for each TypeScript * file compiled. */ gulp.task('tsc', function () { // Remove the ${outDir}/ directory to prevent confusion if files were deleted in ${srcDir}/ fs.emptyDirSync(`${outDir}`); // Build all TypeScript files (including tests) to ${outDir}/, based on the configuration defined in // `tsconfig.json`. let tsResult = tsProject.src().pipe(sourcemaps.init()).pipe(tsProject()); let tsc = tsResult.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(outDir)); // Copy all addons from ${srcDir}/ to ${outDir}/ let copyAddons = gulp.src(`${srcDir}/addons/**/*`).pipe(gulp.dest(`${outDir}/addons`)); // Copy stylesheets from ${srcDir}/ to ${outDir}/ let copyStylesheets = gulp.src(`${srcDir}/**/*.css`).pipe(gulp.dest(outDir)); return merge(tsc, copyAddons, copyStylesheets); }); /** * Bundle JavaScript files produced by the `tsc` task, into a single file named `xterm.js` with * Browserify. */ gulp.task('browserify', ['tsc'], function() { // Ensure that the build directory exists fs.ensureDirSync(buildDir); let browserifyOptions = { basedir: buildDir, debug: true, entries: [`../${outDir}/xterm.js`], standalone: 'Terminal', cache: {}, packageCache: {} }; let bundleStream = browserify(browserifyOptions) .bundle() .pipe(source('xterm.js')) .pipe(buffer()) .pipe(sourcemaps.init({loadMaps: true, sourceRoot: '..'})) .pipe(sourcemaps.write('./')) .pipe(gulp.dest(buildDir)); // Copy all add-ons from ${outDir}/ to buildDir let copyAddons = gulp.src(`${outDir}/addons/**/*`).pipe(gulp.dest(`${buildDir}/addons`)); // Copy stylesheets from ${outDir}/ to ${buildDir}/ let copyStylesheets = gulp.src(`${outDir}/**/*.css`).pipe(gulp.dest(buildDir)); return merge(bundleStream, copyAddons, copyStylesheets); }); gulp.task('instrument-test', function () { return gulp.src([`${outDir}/**/*.js`]) // Covering files .pipe(istanbul()) // Force `require` to return covered files .pipe(istanbul.hookRequire()); }); gulp.task('mocha', ['instrument-test'], function () { return gulp.src([`${outDir}/*test.js`, `${outDir}/**/*test.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`); chain.apply(); chain.writeSync(); }); /** * Submit coverage results to coveralls.io */ gulp.task('coveralls', function () { gulp.src('coverage/**/lcov.info') .pipe(coveralls()); }); gulp.task('build', ['sorcery']); gulp.task('test', ['mocha']); gulp.task('default', ['build']); xterm.js-2.7.0/jsdoc.json000066400000000000000000000006761311554223300152770ustar00rootroot00000000000000{ "source": { "include": [ "src/" ], "exclude": [ "src/test/" ], "excludePattern": "src/.+\\.test\\.(js|ts)$" }, "opts": { "readme": "README.md", "template": "node_modules/docdash", "encoding": "utf8", "destination": "docs/", "recurse": true, "verbose": true }, "plugins": [ "plugins/markdown" ], "templates": { "cleverLinks": false, "monospaceLinks": false } } xterm.js-2.7.0/logo.png000066400000000000000000000203761311554223300147470ustar00rootroot00000000000000PNG  IHDR[sRGB IDATx ű/@P\QAjPYDP$(Ae\ y!DQ-s{&&(dy7 $\@P% Qd_+ruNO93s7TWWW{ަju"(E@K«勢"(@"ƪx^S(@ *oJUExPcUy)WE oPc7Y*"P*޼ה+"7ʛREE@(^XokE@XMV"/j75劀" j&TQE@P5VśrE@P5VyU"(ŋ{M"(y*UTPE@U潦\PA@Ud*(@"ƪx^S(@ POjK,) NE@hzL_oZhܹ_匒Ayuv޽bF-Zπ]P#СC(#S իWmWh`p _Tm…;jժ7Tн{Hbk 슀"dFT2#߷o]ֶ+-;\`}BO*t&4"(DDcZo۶K",,/^Gcxu̪)"ѩBI&CCX 6/x2uA)"(YB`x,Q P)0{YƥÝ~m@xύ#PY ,X"Dڭ 3u9@Jt|Fё0mD0 ,gϞ(>"0D"a\J`2.L N(@V9h.{l6E2lL?B<;uICE RztE@p7S1RM=/YT1fE ng};ށ~/s _M'lD$bO5@!ǿ_\2C*NՔ-fl]z>˷,ߎx7UD@NVu9u\lL~.^ou+U@* !"Ny* F>nüG Ka8t^=mٲX:WPޚ~s> zJ_S߯81Nv/|/YJ:䛽Wɟ;x2t)1hWc!>W;.#Z{y4"?+mS̳NCO3 ϕ:_{F#KA̿ZH9_w}(ou`h&)F]_>ꈬ6\r(l_lgSQeA䥓7eH܆U6 HArokٮ.(Ϙt;>AdQGp!c (1^ˋ),݆##ssFdzwR I^zʩerrb_Q Lv!쥄n>Sfom z.i9%@y2^rOB1|9S+'5+##x0Lg-2)@ YGh4 F]`~ USu B*˨PI]>ABH6!6{4ɧA t\fd'QF?+֪y"#؛pP /|׿"9.+VXNݏj*IY}\]ʨZPJwԜMCO)p5¦Bbgqa[ɔ#x! 8h􄯜ј),ȨjsBIG?w ʹQѡ$Lof>_q#+ Ug #HY+t}LyX-A )2@]FP8]Ĉ֭[eZr p{yK6x)At.'q2tVd-3Qc*k6ԧk]62ſ+c8c2e(=_nΝh> ;=`b乐44^)„0pp2TR&r W$9]sM>hW_J90es'v鐔rIcݻw̢~SԌrv v}+Cy<8HPBs^ڎFb; ~/X^)hdI2c{A o0|b̙52F2[Y3fua&YQ>F'/\ +FAJPI;ctdtQ$A;tJ.; 7e͛C-_NnjlӀF; }o?q\'@@ACdgDږr =Ўic;4 IdT'o]=4ƕPlQ'[xJn DB(k Z_sw^z "-a$f"7)W2SYe#lѓ)-BEf4(8dF^ 5t^}'hŭϝs9{!S6h& =]8LL[xj)rf&-w޽{eGM/ 3&t[gc ^.EOoX(ѾPbhVN„wM6(j}Ǡ7qE3յI/gӦ7=a. FRYLߑ-kdȍRlʙ{!> r:OS`<S?޼Uʿf[srOώrP62LߡkwZXAӑ|dB+q(LMLVvI򟨝NGL.yhV(L 5 HL@R ۶ 6L|.`1Di@ƿEJ[:Ǯ*+FKě)-z<ou࿇٧jpEX1Z9pK ]d %Hv!{cPQbiW WrFFk\gԓ:ݮTPw:._0pV; 5Rl@D@T}OgrɃhTyqt pG m?WwN]O#_]wxĉAq}T"^xb|1m 0ؓ q q> a^_{2vB b{N904wS.^E 'M[~vXSڳ+PsDVwmwN!%|+)L! 2);F?t/Zȇ(z 3l:)p;mICFwu-JSodh^`mtS6\U'VRC_bCEo`6b4t=#Szqrz" ^8^U5.ϡ&w&zFϰM~NPrڴz6(maa^Ɗv!R#!… "2*~hwP6D]/c~{WL2]{ۘD}Wb;ٗ)'5#`/FkArBcE ?:ʕ+!2nRS0#!e1}p?LoMz|FOڌ.sm%ٮJ[08;t+KI9>I< L?/pr&y_ِkBG3=hƊ֚N2#C ]egOMd2LFJq<2ϰ#'6нC+:qZBt\dO"Po_2r a\JHacdK|^;bd!MSjvڗː4cT{zNB^UC.UlS[Y1Xy!M_o;Bm;K#0@Ba1ಐNBq,0ܝ ͕$`1k +}z]njHoHtu 8?kj-]4j.EWƣH?v(xj8FbJҶ~&S8-lCXG*lΝ;F2;nIɘjw1$QqQF^q6tڹяSǂ+F*AÅg6gP(! EKJJsyVҋ^-z$ 36C3LN\gZc#^OňiWțw\c=Rr#@GNrJC 4]!H:ؓѢH%O]֦:_9ݾ&{ξ+@kOcHPmlpȘCW٪)'jnUb/'AH/ǵ~|u/A!xK(hkHY 0XO0nvg8aNufE͏ʓ#~voشiày(ԏԏ+v6wJ+a1`ƍ> GdriƦCJkNCd$U;@|]첖D/B(teG#;+Paޠ܅NVk}Ygnї=3\qc mhSX-:.cx?½9JMNa]=9%q5FƍANı}d*u |M>( ;:gţSi9g4 \ V-{: uMa֓+VNݛMXfs] Zr~z9~ɳ@{4V$*f1 AKO%sMk2&pW^c8е Xw=3(1(7:ׯ#7HduHJ;>}d*a**Qc!*]oD##k~S/n< $mP\;D$Iݚ_l@W|$lⷐhiԂSe t ]{VZ?3AթSga֚ሳ;v;v"e 2D%7dVFNs)R̹He*Rh.Fpo`侴+'PǧiOKP2x{m!%\7.hSZYk[f٦ޟ_ Ҽy 0툓N >i 7^`O"#21C΅p'Lx<2N^Q.FTC7T)/1)S{0w8hdYU:fSyeo,-04i"Cٌ:;Y0RFx3a2SLZAI򝂼 yߓeگM8K?MQ7 q\(*A\y%W^N+GBשSCw18/G 8 |zmtzz=Sf޵Kb/Q 锇X?nL_Uو,G;# P.{>*n`w>Ia%&%}yH* W.)p50IAnBAUW7x:߷9optiN'znET5ZWZZF 6mIlZF+/6UԸ(hf3)hJg@,YfV1w *:,U"̠<xŨ { let terminal; let compositionHelper; let compositionView; let textarea; let handledText; beforeEach(() => { compositionView = { classList: { add: () => {}, remove: () => {}, }, getBoundingClientRect: () => { return { width: 0 }; }, style: { left: 0, top: 0 }, textContent: '' }; textarea = { value: '', style: { left: 0, top: 0 } }; terminal = { element: { querySelector: () => { return { offsetLeft: 0, offsetTop: 0 }; } }, handler: function (text) { handledText += text; } }; handledText = ''; compositionHelper = new CompositionHelper(textarea, compositionView, terminal); }); describe('Input', () => { it('Should insert simple characters', function (done) { // First character 'ㅇ' compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'ㅇ' }); textarea.value = 'ㅇ'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); setTimeout(() => { // wait for any textarea updates assert.equal(handledText, 'ㅇ'); // Second character 'ㅇ' compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'ㅇ' }); textarea.value = 'ㅇㅇ'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); setTimeout(() => { // wait for any textarea updates assert.equal(handledText, 'ㅇㅇ'); done(); }, 0); }, 0); }, 0); }, 0); }); it('Should insert complex characters', function (done) { // First character '앙' compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'ㅇ' }); textarea.value = 'ㅇ'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: '아' }); textarea.value = '아'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: '앙' }); textarea.value = '앙'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); setTimeout(() => { // wait for any textarea updates assert.equal(handledText, '앙'); // Second character '앙' compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'ㅇ' }); textarea.value = '앙ㅇ'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: '아' }); textarea.value = '앙아'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: '앙' }); textarea.value = '앙앙'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); setTimeout(() => { // wait for any textarea updates assert.equal(handledText, '앙앙'); done(); }, 0); }, 0); }, 0); }, 0); }, 0); }, 0); }, 0); }, 0); }); it('Should insert complex characters that change with following character', function (done) { // First character '아' compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'ㅇ' }); textarea.value = 'ㅇ'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: '아' }); textarea.value = '아'; setTimeout(() => { // wait for any textarea updates // Start second character '아' in first character compositionHelper.compositionupdate({ data: '앙' }); textarea.value = '앙'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: '아' }); textarea.value = '아아'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); setTimeout(() => { // wait for any textarea updates assert.equal(handledText, '아아'); done(); }, 0); }, 0); }, 0); }, 0); }, 0); }); it('Should insert multi-characters compositions', function (done) { // First character 'だ' compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'd' }); textarea.value = 'd'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: 'だ' }); textarea.value = 'だ'; setTimeout(() => { // wait for any textarea updates // Second character 'あ' compositionHelper.compositionupdate({ data: 'だあ' }); textarea.value = 'だあ'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); setTimeout(() => { // wait for any textarea updates assert.equal(handledText, 'だあ'); done(); }, 0); }, 0); }, 0); }, 0); }); it('Should insert multi-character compositions that are converted to other characters with the same length', function (done) { // First character 'だ' compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'd' }); textarea.value = 'd'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: 'だ' }); textarea.value = 'だ'; setTimeout(() => { // wait for any textarea updates // Second character 'ー' compositionHelper.compositionupdate({ data: 'だー' }); textarea.value = 'だー'; setTimeout(() => { // wait for any textarea updates // Convert to katakana 'ダー' compositionHelper.compositionupdate({ data: 'ダー' }); textarea.value = 'ダー'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); setTimeout(() => { // wait for any textarea updates assert.equal(handledText, 'ダー'); done(); }, 0); }, 0); }, 0); }, 0); }, 0); }); it('Should insert multi-character compositions that are converted to other characters with different lengths', function (done) { // First character 'い' compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'い' }); textarea.value = 'い'; setTimeout(() => { // wait for any textarea updates // Second character 'ま' compositionHelper.compositionupdate({ data: 'いm' }); textarea.value = 'いm'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionupdate({ data: 'いま' }); textarea.value = 'いま'; setTimeout(() => { // wait for any textarea updates // Convert to kanji '今' compositionHelper.compositionupdate({ data: '今' }); textarea.value = '今'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); setTimeout(() => { // wait for any textarea updates assert.equal(handledText, '今'); done(); }, 0); }, 0); }, 0); }, 0); }, 0); }); it('Should insert non-composition characters input immediately after composition characters', function (done) { // First character 'ㅇ' compositionHelper.compositionstart(); compositionHelper.compositionupdate({ data: 'ㅇ' }); textarea.value = 'ㅇ'; setTimeout(() => { // wait for any textarea updates compositionHelper.compositionend(); // Second character '1' (a non-composition character) textarea.value = 'ㅇ1'; setTimeout(() => { // wait for any textarea updates assert.equal(handledText, 'ㅇ1'); done(); }, 0); }, 0); }); }); }); xterm.js-2.7.0/src/CompositionHelper.ts000066400000000000000000000213671311554223300201040ustar00rootroot00000000000000/** * @license MIT */ import { ITerminal } from './Interfaces'; interface IPosition { start: number; end: number; } /** * Encapsulates the logic for handling compositionstart, compositionupdate and compositionend * events, displaying the in-progress composition to the UI and forwarding the final composition * to the handler. */ export class CompositionHelper { /** * Whether input composition is currently happening, eg. via a mobile keyboard, speech input or * IME. This variable determines whether the compositionText should be displayed on the UI. */ private isComposing: boolean; /** * The position within the input textarea's value of the current composition. */ private compositionPosition: IPosition; /** * Whether a composition is in the process of being sent, setting this to false will cancel any * in-progress composition. */ private isSendingComposition: boolean; /** * Creates a new CompositionHelper. * @param textarea The textarea that xterm uses for input. * @param compositionView The element to display the in-progress composition in. * @param terminal The Terminal to forward the finished composition to. */ constructor( private textarea: HTMLTextAreaElement, private compositionView: HTMLElement, private terminal: ITerminal ) { this.isComposing = false; this.isSendingComposition = false; this.compositionPosition = { start: null, end: null }; } /** * Handles the compositionstart event, activating the composition view. */ public compositionstart() { this.isComposing = true; this.compositionPosition.start = this.textarea.value.length; this.compositionView.textContent = ''; this.compositionView.classList.add('active'); } /** * Handles the compositionupdate event, updating the composition view. * @param {CompositionEvent} ev The event. */ public compositionupdate(ev: CompositionEvent) { this.compositionView.textContent = ev.data; this.updateCompositionElements(); setTimeout(() => { this.compositionPosition.end = this.textarea.value.length; }, 0); } /** * Handles the compositionend event, hiding the composition view and sending the composition to * the handler. */ public compositionend() { this.finalizeComposition(true); } /** * Handles the keydown event, routing any necessary events to the CompositionHelper functions. * @param ev The keydown event. * @return Whether the Terminal should continue processing the keydown event. */ public keydown(ev: KeyboardEvent) { if (this.isComposing || this.isSendingComposition) { if (ev.keyCode === 229) { // Continue composing if the keyCode is the "composition character" return false; } else if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) { // Continue composing if the keyCode is a modifier key return false; } else { // Finish composition immediately. This is mainly here for the case where enter is // pressed and the handler needs to be triggered before the command is executed. this.finalizeComposition(false); } } if (ev.keyCode === 229) { // If the "composition character" is used but gets to this point it means a non-composition // character (eg. numbers and punctuation) was pressed when the IME was active. this.handleAnyTextareaChanges(); return false; } return true; } /** * Finalizes the composition, resuming regular input actions. This is called when a composition * is ending. * @param waitForPropogation Whether to wait for events to propogate before sending * the input. This should be false if a non-composition keystroke is entered before the * compositionend event is triggered, such as enter, so that the composition is send before * the command is executed. */ private finalizeComposition(waitForPropogation: boolean) { this.compositionView.classList.remove('active'); this.isComposing = false; this.clearTextareaPosition(); if (!waitForPropogation) { // Cancel any delayed composition send requests and send the input immediately. this.isSendingComposition = false; const input = this.textarea.value.substring(this.compositionPosition.start, this.compositionPosition.end); this.terminal.handler(input); } else { // Make a deep copy of the composition position here as a new compositionstart event may // fire before the setTimeout executes. const currentCompositionPosition = { start: this.compositionPosition.start, end: this.compositionPosition.end, }; // Since composition* events happen before the changes take place in the textarea on most // browsers, use a setTimeout with 0ms time to allow the native compositionend event to // complete. This ensures the correct character is retrieved, this solution was used // because: // - The compositionend event's data property is unreliable, at least on Chromium // - The last compositionupdate event's data property does not always accurately describe // the character, a counter example being Korean where an ending consonsant can move to // the following character if the following input is a vowel. this.isSendingComposition = true; setTimeout(() => { // Ensure that the input has not already been sent if (this.isSendingComposition) { this.isSendingComposition = false; let input; if (this.isComposing) { // Use the end position to get the string if a new composition has started. input = this.textarea.value.substring(currentCompositionPosition.start, currentCompositionPosition.end); } else { // Don't use the end position here in order to pick up any characters after the // composition has finished, for example when typing a non-composition character // (eg. 2) after a composition character. input = this.textarea.value.substring(currentCompositionPosition.start); } this.terminal.handler(input); } }, 0); } } /** * Apply any changes made to the textarea after the current event chain is allowed to complete. * This should be called when not currently composing but a keydown event with the "composition * character" (229) is triggered, in order to allow non-composition text to be entered when an * IME is active. */ private handleAnyTextareaChanges() { const oldValue = this.textarea.value; setTimeout(() => { // Ignore if a composition has started since the timeout if (!this.isComposing) { const newValue = this.textarea.value; const diff = newValue.replace(oldValue, ''); if (diff.length > 0) { this.terminal.handler(diff); } } }, 0); } /** * Positions the composition view on top of the cursor and the textarea just below it (so the * IME helper dialog is positioned correctly). * @param dontRecurse Whether to use setTimeout to recursively trigger another update, this is * necessary as the IME events across browsers are not consistently triggered. */ public updateCompositionElements(dontRecurse?: boolean) { if (!this.isComposing) { return; } const cursor = this.terminal.element.querySelector('.terminal-cursor'); if (cursor) { // Take .xterm-rows offsetTop into account as well in case it's positioned absolutely within // the .xterm element. const xtermRows = this.terminal.element.querySelector('.xterm-rows'); const cursorTop = xtermRows.offsetTop + cursor.offsetTop; this.compositionView.style.left = cursor.offsetLeft + 'px'; this.compositionView.style.top = cursorTop + 'px'; this.compositionView.style.height = cursor.offsetHeight + 'px'; this.compositionView.style.lineHeight = cursor.offsetHeight + 'px'; // Sync the textarea to the exact position of the composition view so the IME knows where the // text is. const compositionViewBounds = this.compositionView.getBoundingClientRect(); this.textarea.style.left = cursor.offsetLeft + 'px'; this.textarea.style.top = cursorTop + 'px'; this.textarea.style.width = compositionViewBounds.width + 'px'; this.textarea.style.height = compositionViewBounds.height + 'px'; this.textarea.style.lineHeight = compositionViewBounds.height + 'px'; } if (!dontRecurse) { setTimeout(() => this.updateCompositionElements(true), 0); } }; /** * Clears the textarea's position so that the cursor does not blink on IE. * @private */ private clearTextareaPosition() { this.textarea.style.left = ''; this.textarea.style.top = ''; }; } xterm.js-2.7.0/src/EscapeSequences.ts000066400000000000000000000046351311554223300175140ustar00rootroot00000000000000/** * @license MIT */ /** * C0 control codes * See = https://en.wikipedia.org/wiki/C0_and_C1_control_codes */ export namespace C0 { /** Null (Caret = ^@, C = \0) */ export const NUL = '\x00'; /** Start of Heading (Caret = ^A) */ export const SOH = '\x01'; /** Start of Text (Caret = ^B) */ export const STX = '\x02'; /** End of Text (Caret = ^C) */ export const ETX = '\x03'; /** End of Transmission (Caret = ^D) */ export const EOT = '\x04'; /** Enquiry (Caret = ^E) */ export const ENQ = '\x05'; /** Acknowledge (Caret = ^F) */ export const ACK = '\x06'; /** Bell (Caret = ^G, C = \a) */ export const BEL = '\x07'; /** Backspace (Caret = ^H, C = \b) */ export const BS = '\x08'; /** Character Tabulation, Horizontal Tabulation (Caret = ^I, C = \t) */ export const HT = '\x09'; /** Line Feed (Caret = ^J, C = \n) */ export const LF = '\x0a'; /** Line Tabulation, Vertical Tabulation (Caret = ^K, C = \v) */ export const VT = '\x0b'; /** Form Feed (Caret = ^L, C = \f) */ export const FF = '\x0c'; /** Carriage Return (Caret = ^M, C = \r) */ export const CR = '\x0d'; /** Shift Out (Caret = ^N) */ export const SO = '\x0e'; /** Shift In (Caret = ^O) */ export const SI = '\x0f'; /** Data Link Escape (Caret = ^P) */ export const DLE = '\x10'; /** Device Control One (XON) (Caret = ^Q) */ export const DC1 = '\x11'; /** Device Control Two (Caret = ^R) */ export const DC2 = '\x12'; /** Device Control Three (XOFF) (Caret = ^S) */ export const DC3 = '\x13'; /** Device Control Four (Caret = ^T) */ export const DC4 = '\x14'; /** Negative Acknowledge (Caret = ^U) */ export const NAK = '\x15'; /** Synchronous Idle (Caret = ^V) */ export const SYN = '\x16'; /** End of Transmission Block (Caret = ^W) */ export const ETB = '\x17'; /** Cancel (Caret = ^X) */ export const CAN = '\x18'; /** End of Medium (Caret = ^Y) */ export const EM = '\x19'; /** Substitute (Caret = ^Z) */ export const SUB = '\x1a'; /** Escape (Caret = ^[, C = \e) */ export const ESC = '\x1b'; /** File Separator (Caret = ^\) */ export const FS = '\x1c'; /** Group Separator (Caret = ^]) */ export const GS = '\x1d'; /** Record Separator (Caret = ^^) */ export const RS = '\x1e'; /** Unit Separator (Caret = ^_) */ export const US = '\x1f'; /** Space */ export const SP = '\x20'; /** Delete (Caret = ^?) */ export const DEL = '\x7f'; }; xterm.js-2.7.0/src/EventEmitter.test.ts000066400000000000000000000047471311554223300200350ustar00rootroot00000000000000import { assert } from 'chai'; import { EventEmitter } from './EventEmitter'; describe('EventEmitter', () => { let eventEmitter: EventEmitter; beforeEach(() => { eventEmitter = new EventEmitter(); }); describe('once', () => { it('should trigger the listener only once', () => { let count = 0; const listener = () => count++; eventEmitter.once('test', listener); eventEmitter.emit('test'); assert.equal(count, 1); eventEmitter.emit('test'); assert.equal(count, 1); }); }); describe('emit', () => { it('should emit events to listeners', () => { let count1 = 0; let count2 = 0; const listener1 = () => count1++; const listener2 = () => count2++; eventEmitter.on('test', listener1); eventEmitter.on('test', listener2); eventEmitter.emit('test'); assert.equal(count1, 1); assert.equal(count2, 1); eventEmitter.emit('test'); assert.equal(count1, 2); assert.equal(count2, 2); }); it('should manage multiple listener types', () => { let count1 = 0; let count2 = 0; const listener1 = () => count1++; const listener2 = () => count2++; eventEmitter.on('test', listener1); eventEmitter.on('foo', listener2); eventEmitter.emit('test'); assert.equal(count1, 1); assert.equal(count2, 0); eventEmitter.emit('foo'); assert.equal(count1, 1); assert.equal(count2, 1); }); }); describe('listeners', () => { it('should return listeners for the type requested', () => { assert.equal(eventEmitter.listeners('test').length, 0); const listener = () => {}; eventEmitter.on('test', listener); assert.deepEqual(eventEmitter.listeners('test'), [listener]); }); }); describe('off', () => { it('should remove the specific listener', () => { const listener1 = () => {}; const listener2 = () => {}; eventEmitter.on('foo', listener1); eventEmitter.on('foo', listener2); assert.equal(eventEmitter.listeners('foo').length, 2); eventEmitter.off('foo', listener1); assert.deepEqual(eventEmitter.listeners('foo'), [listener2]); }); }); describe('removeAllListeners', () => { it('should clear all listeners', () => { eventEmitter.on('foo', () => {}); assert.equal(eventEmitter.listeners('foo').length, 1); eventEmitter.removeAllListeners('foo'); assert.equal(eventEmitter.listeners('foo').length, 0); }); }); }); xterm.js-2.7.0/src/EventEmitter.ts000066400000000000000000000027321311554223300170470ustar00rootroot00000000000000/** * @license MIT */ interface ListenerType { (): void; listener?: () => void; }; export class EventEmitter { private _events: {[type: string]: ListenerType[]}; constructor() { // Restore the previous events if available, this will happen if the // constructor is called multiple times on the same object (terminal reset). this._events = this._events || {}; } public on(type, listener): void { this._events[type] = this._events[type] || []; this._events[type].push(listener); } public off(type, listener): void { if (!this._events[type]) { return; } let obj = this._events[type]; let i = obj.length; while (i--) { if (obj[i] === listener || obj[i].listener === listener) { obj.splice(i, 1); return; } } } public removeAllListeners(type): void { if (this._events[type]) { delete this._events[type]; } } public once(type, listener): any { function on() { let args = Array.prototype.slice.call(arguments); this.off(type, on); return listener.apply(this, args); } (on).listener = listener; return this.on(type, on); } public emit(type: string, ...args: any[]): void { if (!this._events[type]) { return; } let obj = this._events[type]; for (let i = 0; i < obj.length; i++) { obj[i].apply(this, args); } } public listeners(type): ListenerType[] { return this._events[type] || []; } } xterm.js-2.7.0/src/InputHandler.test.ts000066400000000000000000000030071311554223300200030ustar00rootroot00000000000000import { assert } from 'chai'; import { InputHandler } from './InputHandler'; describe('InputHandler', () => { describe('setCursorStyle', () => { it('should call Terminal.setOption with correct params', () => { let options = {}; let terminal = { setOption: (option, value) => options[option] = value }; let inputHandler = new InputHandler(terminal); inputHandler.setCursorStyle([0]); assert.equal(options['cursorStyle'], 'block'); assert.equal(options['cursorBlink'], true); options = {}; inputHandler.setCursorStyle([1]); assert.equal(options['cursorStyle'], 'block'); assert.equal(options['cursorBlink'], true); options = {}; inputHandler.setCursorStyle([2]); assert.equal(options['cursorStyle'], 'block'); assert.equal(options['cursorBlink'], false); options = {}; inputHandler.setCursorStyle([3]); assert.equal(options['cursorStyle'], 'underline'); assert.equal(options['cursorBlink'], true); options = {}; inputHandler.setCursorStyle([4]); assert.equal(options['cursorStyle'], 'underline'); assert.equal(options['cursorBlink'], false); options = {}; inputHandler.setCursorStyle([5]); assert.equal(options['cursorStyle'], 'bar'); assert.equal(options['cursorBlink'], true); options = {}; inputHandler.setCursorStyle([6]); assert.equal(options['cursorStyle'], 'bar'); assert.equal(options['cursorBlink'], false); }); }); }); xterm.js-2.7.0/src/InputHandler.ts000066400000000000000000001503311311554223300170300ustar00rootroot00000000000000/** * @license MIT */ import { IInputHandler, ITerminal } from './Interfaces'; import { C0 } from './EscapeSequences'; import { DEFAULT_CHARSET } from './Charsets'; /** * The terminal's standard implementation of IInputHandler, this handles all * input from the Parser. * * Refer to http://invisible-island.net/xterm/ctlseqs/ctlseqs.html to understand * each function's header comment. */ export class InputHandler implements IInputHandler { // TODO: We want to type _terminal when it's pulled into TS constructor(private _terminal: any) { } public addChar(char: string, code: number): void { if (char >= ' ') { // calculate print space // expensive call, therefore we save width in line buffer const ch_width = wcwidth(code); if (this._terminal.charset && this._terminal.charset[char]) { char = this._terminal.charset[char]; } let row = this._terminal.y + this._terminal.ybase; // insert combining char in last cell // FIXME: needs handling after cursor jumps if (!ch_width && this._terminal.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]) { // 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; } else { this._terminal.lines.get(row)[this._terminal.x - 1][1] += char; } this._terminal.updateRange(this._terminal.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) { // autowrap - DECAWM if (this._terminal.wraparoundMode) { this._terminal.x = 0; this._terminal.y++; if (this._terminal.y > this._terminal.scrollBottom) { this._terminal.y--; this._terminal.scroll(); } } else { if (ch_width === 2) // FIXME: check for xterm behavior return; } } row = this._terminal.y + this._terminal.ybase; // insert mode: move characters to right if (this._terminal.insertMode) { // do this twice for a fullwidth char 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(); 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]; // insert empty cell at cursor this._terminal.lines.get(row).splice(this._terminal.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); // 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++; } } } /** * BEL * Bell (Ctrl-G). */ public bell(): void { if (!this._terminal.visualBell) { return; } this._terminal.element.style.borderColor = 'white'; setTimeout(() => this._terminal.element.style.borderColor = '', 10); if (this._terminal.popOnBell) { this._terminal.focus(); } } /** * LF * Line Feed or New Line (NL). (LF is Ctrl-J). */ public lineFeed(): void { if (this._terminal.convertEol) { this._terminal.x = 0; } this._terminal.y++; if (this._terminal.y > this._terminal.scrollBottom) { this._terminal.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--; } } /** * CR * Carriage Return (Ctrl-M). */ public carriageReturn(): void { this._terminal.x = 0; } /** * BS * Backspace (Ctrl-H). */ public backspace(): void { if (this._terminal.x > 0) { this._terminal.x--; } } /** * TAB * Horizontal Tab (HT) (Ctrl-I). */ public tab(): void { this._terminal.x = this._terminal.nextStop(); } /** * SO * Shift Out (Ctrl-N) -> Switch to Alternate Character Set. This invokes the * G1 character set. */ public shiftOut(): void { this._terminal.setgLevel(1); } /** * SI * Shift In (Ctrl-O) -> Switch to Standard Character Set. This invokes the G0 * character set (the default). */ public shiftIn(): void { this._terminal.setgLevel(0); } /** * CSI Ps @ * Insert Ps (Blank) Character(s) (default = 1) (ICH). */ public insertChars(params: number[]): void { let param, row, j, ch; param = params[0]; if (param < 1) param = 1; row = this._terminal.y + this._terminal.ybase; j = this._terminal.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(); } } /** * CSI Ps A * Cursor Up Ps Times (default = 1) (CUU). */ public cursorUp(params: number[]): void { let param = params[0]; if (param < 1) { param = 1; } this._terminal.y -= param; if (this._terminal.y < 0) { this._terminal.y = 0; } } /** * CSI Ps B * Cursor Down Ps Times (default = 1) (CUD). */ public cursorDown(params: number[]) { let param = params[0]; if (param < 1) { param = 1; } this._terminal.y += param; if (this._terminal.y >= this._terminal.rows) { this._terminal.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--; } } /** * CSI Ps C * Cursor Forward Ps Times (default = 1) (CUF). */ public cursorForward(params: number[]) { let param = params[0]; if (param < 1) { param = 1; } this._terminal.x += param; if (this._terminal.x >= this._terminal.cols) { this._terminal.x = this._terminal.cols - 1; } } /** * CSI Ps D * Cursor Backward Ps Times (default = 1) (CUB). */ public cursorBackward(params: number[]) { let param = params[0]; if (param < 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--; } this._terminal.x -= param; if (this._terminal.x < 0) { this._terminal.x = 0; } } /** * CSI Ps E * Cursor Next Line Ps Times (default = 1) (CNL). * same as CSI Ps B ? */ public cursorNextLine(params: number[]): void { let param = params[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.x = 0; }; /** * CSI Ps F * Cursor Preceding Line Ps Times (default = 1) (CNL). * reuse CSI Ps A ? */ public cursorPrecedingLine(params: number[]): void { let param = params[0]; if (param < 1) { param = 1; } this._terminal.y -= param; if (this._terminal.y < 0) { this._terminal.y = 0; } this._terminal.x = 0; }; /** * CSI Ps G * Cursor Character Absolute [column] (default = [row,1]) (CHA). */ public cursorCharAbsolute(params: number[]): void { let param = params[0]; if (param < 1) { param = 1; } this._terminal.x = param - 1; } /** * CSI Ps ; Ps H * Cursor Position [row;column] (default = [1,1]) (CUP). */ public cursorPosition(params: number[]): void { let row, col; row = params[0] - 1; if (params.length >= 2) { col = params[1] - 1; } else { col = 0; } if (row < 0) { row = 0; } else if (row >= this._terminal.rows) { row = this._terminal.rows - 1; } if (col < 0) { col = 0; } else if (col >= this._terminal.cols) { col = this._terminal.cols - 1; } this._terminal.x = col; this._terminal.y = row; } /** * CSI Ps I * Cursor Forward Tabulation Ps tab stops (default = 1) (CHT). */ public cursorForwardTab(params: number[]): void { let param = params[0] || 1; while (param--) { this._terminal.x = this._terminal.nextStop(); } } /** * CSI Ps J Erase in Display (ED). * Ps = 0 -> Erase Below (default). * Ps = 1 -> Erase Above. * Ps = 2 -> Erase All. * Ps = 3 -> Erase Saved Lines (xterm). * CSI ? Ps J * Erase in Display (DECSED). * Ps = 0 -> Selective Erase Below (default). * Ps = 1 -> Selective Erase Above. * Ps = 2 -> Selective Erase All. */ public eraseInDisplay(params: number[]): void { let j; switch (params[0]) { case 0: this._terminal.eraseRight(this._terminal.x, this._terminal.y); j = this._terminal.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; while (j--) { this._terminal.eraseLine(j); } break; case 2: j = this._terminal.rows; while (j--) this._terminal.eraseLine(j); break; case 3: // Clear scrollback (everything not in viewport) const scrollBackSize = this._terminal.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); } break; } } /** * CSI Ps K Erase in Line (EL). * Ps = 0 -> Erase to Right (default). * Ps = 1 -> Erase to Left. * Ps = 2 -> Erase All. * CSI ? Ps K * Erase in Line (DECSEL). * Ps = 0 -> Selective Erase to Right (default). * Ps = 1 -> Selective Erase to Left. * Ps = 2 -> Selective Erase All. */ public eraseInLine(params: number[]): void { switch (params[0]) { case 0: this._terminal.eraseRight(this._terminal.x, this._terminal.y); break; case 1: this._terminal.eraseLeft(this._terminal.x, this._terminal.y); break; case 2: this._terminal.eraseLine(this._terminal.y); break; } } /** * CSI Ps L * Insert Ps Line(s) (default = 1) (IL). */ public insertLines(params: number[]): void { let param, row, j; param = params[0]; if (param < 1) { param = 1; } row = this._terminal.y + this._terminal.ybase; j = this._terminal.rows - 1 - this._terminal.scrollBottom; j = this._terminal.rows - 1 + this._terminal.ybase - j + 1; while (param--) { if (this._terminal.lines.length === this._terminal.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--; 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.maxRange(); this._terminal.updateRange(this._terminal.y); this._terminal.updateRange(this._terminal.scrollBottom); } /** * CSI Ps M * Delete Ps Line(s) (default = 1) (DL). */ public deleteLines(params: number[]): void { let param, row, j; param = params[0]; if (param < 1) { param = 1; } row = this._terminal.y + this._terminal.ybase; j = this._terminal.rows - 1 - this._terminal.scrollBottom; j = this._terminal.rows - 1 + this._terminal.ybase - j; while (param--) { if (this._terminal.lines.length === this._terminal.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; } // 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.maxRange(); this._terminal.updateRange(this._terminal.y); this._terminal.updateRange(this._terminal.scrollBottom); } /** * CSI Ps P * Delete Ps Character(s) (default = 1) (DCH). */ public deleteChars(params: number[]): void { let param, row, ch; param = params[0]; if (param < 1) { param = 1; } row = this._terminal.y + this._terminal.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); } } /** * CSI Ps S Scroll up Ps lines (default = 1) (SU). */ 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.maxRange(); this._terminal.updateRange(this._terminal.scrollTop); this._terminal.updateRange(this._terminal.scrollBottom); } /** * CSI Ps T Scroll down Ps lines (default = 1) (SD). */ 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.maxRange(); this._terminal.updateRange(this._terminal.scrollTop); this._terminal.updateRange(this._terminal.scrollBottom); } /** * CSI Ps X * Erase Ps Character(s) (default = 1) (ECH). */ public eraseChars(params: number[]): void { let param, row, j, ch; param = params[0]; if (param < 1) { param = 1; } row = this._terminal.y + this._terminal.ybase; j = this._terminal.x; ch = [this._terminal.eraseAttr(), ' ', 1]; // xterm while (param-- && j < this._terminal.cols) { this._terminal.lines.get(row)[j++] = ch; } } /** * CSI Ps Z Cursor Backward Tabulation Ps tab stops (default = 1) (CBT). */ public cursorBackwardTab(params: number[]): void { let param = params[0] || 1; while (param--) { this._terminal.x = this._terminal.prevStop(); } } /** * CSI Pm ` Character Position Absolute * [column] (default = [row,1]) (HPA). */ public charPosAbsolute(params: number[]): void { let param = params[0]; if (param < 1) { param = 1; } this._terminal.x = param - 1; if (this._terminal.x >= this._terminal.cols) { this._terminal.x = this._terminal.cols - 1; } } /** * CSI Pm a Character Position Relative * [columns] (default = [row,col+1]) (HPR) * reuse CSI Ps C ? */ public HPositionRelative(params: number[]): void { let param = params[0]; if (param < 1) { param = 1; } this._terminal.x += param; if (this._terminal.x >= this._terminal.cols) { this._terminal.x = this._terminal.cols - 1; } } /** * CSI Ps b Repeat the preceding graphic character Ps times (REP). */ 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]; while (param--) { line[this._terminal.x++] = ch; } } /** * CSI Ps c Send Device Attributes (Primary DA). * Ps = 0 or omitted -> request attributes from terminal. The * response depends on the decTerminalID resource setting. * -> CSI ? 1 ; 2 c (``VT100 with Advanced Video Option'') * -> CSI ? 1 ; 0 c (``VT101 with No Options'') * -> CSI ? 6 c (``VT102'') * -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c (``VT220'') * The VT100-style response parameters do not mean anything by * themselves. VT220 parameters do, telling the host what fea- * tures the terminal supports: * Ps = 1 -> 132-columns. * Ps = 2 -> Printer. * Ps = 6 -> Selective erase. * Ps = 8 -> User-defined keys. * Ps = 9 -> National replacement character sets. * Ps = 1 5 -> Technical characters. * Ps = 2 2 -> ANSI color, e.g., VT525. * Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode). * CSI > Ps c * Send Device Attributes (Secondary DA). * Ps = 0 or omitted -> request the terminal's identification * code. The response depends on the decTerminalID resource set- * ting. It should apply only to VT220 and up, but xterm extends * this to VT100. * -> CSI > Pp ; Pv ; Pc c * where Pp denotes the terminal type * Pp = 0 -> ``VT100''. * Pp = 1 -> ``VT220''. * and Pv is the firmware version (for xterm, this was originally * the XFree86 patch number, starting with 95). In a DEC termi- * nal, Pc indicates the ROM cartridge registration number and is * always zero. * More information: * xterm/charproc.c - line 2012, for more information. * vim responds with ^[[?0c or ^[[?1c after the terminal's response (?) */ public sendDeviceAttributes(params: number[]): void { if (params[0] > 0) { return; } if (!this._terminal.prefix) { if (this._terminal.is('xterm') || this._terminal.is('rxvt-unicode') || this._terminal.is('screen')) { this._terminal.send(C0.ESC + '[?1;2c'); } else if (this._terminal.is('linux')) { this._terminal.send(C0.ESC + '[?6c'); } } else if (this._terminal.prefix === '>') { // xterm and urxvt // seem to spit this // out around ~370 times (?). if (this._terminal.is('xterm')) { this._terminal.send(C0.ESC + '[>0;276;0c'); } else if (this._terminal.is('rxvt-unicode')) { this._terminal.send(C0.ESC + '[>85;95;0c'); } else if (this._terminal.is('linux')) { // not supported by linux console. // linux console echoes parameters. this._terminal.send(params[0] + 'c'); } else if (this._terminal.is('screen')) { this._terminal.send(C0.ESC + '[>83;40003;0c'); } } } /** * CSI Pm d Vertical Position Absolute (VPA) * [row] (default = [1,column]) */ public linePosAbsolute(params: number[]): void { let param = params[0]; if (param < 1) { param = 1; } this._terminal.y = param - 1; if (this._terminal.y >= this._terminal.rows) { this._terminal.y = this._terminal.rows - 1; } } /** * CSI Pm e Vertical Position Relative (VPR) * [rows] (default = [row+1,column]) * reuse CSI Ps B ? */ public VPositionRelative(params: number[]): void { let param = params[0]; if (param < 1) { param = 1; } this._terminal.y += param; if (this._terminal.y >= this._terminal.rows) { this._terminal.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--; } } /** * CSI Ps ; Ps f * Horizontal and Vertical Position [row;column] (default = * [1,1]) (HVP). */ public HVPosition(params: number[]): void { 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.x = params[1] - 1; if (this._terminal.x >= this._terminal.cols) { this._terminal.x = this._terminal.cols - 1; } } /** * CSI Ps g Tab Clear (TBC). * Ps = 0 -> Clear Current Column (default). * Ps = 3 -> Clear All. * Potentially: * Ps = 2 -> Clear Stops on Line. * http://vt100.net/annarbor/aaa-ug/section6.html */ public tabClear(params: number[]): void { let param = params[0]; if (param <= 0) { delete this._terminal.tabs[this._terminal.x]; } else if (param === 3) { this._terminal.tabs = {}; } } /** * CSI Pm h Set Mode (SM). * Ps = 2 -> Keyboard Action Mode (AM). * Ps = 4 -> Insert Mode (IRM). * Ps = 1 2 -> Send/receive (SRM). * Ps = 2 0 -> Automatic Newline (LNM). * CSI ? Pm h * DEC Private Mode Set (DECSET). * Ps = 1 -> Application Cursor Keys (DECCKM). * Ps = 2 -> Designate USASCII for character sets G0-G3 * (DECANM), and set VT100 mode. * Ps = 3 -> 132 Column Mode (DECCOLM). * Ps = 4 -> Smooth (Slow) Scroll (DECSCLM). * Ps = 5 -> Reverse Video (DECSCNM). * Ps = 6 -> Origin Mode (DECOM). * Ps = 7 -> Wraparound Mode (DECAWM). * Ps = 8 -> Auto-repeat Keys (DECARM). * Ps = 9 -> Send Mouse X & Y on button press. See the sec- * tion Mouse Tracking. * Ps = 1 0 -> Show toolbar (rxvt). * Ps = 1 2 -> Start Blinking Cursor (att610). * Ps = 1 8 -> Print form feed (DECPFF). * Ps = 1 9 -> Set print extent to full screen (DECPEX). * Ps = 2 5 -> Show Cursor (DECTCEM). * Ps = 3 0 -> Show scrollbar (rxvt). * Ps = 3 5 -> Enable font-shifting functions (rxvt). * Ps = 3 8 -> Enter Tektronix Mode (DECTEK). * Ps = 4 0 -> Allow 80 -> 132 Mode. * Ps = 4 1 -> more(1) fix (see curses resource). * Ps = 4 2 -> Enable Nation Replacement Character sets (DECN- * RCM). * Ps = 4 4 -> Turn On Margin Bell. * Ps = 4 5 -> Reverse-wraparound Mode. * Ps = 4 6 -> Start Logging. This is normally disabled by a * compile-time option. * Ps = 4 7 -> Use Alternate Screen Buffer. (This may be dis- * abled by the titeInhibit resource). * Ps = 6 6 -> Application keypad (DECNKM). * Ps = 6 7 -> Backarrow key sends backspace (DECBKM). * Ps = 1 0 0 0 -> Send Mouse X & Y on button press and * release. See the section Mouse Tracking. * Ps = 1 0 0 1 -> Use Hilite Mouse Tracking. * Ps = 1 0 0 2 -> Use Cell Motion Mouse Tracking. * Ps = 1 0 0 3 -> Use All Motion Mouse Tracking. * Ps = 1 0 0 4 -> Send FocusIn/FocusOut events. * Ps = 1 0 0 5 -> Enable Extended Mouse Mode. * Ps = 1 0 1 0 -> Scroll to bottom on tty output (rxvt). * Ps = 1 0 1 1 -> Scroll to bottom on key press (rxvt). * Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit. * (enables the eightBitInput resource). * Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num- * Lock keys. (This enables the numLock resource). * Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This * enables the metaSendsEscape resource). * Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete * key. * Ps = 1 0 3 9 -> Send ESC when Alt modifies a key. (This * enables the altSendsEscape resource). * Ps = 1 0 4 0 -> Keep selection even if not highlighted. * (This enables the keepSelection resource). * Ps = 1 0 4 1 -> Use the CLIPBOARD selection. (This enables * the selectToClipboard resource). * Ps = 1 0 4 2 -> Enable Urgency window manager hint when * Control-G is received. (This enables the bellIsUrgent * resource). * Ps = 1 0 4 3 -> Enable raising of the window when Control-G * is received. (enables the popOnBell resource). * Ps = 1 0 4 7 -> Use Alternate Screen Buffer. (This may be * disabled by the titeInhibit resource). * Ps = 1 0 4 8 -> Save cursor as in DECSC. (This may be dis- * abled by the titeInhibit resource). * Ps = 1 0 4 9 -> Save cursor as in DECSC and use Alternate * Screen Buffer, clearing it first. (This may be disabled by * the titeInhibit resource). This combines the effects of the 1 * 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based * applications rather than the 4 7 mode. * Ps = 1 0 5 0 -> Set terminfo/termcap function-key mode. * Ps = 1 0 5 1 -> Set Sun function-key mode. * Ps = 1 0 5 2 -> Set HP function-key mode. * Ps = 1 0 5 3 -> Set SCO function-key mode. * Ps = 1 0 6 0 -> Set legacy keyboard emulation (X11R6). * Ps = 1 0 6 1 -> Set VT220 keyboard emulation. * Ps = 2 0 0 4 -> Set bracketed paste mode. * Modes: * http: *vt100.net/docs/vt220-rm/chapter4.html */ public setMode(params: number[]): void { if (params.length > 1) { for (let i = 0; i < params.length; i++) { this.setMode([params[i]]); } return; } if (!this._terminal.prefix) { switch (params[0]) { case 4: this._terminal.insertMode = true; break; case 20: // this._terminal.convertEol = true; break; } } else if (this._terminal.prefix === '?') { switch (params[0]) { case 1: this._terminal.applicationCursor = true; break; case 2: this._terminal.setgCharset(0, DEFAULT_CHARSET); this._terminal.setgCharset(1, DEFAULT_CHARSET); this._terminal.setgCharset(2, DEFAULT_CHARSET); this._terminal.setgCharset(3, DEFAULT_CHARSET); // set VT100 mode here break; case 3: // 132 col mode this._terminal.savedCols = this._terminal.cols; this._terminal.resize(132, this._terminal.rows); break; case 6: this._terminal.originMode = true; break; case 7: this._terminal.wraparoundMode = true; break; case 12: // this.cursorBlink = true; break; case 66: this._terminal.log('Serial port requested application keypad.'); this._terminal.applicationKeypad = true; this._terminal.viewport.syncScrollArea(); break; case 9: // X10 Mouse // no release, no motion, no wheel, no modifiers. case 1000: // vt200 mouse // no motion. // no modifiers, except control on the wheel. case 1002: // button event mouse case 1003: // any event mouse // any event - sends motion events, // even if there is no button held down. // TODO: Why are params[0] compares nested within a switch for params[0]? this._terminal.x10Mouse = params[0] === 9; this._terminal.vt200Mouse = params[0] === 1000; this._terminal.normalMouse = params[0] > 1000; this._terminal.mouseEvents = true; this._terminal.element.style.cursor = 'default'; this._terminal.log('Binding to mouse events.'); break; case 1004: // send focusin/focusout events // focusin: ^[[I // focusout: ^[[O this._terminal.sendFocus = true; break; case 1005: // utf8 ext mode mouse this._terminal.utfMouse = true; // for wide terminals // simply encodes large values as utf8 characters break; case 1006: // sgr ext mode mouse this._terminal.sgrMouse = true; // for wide terminals // does not add 32 to fields // press: ^[[ Keyboard Action Mode (AM). * Ps = 4 -> Replace Mode (IRM). * Ps = 1 2 -> Send/receive (SRM). * Ps = 2 0 -> Normal Linefeed (LNM). * CSI ? Pm l * DEC Private Mode Reset (DECRST). * Ps = 1 -> Normal Cursor Keys (DECCKM). * Ps = 2 -> Designate VT52 mode (DECANM). * Ps = 3 -> 80 Column Mode (DECCOLM). * Ps = 4 -> Jump (Fast) Scroll (DECSCLM). * Ps = 5 -> Normal Video (DECSCNM). * Ps = 6 -> Normal Cursor Mode (DECOM). * Ps = 7 -> No Wraparound Mode (DECAWM). * Ps = 8 -> No Auto-repeat Keys (DECARM). * Ps = 9 -> Don't send Mouse X & Y on button press. * Ps = 1 0 -> Hide toolbar (rxvt). * Ps = 1 2 -> Stop Blinking Cursor (att610). * Ps = 1 8 -> Don't print form feed (DECPFF). * Ps = 1 9 -> Limit print to scrolling region (DECPEX). * Ps = 2 5 -> Hide Cursor (DECTCEM). * Ps = 3 0 -> Don't show scrollbar (rxvt). * Ps = 3 5 -> Disable font-shifting functions (rxvt). * Ps = 4 0 -> Disallow 80 -> 132 Mode. * Ps = 4 1 -> No more(1) fix (see curses resource). * Ps = 4 2 -> Disable Nation Replacement Character sets (DEC- * NRCM). * Ps = 4 4 -> Turn Off Margin Bell. * Ps = 4 5 -> No Reverse-wraparound Mode. * Ps = 4 6 -> Stop Logging. (This is normally disabled by a * compile-time option). * Ps = 4 7 -> Use Normal Screen Buffer. * Ps = 6 6 -> Numeric keypad (DECNKM). * Ps = 6 7 -> Backarrow key sends delete (DECBKM). * Ps = 1 0 0 0 -> Don't send Mouse X & Y on button press and * release. See the section Mouse Tracking. * Ps = 1 0 0 1 -> Don't use Hilite Mouse Tracking. * Ps = 1 0 0 2 -> Don't use Cell Motion Mouse Tracking. * Ps = 1 0 0 3 -> Don't use All Motion Mouse Tracking. * Ps = 1 0 0 4 -> Don't send FocusIn/FocusOut events. * Ps = 1 0 0 5 -> Disable Extended Mouse Mode. * Ps = 1 0 1 0 -> Don't scroll to bottom on tty output * (rxvt). * Ps = 1 0 1 1 -> Don't scroll to bottom on key press (rxvt). * Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables * the eightBitInput resource). * Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num- * Lock keys. (This disables the numLock resource). * Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key. * (This disables the metaSendsEscape resource). * Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad * Delete key. * Ps = 1 0 3 9 -> Don't send ESC when Alt modifies a key. * (This disables the altSendsEscape resource). * Ps = 1 0 4 0 -> Do not keep selection when not highlighted. * (This disables the keepSelection resource). * Ps = 1 0 4 1 -> Use the PRIMARY selection. (This disables * the selectToClipboard resource). * Ps = 1 0 4 2 -> Disable Urgency window manager hint when * Control-G is received. (This disables the bellIsUrgent * resource). * Ps = 1 0 4 3 -> Disable raising of the window when Control- * G is received. (This disables the popOnBell resource). * Ps = 1 0 4 7 -> Use Normal Screen Buffer, clearing screen * first if in the Alternate Screen. (This may be disabled by * the titeInhibit resource). * Ps = 1 0 4 8 -> Restore cursor as in DECRC. (This may be * disabled by the titeInhibit resource). * Ps = 1 0 4 9 -> Use Normal Screen Buffer and restore cursor * as in DECRC. (This may be disabled by the titeInhibit * resource). This combines the effects of the 1 0 4 7 and 1 0 * 4 8 modes. Use this with terminfo-based applications rather * than the 4 7 mode. * Ps = 1 0 5 0 -> Reset terminfo/termcap function-key mode. * Ps = 1 0 5 1 -> Reset Sun function-key mode. * Ps = 1 0 5 2 -> Reset HP function-key mode. * Ps = 1 0 5 3 -> Reset SCO function-key mode. * Ps = 1 0 6 0 -> Reset legacy keyboard emulation (X11R6). * Ps = 1 0 6 1 -> Reset keyboard emulation to Sun/PC style. * Ps = 2 0 0 4 -> Reset bracketed paste mode. */ public resetMode(params: number[]): void { if (params.length > 1) { for (let i = 0; i < params.length; i++) { this.resetMode([params[i]]); } return; } if (!this._terminal.prefix) { switch (params[0]) { case 4: this._terminal.insertMode = false; break; case 20: // this._terminal.convertEol = false; break; } } else if (this._terminal.prefix === '?') { switch (params[0]) { case 1: this._terminal.applicationCursor = false; break; case 3: if (this._terminal.cols === 132 && this._terminal.savedCols) { this._terminal.resize(this._terminal.savedCols, this._terminal.rows); } delete this._terminal.savedCols; break; case 6: this._terminal.originMode = false; break; case 7: this._terminal.wraparoundMode = false; break; case 12: // this.cursorBlink = false; break; case 66: this._terminal.log('Switching back to normal keypad.'); this._terminal.applicationKeypad = false; this._terminal.viewport.syncScrollArea(); break; case 9: // X10 Mouse case 1000: // vt200 mouse case 1002: // button event mouse case 1003: // any event mouse this._terminal.x10Mouse = false; this._terminal.vt200Mouse = false; this._terminal.normalMouse = false; this._terminal.mouseEvents = false; this._terminal.element.style.cursor = ''; break; case 1004: // send focusin/focusout events this._terminal.sendFocus = false; break; case 1005: // utf8 ext mode mouse this._terminal.utfMouse = false; break; case 1006: // sgr ext mode mouse this._terminal.sgrMouse = false; break; case 1015: // urxvt ext mode mouse this._terminal.urxvtMouse = false; break; case 25: // hide cursor this._terminal.cursorHidden = true; break; case 1049: // alt screen buffer cursor ; // 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; // 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(); } break; } } } /** * CSI Pm m Character Attributes (SGR). * Ps = 0 -> Normal (default). * Ps = 1 -> Bold. * Ps = 4 -> Underlined. * Ps = 5 -> Blink (appears as Bold). * Ps = 7 -> Inverse. * Ps = 8 -> Invisible, i.e., hidden (VT300). * Ps = 2 2 -> Normal (neither bold nor faint). * Ps = 2 4 -> Not underlined. * Ps = 2 5 -> Steady (not blinking). * Ps = 2 7 -> Positive (not inverse). * Ps = 2 8 -> Visible, i.e., not hidden (VT300). * Ps = 3 0 -> Set foreground color to Black. * Ps = 3 1 -> Set foreground color to Red. * Ps = 3 2 -> Set foreground color to Green. * Ps = 3 3 -> Set foreground color to Yellow. * Ps = 3 4 -> Set foreground color to Blue. * Ps = 3 5 -> Set foreground color to Magenta. * Ps = 3 6 -> Set foreground color to Cyan. * Ps = 3 7 -> Set foreground color to White. * Ps = 3 9 -> Set foreground color to default (original). * Ps = 4 0 -> Set background color to Black. * Ps = 4 1 -> Set background color to Red. * Ps = 4 2 -> Set background color to Green. * Ps = 4 3 -> Set background color to Yellow. * Ps = 4 4 -> Set background color to Blue. * Ps = 4 5 -> Set background color to Magenta. * Ps = 4 6 -> Set background color to Cyan. * Ps = 4 7 -> Set background color to White. * Ps = 4 9 -> Set background color to default (original). * * If 16-color support is compiled, the following apply. Assume * that xterm's resources are set so that the ISO color codes are * the first 8 of a set of 16. Then the aixterm colors are the * bright versions of the ISO colors: * Ps = 9 0 -> Set foreground color to Black. * Ps = 9 1 -> Set foreground color to Red. * Ps = 9 2 -> Set foreground color to Green. * Ps = 9 3 -> Set foreground color to Yellow. * Ps = 9 4 -> Set foreground color to Blue. * Ps = 9 5 -> Set foreground color to Magenta. * Ps = 9 6 -> Set foreground color to Cyan. * Ps = 9 7 -> Set foreground color to White. * Ps = 1 0 0 -> Set background color to Black. * Ps = 1 0 1 -> Set background color to Red. * Ps = 1 0 2 -> Set background color to Green. * Ps = 1 0 3 -> Set background color to Yellow. * Ps = 1 0 4 -> Set background color to Blue. * Ps = 1 0 5 -> Set background color to Magenta. * Ps = 1 0 6 -> Set background color to Cyan. * Ps = 1 0 7 -> Set background color to White. * * If xterm is compiled with the 16-color support disabled, it * supports the following, from rxvt: * Ps = 1 0 0 -> Set foreground and background color to * default. * * If 88- or 256-color support is compiled, the following apply. * Ps = 3 8 ; 5 ; Ps -> Set foreground color to the second * Ps. * Ps = 4 8 ; 5 ; Ps -> Set background color to the second * Ps. */ public charAttributes(params: number[]): void { // Optimize a single SGR0. if (params.length === 1 && params[0] === 0) { this._terminal.curAttr = this._terminal.defAttr; return; } let l = params.length , i = 0 , flags = this._terminal.curAttr >> 18 , fg = (this._terminal.curAttr >> 9) & 0x1ff , bg = this._terminal.curAttr & 0x1ff , p; for (; i < l; i++) { p = params[i]; if (p >= 30 && p <= 37) { // fg color 8 fg = p - 30; } else if (p >= 40 && p <= 47) { // bg color 8 bg = p - 40; } else if (p >= 90 && p <= 97) { // fg color 16 p += 8; fg = p - 90; } else if (p >= 100 && p <= 107) { // bg color 16 p += 8; bg = p - 100; } else if (p === 0) { // default flags = this._terminal.defAttr >> 18; fg = (this._terminal.defAttr >> 9) & 0x1ff; bg = this._terminal.defAttr & 0x1ff; // flags = 0; // fg = 0x1ff; // bg = 0x1ff; } else if (p === 1) { // bold text flags |= 1; } else if (p === 4) { // underlined text flags |= 2; } else if (p === 5) { // blink flags |= 4; } else if (p === 7) { // inverse and positive // test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m' flags |= 8; } else if (p === 8) { // invisible flags |= 16; } else if (p === 22) { // not bold flags &= ~1; } else if (p === 24) { // not underlined flags &= ~2; } else if (p === 25) { // not blink flags &= ~4; } else if (p === 27) { // not inverse flags &= ~8; } else if (p === 28) { // not invisible flags &= ~16; } else if (p === 39) { // reset fg fg = (this._terminal.defAttr >> 9) & 0x1ff; } else if (p === 49) { // reset bg bg = this._terminal.defAttr & 0x1ff; } else if (p === 38) { // fg color 256 if (params[i + 1] === 2) { i += 2; fg = this._terminal.matchColor( params[i] & 0xff, params[i + 1] & 0xff, params[i + 2] & 0xff); if (fg === -1) fg = 0x1ff; i += 2; } else if (params[i + 1] === 5) { i += 2; p = params[i] & 0xff; fg = p; } } else if (p === 48) { // bg color 256 if (params[i + 1] === 2) { i += 2; bg = this._terminal.matchColor( params[i] & 0xff, params[i + 1] & 0xff, params[i + 2] & 0xff); if (bg === -1) bg = 0x1ff; i += 2; } else if (params[i + 1] === 5) { i += 2; p = params[i] & 0xff; bg = p; } } else if (p === 100) { // reset fg/bg fg = (this._terminal.defAttr >> 9) & 0x1ff; bg = this._terminal.defAttr & 0x1ff; } else { this._terminal.error('Unknown SGR attribute: %d.', p); } } this._terminal.curAttr = (flags << 18) | (fg << 9) | bg; } /** * CSI Ps n Device Status Report (DSR). * Ps = 5 -> Status Report. Result (``OK'') is * CSI 0 n * Ps = 6 -> Report Cursor Position (CPR) [row;column]. * Result is * CSI r ; c R * CSI ? Ps n * Device Status Report (DSR, DEC-specific). * Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI * ? r ; c R (assumes page is zero). * Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready). * or CSI ? 1 1 n (not ready). * Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked) * or CSI ? 2 1 n (locked). * Ps = 2 6 -> Report Keyboard status as * CSI ? 2 7 ; 1 ; 0 ; 0 n (North American). * The last two parameters apply to VT400 & up, and denote key- * board ready and LK01 respectively. * Ps = 5 3 -> Report Locator status as * CSI ? 5 3 n Locator available, if compiled-in, or * CSI ? 5 0 n No Locator, if not. */ public deviceStatus(params: number[]): void { if (!this._terminal.prefix) { switch (params[0]) { case 5: // status report this._terminal.send(C0.ESC + '[0n'); break; case 6: // cursor position this._terminal.send(C0.ESC + '[' + (this._terminal.y + 1) + ';' + (this._terminal.x + 1) + 'R'); break; } } else if (this._terminal.prefix === '?') { // modern xterm doesnt seem to // respond to any of these except ?6, 6, and 5 switch (params[0]) { case 6: // cursor position this._terminal.send(C0.ESC + '[?' + (this._terminal.y + 1) + ';' + (this._terminal.x + 1) + 'R'); break; case 15: // no printer // this.send(C0.ESC + '[?11n'); break; case 25: // dont support user defined keys // this.send(C0.ESC + '[?21n'); break; case 26: // north american keyboard // this.send(C0.ESC + '[?27;1;0;0n'); break; case 53: // no dec locator/mouse // this.send(C0.ESC + '[?50n'); break; } } } /** * CSI ! p Soft terminal reset (DECSTR). * http://vt100.net/docs/vt220-rm/table4-10.html */ public softReset(params: number[]): void { this._terminal.cursorHidden = false; this._terminal.insertMode = false; this._terminal.originMode = false; this._terminal.wraparoundMode = true; // defaults: xterm - true, vt100 - false 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.curAttr = this._terminal.defAttr; this._terminal.x = this._terminal.y = 0; // ? this._terminal.charset = null; this._terminal.glevel = 0; // ?? this._terminal.charsets = [null]; // ?? } /** * CSI Ps SP q Set cursor style (DECSCUSR, VT520). * Ps = 0 -> blinking block. * Ps = 1 -> blinking block (default). * Ps = 2 -> steady block. * Ps = 3 -> blinking underline. * Ps = 4 -> steady underline. * Ps = 5 -> blinking bar (xterm). * Ps = 6 -> steady bar (xterm). */ public setCursorStyle(params?: number[]): void { const param = params[0] < 1 ? 1 : params[0]; switch (param) { case 1: case 2: this._terminal.setOption('cursorStyle', 'block'); break; case 3: case 4: this._terminal.setOption('cursorStyle', 'underline'); break; case 5: case 6: this._terminal.setOption('cursorStyle', 'bar'); break; } const isBlinking = param % 2 === 1; this._terminal.setOption('cursorBlink', isBlinking); } /** * CSI Ps ; Ps r * Set Scrolling Region [top;bottom] (default = full size of win- * dow) (DECSTBM). * CSI ? Pm r */ 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; } /** * CSI s * Save cursor (ANSI.SYS). */ public saveCursor(params: number[]): void { this._terminal.savedX = this._terminal.x; this._terminal.savedY = this._terminal.y; } /** * CSI u * Restore cursor (ANSI.SYS). */ public restoreCursor(params: number[]): void { this._terminal.x = this._terminal.savedX || 0; this._terminal.y = this._terminal.savedY || 0; } } const wcwidth = (function(opts) { // extracted from https://www.cl.cam.ac.uk/%7Emgk25/ucs/wcwidth.c // combining characters const COMBINING = [ [0x0300, 0x036F], [0x0483, 0x0486], [0x0488, 0x0489], [0x0591, 0x05BD], [0x05BF, 0x05BF], [0x05C1, 0x05C2], [0x05C4, 0x05C5], [0x05C7, 0x05C7], [0x0600, 0x0603], [0x0610, 0x0615], [0x064B, 0x065E], [0x0670, 0x0670], [0x06D6, 0x06E4], [0x06E7, 0x06E8], [0x06EA, 0x06ED], [0x070F, 0x070F], [0x0711, 0x0711], [0x0730, 0x074A], [0x07A6, 0x07B0], [0x07EB, 0x07F3], [0x0901, 0x0902], [0x093C, 0x093C], [0x0941, 0x0948], [0x094D, 0x094D], [0x0951, 0x0954], [0x0962, 0x0963], [0x0981, 0x0981], [0x09BC, 0x09BC], [0x09C1, 0x09C4], [0x09CD, 0x09CD], [0x09E2, 0x09E3], [0x0A01, 0x0A02], [0x0A3C, 0x0A3C], [0x0A41, 0x0A42], [0x0A47, 0x0A48], [0x0A4B, 0x0A4D], [0x0A70, 0x0A71], [0x0A81, 0x0A82], [0x0ABC, 0x0ABC], [0x0AC1, 0x0AC5], [0x0AC7, 0x0AC8], [0x0ACD, 0x0ACD], [0x0AE2, 0x0AE3], [0x0B01, 0x0B01], [0x0B3C, 0x0B3C], [0x0B3F, 0x0B3F], [0x0B41, 0x0B43], [0x0B4D, 0x0B4D], [0x0B56, 0x0B56], [0x0B82, 0x0B82], [0x0BC0, 0x0BC0], [0x0BCD, 0x0BCD], [0x0C3E, 0x0C40], [0x0C46, 0x0C48], [0x0C4A, 0x0C4D], [0x0C55, 0x0C56], [0x0CBC, 0x0CBC], [0x0CBF, 0x0CBF], [0x0CC6, 0x0CC6], [0x0CCC, 0x0CCD], [0x0CE2, 0x0CE3], [0x0D41, 0x0D43], [0x0D4D, 0x0D4D], [0x0DCA, 0x0DCA], [0x0DD2, 0x0DD4], [0x0DD6, 0x0DD6], [0x0E31, 0x0E31], [0x0E34, 0x0E3A], [0x0E47, 0x0E4E], [0x0EB1, 0x0EB1], [0x0EB4, 0x0EB9], [0x0EBB, 0x0EBC], [0x0EC8, 0x0ECD], [0x0F18, 0x0F19], [0x0F35, 0x0F35], [0x0F37, 0x0F37], [0x0F39, 0x0F39], [0x0F71, 0x0F7E], [0x0F80, 0x0F84], [0x0F86, 0x0F87], [0x0F90, 0x0F97], [0x0F99, 0x0FBC], [0x0FC6, 0x0FC6], [0x102D, 0x1030], [0x1032, 0x1032], [0x1036, 0x1037], [0x1039, 0x1039], [0x1058, 0x1059], [0x1160, 0x11FF], [0x135F, 0x135F], [0x1712, 0x1714], [0x1732, 0x1734], [0x1752, 0x1753], [0x1772, 0x1773], [0x17B4, 0x17B5], [0x17B7, 0x17BD], [0x17C6, 0x17C6], [0x17C9, 0x17D3], [0x17DD, 0x17DD], [0x180B, 0x180D], [0x18A9, 0x18A9], [0x1920, 0x1922], [0x1927, 0x1928], [0x1932, 0x1932], [0x1939, 0x193B], [0x1A17, 0x1A18], [0x1B00, 0x1B03], [0x1B34, 0x1B34], [0x1B36, 0x1B3A], [0x1B3C, 0x1B3C], [0x1B42, 0x1B42], [0x1B6B, 0x1B73], [0x1DC0, 0x1DCA], [0x1DFE, 0x1DFF], [0x200B, 0x200F], [0x202A, 0x202E], [0x2060, 0x2063], [0x206A, 0x206F], [0x20D0, 0x20EF], [0x302A, 0x302F], [0x3099, 0x309A], [0xA806, 0xA806], [0xA80B, 0xA80B], [0xA825, 0xA826], [0xFB1E, 0xFB1E], [0xFE00, 0xFE0F], [0xFE20, 0xFE23], [0xFEFF, 0xFEFF], [0xFFF9, 0xFFFB], [0x10A01, 0x10A03], [0x10A05, 0x10A06], [0x10A0C, 0x10A0F], [0x10A38, 0x10A3A], [0x10A3F, 0x10A3F], [0x1D167, 0x1D169], [0x1D173, 0x1D182], [0x1D185, 0x1D18B], [0x1D1AA, 0x1D1AD], [0x1D242, 0x1D244], [0xE0001, 0xE0001], [0xE0020, 0xE007F], [0xE0100, 0xE01EF] ]; // binary search function bisearch(ucs) { let min = 0; let max = COMBINING.length - 1; let mid; if (ucs < COMBINING[0][0] || ucs > COMBINING[max][1]) return false; while (max >= min) { mid = Math.floor((min + max) / 2); if (ucs > COMBINING[mid][1]) min = mid + 1; else if (ucs < COMBINING[mid][0]) max = mid - 1; else return true; } return false; } function wcwidth(ucs) { // test for 8-bit control characters if (ucs === 0) return opts.nul; if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) return opts.control; // binary search in table of non-spacing characters if (bisearch(ucs)) return 0; // if we arrive here, ucs is not a combining or C0/C1 control character if (isWide(ucs)) { return 2; } return 1; } function isWide(ucs) { return ( ucs >= 0x1100 && ( ucs <= 0x115f || // Hangul Jamo init. consonants ucs === 0x2329 || ucs === 0x232a || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs !== 0x303f) || // CJK..Yi (ucs >= 0xac00 && ucs <= 0xd7a3) || // Hangul Syllables (ucs >= 0xf900 && ucs <= 0xfaff) || // CJK Compat Ideographs (ucs >= 0xfe10 && ucs <= 0xfe19) || // Vertical forms (ucs >= 0xfe30 && ucs <= 0xfe6f) || // CJK Compat Forms (ucs >= 0xff00 && ucs <= 0xff60) || // Fullwidth Forms (ucs >= 0xffe0 && ucs <= 0xffe6) || (ucs >= 0x20000 && ucs <= 0x2fffd) || (ucs >= 0x30000 && ucs <= 0x3fffd))); } return wcwidth; })({nul: 0, control: 0}); // configurable options xterm.js-2.7.0/src/Interfaces.ts000066400000000000000000000113361311554223300165170ustar00rootroot00000000000000/** * @license MIT */ import { LinkMatcherOptions } from './Interfaces'; import { LinkMatcherHandler, LinkMatcherValidationCallback } from './Types'; export interface IBrowser { isNode: boolean; userAgent: string; platform: string; isFirefox: boolean; isMSIE: boolean; isMac: boolean; isIpad: boolean; isIphone: boolean; isMSWindows: boolean; } export interface ITerminal { element: HTMLElement; rowContainer: HTMLElement; textarea: HTMLTextAreaElement; ybase: number; ydisp: number; lines: ICircularList; rows: number; cols: number; browser: IBrowser; writeBuffer: string[]; children: HTMLElement[]; cursorHidden: boolean; cursorState: number; x: number; y: number; defAttr: number; /** * Emit the 'data' event and populate the given data. * @param data The data to populate in the event. */ handler(data: string); on(event: string, callback: () => void); scrollDisp(disp: number, suppressScrollEvent: boolean); cancel(ev: Event, force?: boolean); log(text: string): void; emit(event: string, data: any); } export interface ICharMeasure { width: number; height: number; measure(): void; } export interface ILinkifier { linkifyRow(rowIndex: number): void; attachHypertextLinkHandler(handler: LinkMatcherHandler): void; registerLinkMatcher(regex: RegExp, handler: LinkMatcherHandler, options?: LinkMatcherOptions): number; deregisterLinkMatcher(matcherId: number): boolean; } interface ICircularList { length: number; maxLength: number; forEach(callbackfn: (value: T, index: number, array: T[]) => void): void; get(index: number): T; set(index: number, value: T): void; push(value: T): void; pop(): T; splice(start: number, deleteCount: number, ...items: T[]): void; trimStart(count: number): void; shiftElements(start: number, count: number, offset: number): void; } export interface LinkMatcherOptions { /** * The index of the link from the regex.match(text) call. This defaults to 0 * (for regular expressions without capture groups). */ matchIndex?: number; /** * A callback that validates an individual link, returning true if valid and * false if invalid. */ validationCallback?: LinkMatcherValidationCallback; /** * The priority of the link matcher, this defines the order in which the link * matcher is evaluated relative to others, from highest to lowest. The * default value is 0. */ priority?: number; } /** * Handles actions generated by the parser. */ export interface IInputHandler { addChar(char: string, code: number): void; /** C0 BEL */ bell(): void; /** C0 LF */ lineFeed(): void; /** C0 CR */ carriageReturn(): void; /** C0 BS */ backspace(): void; /** C0 HT */ tab(): void; /** C0 SO */ shiftOut(): void; /** C0 SI */ shiftIn(): void; /** CSI @ */ insertChars(params?: number[]): void; /** CSI A */ cursorUp(params?: number[]): void; /** CSI B */ cursorDown(params?: number[]): void; /** CSI C */ cursorForward(params?: number[]): void; /** CSI D */ cursorBackward(params?: number[]): void; /** CSI E */ cursorNextLine(params?: number[]): void; /** CSI F */ cursorPrecedingLine(params?: number[]): void; /** CSI G */ cursorCharAbsolute(params?: number[]): void; /** CSI H */ cursorPosition(params?: number[]): void; /** CSI I */ cursorForwardTab(params?: number[]): void; /** CSI J */ eraseInDisplay(params?: number[]): void; /** CSI K */ eraseInLine(params?: number[]): void; /** CSI L */ insertLines(params?: number[]): void; /** CSI M */ deleteLines(params?: number[]): void; /** CSI P */ deleteChars(params?: number[]): void; /** CSI S */ scrollUp(params?: number[]): void; /** CSI T */ scrollDown(params?: number[]): void; /** CSI X */ eraseChars(params?: number[]): void; /** CSI Z */ cursorBackwardTab(params?: number[]): void; /** CSI ` */ charPosAbsolute(params?: number[]): void; /** CSI a */ HPositionRelative(params?: number[]): void; /** CSI b */ repeatPrecedingCharacter(params?: number[]): void; /** CSI c */ sendDeviceAttributes(params?: number[]): void; /** CSI d */ linePosAbsolute(params?: number[]): void; /** CSI e */ VPositionRelative(params?: number[]): void; /** CSI f */ HVPosition(params?: number[]): void; /** CSI g */ tabClear(params?: number[]): void; /** CSI h */ setMode(params?: number[]): void; /** CSI l */ resetMode(params?: number[]): void; /** CSI m */ charAttributes(params?: number[]): void; /** CSI n */ deviceStatus(params?: number[]): void; /** CSI p */ softReset(params?: number[]): void; /** CSI q */ setCursorStyle(params?: number[]): void; /** CSI r */ setScrollRegion(params?: number[]): void; /** CSI s */ saveCursor(params?: number[]): void; /** CSI u */ restoreCursor(params?: number[]): void; } xterm.js-2.7.0/src/Linkifier.test.ts000066400000000000000000000150511311554223300173240ustar00rootroot00000000000000/** * @license MIT */ import jsdom = require('jsdom'); import { assert } from 'chai'; import { ITerminal, ILinkifier } from './Interfaces'; import { Linkifier } from './Linkifier'; import { LinkMatcher } from './Types'; class TestLinkifier extends Linkifier { constructor() { Linkifier.TIME_BEFORE_LINKIFY = 0; super(); } public get linkMatchers(): LinkMatcher[] { return this._linkMatchers; } } describe('Linkifier', () => { let window: Window; let document: Document; let container: HTMLElement; let rows: HTMLElement[]; let linkifier: TestLinkifier; beforeEach(done => { jsdom.env('', (err, w) => { window = w; document = window.document; linkifier = new TestLinkifier(); done(); }); }); function addRow(html: string) { const element = document.createElement('div'); element.innerHTML = html; container.appendChild(element); rows.push(element); } describe('before attachToDom', () => { it('should allow link matcher registration', done => { assert.doesNotThrow(() => { const linkMatcherId = linkifier.registerLinkMatcher(/foo/, () => {}); assert.isTrue(linkifier.deregisterLinkMatcher(linkMatcherId)); done(); }); }); }); describe('after attachToDom', () => { beforeEach(() => { rows = []; linkifier.attachToDom(document, rows); container = document.createElement('div'); document.body.appendChild(container); }); function clickElement(element: Node) { const event = document.createEvent('MouseEvent'); event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); element.dispatchEvent(event); } function assertLinkifiesEntireRow(uri: string, done: MochaDone) { addRow(uri); linkifier.linkifyRow(0); setTimeout(() => { assert.equal((rows[0].firstChild).tagName, 'A'); assert.equal((rows[0].firstChild).textContent, uri); done(); }, 0); } describe('http links', () => { function assertLinkifiesEntireRow(uri: string, done: MochaDone) { addRow(uri); linkifier.linkifyRow(0); setTimeout(() => { assert.equal((rows[0].firstChild).tagName, 'A'); assert.equal((rows[0].firstChild).textContent, uri); done(); }, 0); } it('should allow ~ character in URI path', done => assertLinkifiesEntireRow('http://foo.com/a~b#c~d?e~f', done)); }); describe('link matcher', () => { function assertLinkifiesRow(rowText: string, linkMatcherRegex: RegExp, expectedHtml: string, done: MochaDone) { addRow(rowText); linkifier.registerLinkMatcher(linkMatcherRegex, () => {}); linkifier.linkifyRow(0); // Allow linkify to happen setTimeout(() => { assert.equal(rows[0].innerHTML, expectedHtml); done(); }, 0); } it('should match a single link', done => { assertLinkifiesRow('foo', /foo/, 'foo', done); }); it('should match a single link at the start of a text node', done => { assertLinkifiesRow('foo bar', /foo/, 'foo bar', done); }); it('should match a single link in the middle of a text node', done => { assertLinkifiesRow('foo bar baz', /bar/, 'foo bar baz', done); }); it('should match a single link at the end of a text node', done => { assertLinkifiesRow('foo bar', /bar/, 'foo bar', done); }); it('should match a link after a link at the start of a text node', done => { assertLinkifiesRow('foo bar', /foo|bar/, 'foo bar', done); }); it('should match a link after a link in the middle of a text node', done => { assertLinkifiesRow('foo bar baz', /bar|baz/, 'foo bar baz', done); }); it('should match a link immediately after a link at the end of a text node', done => { assertLinkifiesRow('foo barbaz', /bar|baz/, 'foo barbaz', done); }); }); describe('validationCallback', () => { it('should enable link if true', done => { addRow('test'); linkifier.registerLinkMatcher(/test/, () => done(), { validationCallback: (url, element, cb) => { cb(true); assert.equal((rows[0].firstChild).tagName, 'A'); setTimeout(() => clickElement(rows[0].firstChild), 0); } }); linkifier.linkifyRow(0); }); it('should disable link if false', done => { addRow('test'); linkifier.registerLinkMatcher(/test/, () => assert.fail(), { validationCallback: (url, element, cb) => { cb(false); assert.equal((rows[0].firstChild).tagName, 'A'); setTimeout(() => clickElement(rows[0].firstChild), 0); } }); linkifier.linkifyRow(0); // Allow time for the click to be performed setTimeout(() => done(), 10); }); it('should trigger for multiple link matches on one row', done => { addRow('test test'); let count = 0; linkifier.registerLinkMatcher(/test/, () => assert.fail(), { validationCallback: (url, element, cb) => { count += 1; if (count === 2) { done(); } cb(false); } }); linkifier.linkifyRow(0); }); }); describe('priority', () => { it('should order the list from highest priority to lowest #1', () => { const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: 1 }); const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: -1 }); assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [aId, 0, bId]); }); it('should order the list from highest priority to lowest #2', () => { const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: -1 }); const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: 1 }); assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [bId, 0, aId]); }); it('should order items of equal priority in the order they are added', () => { const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: 0 }); const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: 0 }); assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [0, aId, bId]); }); }); }); }); xterm.js-2.7.0/src/Linkifier.ts000066400000000000000000000306561311554223300163560ustar00rootroot00000000000000/** * @license MIT */ import { LinkMatcherOptions } from './Interfaces'; import { LinkMatcher, LinkMatcherHandler, LinkMatcherValidationCallback } from './Types'; const INVALID_LINK_CLASS = 'xterm-invalid-link'; const protocolClause = '(https?:\\/\\/)'; const domainCharacterSet = '[\\da-z\\.-]+'; const negatedDomainCharacterSet = '[^\\da-z\\.-]+'; const domainBodyClause = '(' + domainCharacterSet + ')'; const tldClause = '([a-z\\.]{2,6})'; const ipClause = '((\\d{1,3}\\.){3}\\d{1,3})'; const localHostClause = '(localhost)'; const portClause = '(:\\d{1,5})'; const hostClause = '((' + domainBodyClause + '\\.' + tldClause + ')|' + ipClause + '|' + localHostClause + ')' + portClause + '?'; const pathClause = '(\\/[\\/\\w\\.\\-%~]*)*'; const queryStringHashFragmentCharacterSet = '[0-9\\w\\[\\]\\(\\)\\/\\?\\!#@$%&\'*+,:;~\\=\\.\\-]*'; const queryStringClause = '(\\?' + queryStringHashFragmentCharacterSet + ')?'; const hashFragmentClause = '(#' + queryStringHashFragmentCharacterSet + ')?'; const negatedPathCharacterSet = '[^\\/\\w\\.\\-%]+'; const bodyClause = hostClause + pathClause + queryStringClause + hashFragmentClause; const start = '(?:^|' + negatedDomainCharacterSet + ')('; const end = ')($|' + negatedPathCharacterSet + ')'; const strictUrlRegex = new RegExp(start + protocolClause + bodyClause + end); /** * The ID of the built in http(s) link matcher. */ const HYPERTEXT_LINK_MATCHER_ID = 0; /** * The Linkifier applies links to rows shortly after they have been refreshed. */ export class Linkifier { /** * The time to wait after a row is changed before it is linkified. This prevents * the costly operation of searching every row multiple times, potentially a * huge amount of times. */ protected static TIME_BEFORE_LINKIFY = 200; protected _linkMatchers: LinkMatcher[]; private _document: Document; private _rows: HTMLElement[]; private _rowTimeoutIds: number[]; private _nextLinkMatcherId = HYPERTEXT_LINK_MATCHER_ID; constructor() { this._rowTimeoutIds = []; this._linkMatchers = []; this.registerLinkMatcher(strictUrlRegex, null, { matchIndex: 1 }); } /** * Attaches the linkifier to the DOM, enabling linkification. * @param document The document object. * @param rows The array of rows to apply links to. */ public attachToDom(document: Document, rows: HTMLElement[]) { this._document = document; this._rows = rows; } /** * Queues a row for linkification. * @param {number} rowIndex The index of the row to linkify. */ public linkifyRow(rowIndex: number): void { // Don't attempt linkify if not yet attached to DOM if (!this._document) { return; } const timeoutId = this._rowTimeoutIds[rowIndex]; if (timeoutId) { clearTimeout(timeoutId); } this._rowTimeoutIds[rowIndex] = setTimeout(this._linkifyRow.bind(this, rowIndex), Linkifier.TIME_BEFORE_LINKIFY); } /** * Attaches a handler for hypertext links, overriding default behavior * for standard http(s) links. * @param {LinkHandler} handler The handler to use, this can be cleared with * null. */ public setHypertextLinkHandler(handler: LinkMatcherHandler): void { this._linkMatchers[HYPERTEXT_LINK_MATCHER_ID].handler = handler; } /** * Attaches a validation callback for hypertext links. * @param {LinkMatcherValidationCallback} callback The callback to use, this * can be cleared with null. */ public setHypertextValidationCallback(callback: LinkMatcherValidationCallback): void { this._linkMatchers[HYPERTEXT_LINK_MATCHER_ID].validationCallback = callback; } /** * Registers a link matcher, allowing custom link patterns to be matched and * handled. * @param {RegExp} regex The regular expression to search for, specifically * this searches the textContent of the rows. You will want to use \s to match * a space ' ' character for example. * @param {LinkHandler} handler The callback when the link is called. * @param {LinkMatcherOptions} [options] Options for the link matcher. * @return {number} The ID of the new matcher, this can be used to deregister. */ public registerLinkMatcher(regex: RegExp, handler: LinkMatcherHandler, options: LinkMatcherOptions = {}): number { if (this._nextLinkMatcherId !== HYPERTEXT_LINK_MATCHER_ID && !handler) { throw new Error('handler must be defined'); } const matcher: LinkMatcher = { id: this._nextLinkMatcherId++, regex, handler, matchIndex: options.matchIndex, validationCallback: options.validationCallback, priority: options.priority || 0 }; this._addLinkMatcherToList(matcher); return matcher.id; } /** * Inserts a link matcher to the list in the correct position based on the * priority of each link matcher. New link matchers of equal priority are * considered after older link matchers. * @param matcher The link matcher to be added. */ private _addLinkMatcherToList(matcher: LinkMatcher): void { if (this._linkMatchers.length === 0) { this._linkMatchers.push(matcher); return; } for (let i = this._linkMatchers.length - 1; i >= 0; i--) { if (matcher.priority <= this._linkMatchers[i].priority) { this._linkMatchers.splice(i + 1, 0, matcher); return; } } this._linkMatchers.splice(0, 0, matcher); } /** * Deregisters a link matcher if it has been registered. * @param {number} matcherId The link matcher's ID (returned after register) * @return {boolean} Whether a link matcher was found and deregistered. */ public deregisterLinkMatcher(matcherId: number): boolean { // ID 0 is the hypertext link matcher which cannot be deregistered for (let i = 1; i < this._linkMatchers.length; i++) { if (this._linkMatchers[i].id === matcherId) { this._linkMatchers.splice(i, 1); return true; } } return false; } /** * Linkifies a row. * @param {number} rowIndex The index of the row to linkify. */ private _linkifyRow(rowIndex: number): void { const row = this._rows[rowIndex]; if (!row) { return; } const text = row.textContent; for (let i = 0; i < this._linkMatchers.length; i++) { const matcher = this._linkMatchers[i]; const linkElements = this._doLinkifyRow(row, matcher); if (linkElements.length > 0) { // Fire validation callback if (matcher.validationCallback) { for (let j = 0; j < linkElements.length; j++) { const element = linkElements[j]; matcher.validationCallback(element.textContent, element, isValid => { if (!isValid) { element.classList.add(INVALID_LINK_CLASS); } }); } } // Only allow a single LinkMatcher to trigger on any given row. return; } } } /** * Linkifies a row given a specific handler. * @param {HTMLElement} row The row to linkify. * @param {LinkMatcher} matcher The link matcher for this line. * @return The link element if it was added, otherwise undefined. */ private _doLinkifyRow(row: HTMLElement, matcher: LinkMatcher): HTMLElement[] { // Iterate over nodes as we want to consider text nodes let result = []; const isHttpLinkMatcher = matcher.id === HYPERTEXT_LINK_MATCHER_ID; const nodes = row.childNodes; // Find the first match let match = row.textContent.match(matcher.regex); if (!match || match.length === 0) { return result; } let uri = match[typeof matcher.matchIndex !== 'number' ? 0 : matcher.matchIndex]; // Set the next searches start index let rowStartIndex = match.index + uri.length; for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; const searchIndex = node.textContent.indexOf(uri); if (searchIndex >= 0) { const linkElement = this._createAnchorElement(uri, matcher.handler, isHttpLinkMatcher); if (node.textContent.length === uri.length) { // Matches entire string if (node.nodeType === 3 /*Node.TEXT_NODE*/) { this._replaceNode(node, linkElement); } else { const element = (node); if (element.nodeName === 'A') { // This row has already been linkified return result; } element.innerHTML = ''; element.appendChild(linkElement); } } else { // Matches part of string const nodesAdded = this._replaceNodeSubstringWithNode(node, linkElement, uri, searchIndex); // No need to consider the new nodes i += nodesAdded; } result.push(linkElement); // Find the next match match = row.textContent.substring(rowStartIndex).match(matcher.regex); if (!match || match.length === 0) { return result; } uri = match[typeof matcher.matchIndex !== 'number' ? 0 : matcher.matchIndex]; rowStartIndex += match.index + uri.length; } } return result; } /** * Creates a link anchor element. * @param {string} uri The uri of the link. * @return {HTMLAnchorElement} The link. */ private _createAnchorElement(uri: string, handler: LinkMatcherHandler, isHypertextLinkHandler: boolean): HTMLAnchorElement { const element = this._document.createElement('a'); element.textContent = uri; element.draggable = false; if (isHypertextLinkHandler) { element.href = uri; // Force link on another tab so work is not lost element.target = '_blank'; element.addEventListener('click', (event: MouseEvent) => { if (handler) { return handler(event, uri); } }); } else { element.addEventListener('click', (event: MouseEvent) => { // Don't execute the handler if the link is flagged as invalid if (element.classList.contains(INVALID_LINK_CLASS)) { return; } return handler(event, uri); }); } return element; } /** * Replace a node with 1 or more other nodes. * @param {Node} oldNode The node to replace. * @param {Node[]} newNodes The new nodes to insert in order. */ private _replaceNode(oldNode: Node, ...newNodes: Node[]): void { const parent = oldNode.parentNode; for (let i = 0; i < newNodes.length; i++) { parent.insertBefore(newNodes[i], oldNode); } parent.removeChild(oldNode); } /** * Replace a substring within a node with a new node. * @param {Node} targetNode The target node; either a text node or a * containing a single text node. * @param {Node} newNode The new node to insert. * @param {string} substring The substring to replace. * @param {number} substringIndex The index of the substring within the string. * @return The number of nodes to skip when searching for the next uri. */ private _replaceNodeSubstringWithNode(targetNode: Node, newNode: Node, substring: string, substringIndex: number): number { let node = targetNode; if (node.nodeType !== 3/*Node.TEXT_NODE*/) { node = node.childNodes[0]; } // The targetNode will be either a text node or a . The text node // (targetNode or its only-child) needs to be replaced with newNode plus new // text nodes potentially on either side. if (node.childNodes.length === 0 && node.nodeType !== 3/*Node.TEXT_NODE*/) { throw new Error('targetNode must be a text node or only contain a single text node'); } const fullText = node.textContent; if (substringIndex === 0) { // Replace with const rightText = fullText.substring(substring.length); const rightTextNode = this._document.createTextNode(rightText); this._replaceNode(node, newNode, rightTextNode); return 0; } if (substringIndex === targetNode.textContent.length - substring.length) { // Replace with const leftText = fullText.substring(0, substringIndex); const leftTextNode = this._document.createTextNode(leftText); this._replaceNode(node, leftTextNode, newNode); return 0; } // Replace with const leftText = fullText.substring(0, substringIndex); const leftTextNode = this._document.createTextNode(leftText); const rightText = fullText.substring(substringIndex + substring.length); const rightTextNode = this._document.createTextNode(rightText); this._replaceNode(node, leftTextNode, newNode, rightTextNode); return 1; } } xterm.js-2.7.0/src/Parser.ts000066400000000000000000000533741311554223300157000ustar00rootroot00000000000000/** * @license MIT */ import { C0 } from './EscapeSequences'; import { IInputHandler } from './Interfaces'; import { CHARSETS, DEFAULT_CHARSET } from './Charsets'; const normalStateHandler: {[key: string]: (parser: Parser, handler: IInputHandler) => void} = {}; normalStateHandler[C0.BEL] = (parser, handler) => handler.bell(); normalStateHandler[C0.LF] = (parser, handler) => handler.lineFeed(); normalStateHandler[C0.VT] = normalStateHandler[C0.LF]; normalStateHandler[C0.FF] = normalStateHandler[C0.LF]; normalStateHandler[C0.CR] = (parser, handler) => handler.carriageReturn(); normalStateHandler[C0.BS] = (parser, handler) => handler.backspace(); normalStateHandler[C0.HT] = (parser, handler) => handler.tab(); normalStateHandler[C0.SO] = (parser, handler) => handler.shiftOut(); normalStateHandler[C0.SI] = (parser, handler) => handler.shiftIn(); normalStateHandler[C0.ESC] = (parser, handler) => parser.setState(ParserState.ESCAPED); // TODO: Remove terminal when parser owns params and currentParam const escapedStateHandler: {[key: string]: (parser: Parser, terminal: any) => void} = {}; escapedStateHandler['['] = (parser, terminal) => { // ESC [ Control Sequence Introducer (CSI is 0x9b) terminal.params = []; terminal.currentParam = 0; parser.setState(ParserState.CSI_PARAM); }; escapedStateHandler[']'] = (parser, terminal) => { // ESC ] Operating System Command (OSC is 0x9d) terminal.params = []; terminal.currentParam = 0; parser.setState(ParserState.OSC); }; escapedStateHandler['P'] = (parser, terminal) => { // ESC P Device Control String (DCS is 0x90) terminal.params = []; terminal.currentParam = 0; parser.setState(ParserState.DCS); }; escapedStateHandler['_'] = (parser, terminal) => { // ESC _ Application Program Command ( APC is 0x9f). parser.setState(ParserState.IGNORE); }; escapedStateHandler['^'] = (parser, terminal) => { // ESC ^ Privacy Message ( PM is 0x9e). parser.setState(ParserState.IGNORE); }; escapedStateHandler['c'] = (parser, terminal) => { // ESC c Full Reset (RIS). terminal.reset(); }; escapedStateHandler['E'] = (parser, terminal) => { // ESC E Next Line ( NEL is 0x85). terminal.x = 0; terminal.index(); parser.setState(ParserState.NORMAL); }; escapedStateHandler['D'] = (parser, terminal) => { // ESC D Index ( IND is 0x84). terminal.index(); parser.setState(ParserState.NORMAL); }; escapedStateHandler['M'] = (parser, terminal) => { // ESC M Reverse Index ( RI is 0x8d). terminal.reverseIndex(); parser.setState(ParserState.NORMAL); }; escapedStateHandler['%'] = (parser, terminal) => { // ESC % Select default/utf-8 character set. // @ = default, G = utf-8 terminal.setgLevel(0); terminal.setgCharset(0, DEFAULT_CHARSET); // US (default) parser.setState(ParserState.NORMAL); parser.skipNextChar(); }; escapedStateHandler[C0.CAN] = (parser) => parser.setState(ParserState.NORMAL); const csiParamStateHandler: {[key: string]: (parser: Parser) => void} = {}; csiParamStateHandler['?'] = (parser) => parser.setPrefix('?'); csiParamStateHandler['>'] = (parser) => parser.setPrefix('>'); csiParamStateHandler['!'] = (parser) => parser.setPrefix('!'); csiParamStateHandler['0'] = (parser) => parser.setParam(parser.getParam() * 10); csiParamStateHandler['1'] = (parser) => parser.setParam(parser.getParam() * 10 + 1); csiParamStateHandler['2'] = (parser) => parser.setParam(parser.getParam() * 10 + 2); csiParamStateHandler['3'] = (parser) => parser.setParam(parser.getParam() * 10 + 3); csiParamStateHandler['4'] = (parser) => parser.setParam(parser.getParam() * 10 + 4); csiParamStateHandler['5'] = (parser) => parser.setParam(parser.getParam() * 10 + 5); csiParamStateHandler['6'] = (parser) => parser.setParam(parser.getParam() * 10 + 6); csiParamStateHandler['7'] = (parser) => parser.setParam(parser.getParam() * 10 + 7); csiParamStateHandler['8'] = (parser) => parser.setParam(parser.getParam() * 10 + 8); csiParamStateHandler['9'] = (parser) => parser.setParam(parser.getParam() * 10 + 9); csiParamStateHandler['$'] = (parser) => parser.setPostfix('$'); csiParamStateHandler['"'] = (parser) => parser.setPostfix('"'); csiParamStateHandler[' '] = (parser) => parser.setPostfix(' '); csiParamStateHandler['\''] = (parser) => parser.setPostfix('\''); csiParamStateHandler[';'] = (parser) => parser.finalizeParam(); csiParamStateHandler[C0.CAN] = (parser) => parser.setState(ParserState.NORMAL); const csiStateHandler: {[key: string]: (handler: IInputHandler, params: number[], prefix: string, postfix: string, parser: Parser) => void} = {}; csiStateHandler['@'] = (handler, params, prefix) => handler.insertChars(params); csiStateHandler['A'] = (handler, params, prefix) => handler.cursorUp(params); csiStateHandler['B'] = (handler, params, prefix) => handler.cursorDown(params); csiStateHandler['C'] = (handler, params, prefix) => handler.cursorForward(params); csiStateHandler['D'] = (handler, params, prefix) => handler.cursorBackward(params); csiStateHandler['E'] = (handler, params, prefix) => handler.cursorNextLine(params); csiStateHandler['F'] = (handler, params, prefix) => handler.cursorPrecedingLine(params); csiStateHandler['G'] = (handler, params, prefix) => handler.cursorCharAbsolute(params); csiStateHandler['H'] = (handler, params, prefix) => handler.cursorPosition(params); csiStateHandler['I'] = (handler, params, prefix) => handler.cursorForwardTab(params); csiStateHandler['J'] = (handler, params, prefix) => handler.eraseInDisplay(params); csiStateHandler['K'] = (handler, params, prefix) => handler.eraseInLine(params); csiStateHandler['L'] = (handler, params, prefix) => handler.insertLines(params); csiStateHandler['M'] = (handler, params, prefix) => handler.deleteLines(params); csiStateHandler['P'] = (handler, params, prefix) => handler.deleteChars(params); csiStateHandler['S'] = (handler, params, prefix) => handler.scrollUp(params); csiStateHandler['T'] = (handler, params, prefix) => { if (params.length < 2 && !prefix) { handler.scrollDown(params); } }; csiStateHandler['X'] = (handler, params, prefix) => handler.eraseChars(params); csiStateHandler['Z'] = (handler, params, prefix) => handler.cursorBackwardTab(params); csiStateHandler['`'] = (handler, params, prefix) => handler.charPosAbsolute(params); csiStateHandler['a'] = (handler, params, prefix) => handler.HPositionRelative(params); csiStateHandler['b'] = (handler, params, prefix) => handler.repeatPrecedingCharacter(params); csiStateHandler['c'] = (handler, params, prefix) => handler.sendDeviceAttributes(params); csiStateHandler['d'] = (handler, params, prefix) => handler.linePosAbsolute(params); csiStateHandler['e'] = (handler, params, prefix) => handler.VPositionRelative(params); csiStateHandler['f'] = (handler, params, prefix) => handler.HVPosition(params); csiStateHandler['g'] = (handler, params, prefix) => handler.tabClear(params); csiStateHandler['h'] = (handler, params, prefix) => handler.setMode(params); csiStateHandler['l'] = (handler, params, prefix) => handler.resetMode(params); csiStateHandler['m'] = (handler, params, prefix) => handler.charAttributes(params); csiStateHandler['n'] = (handler, params, prefix) => handler.deviceStatus(params); csiStateHandler['p'] = (handler, params, prefix) => { switch (prefix) { case '!': handler.softReset(params); break; } }; csiStateHandler['q'] = (handler, params, prefix, postfix) => { if (postfix === ' ') { handler.setCursorStyle(params); } }; csiStateHandler['r'] = (handler, params) => handler.setScrollRegion(params); csiStateHandler['s'] = (handler, params) => handler.saveCursor(params); csiStateHandler['u'] = (handler, params) => handler.restoreCursor(params); csiStateHandler[C0.CAN] = (handler, params, prefix, postfix, parser) => parser.setState(ParserState.NORMAL); enum ParserState { NORMAL = 0, ESCAPED = 1, CSI_PARAM = 2, CSI = 3, OSC = 4, CHARSET = 5, DCS = 6, IGNORE = 7 } /** * The terminal's parser, all input into the terminal goes through the parser * which parses and defers the actual input handling the the IInputHandler * specified in the constructor. */ export class Parser { private _state: ParserState; private _position: number; // TODO: Remove terminal when handler can do everything constructor( private _inputHandler: IInputHandler, private _terminal: any ) { this._state = ParserState.NORMAL; } /** * Parse and handle data. * * @param data The data to parse. */ public parse(data: string): ParserState { let l = data.length, j, cs, ch, code, low; this._position = 0; // apply leftover surrogate high from last write if (this._terminal.surrogate_high) { data = this._terminal.surrogate_high + data; this._terminal.surrogate_high = ''; } for (; this._position < l; this._position++) { ch = data[this._position]; // FIXME: higher chars than 0xa0 are not allowed in escape sequences // --> maybe move to default code = data.charCodeAt(this._position); if (0xD800 <= code && code <= 0xDBFF) { // we got a surrogate high // get surrogate low (next 2 bytes) low = data.charCodeAt(this._position + 1); if (isNaN(low)) { // end of data stream, save surrogate high this._terminal.surrogate_high = ch; continue; } code = ((code - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000; ch += data.charAt(this._position + 1); } // surrogate low - already handled above if (0xDC00 <= code && code <= 0xDFFF) continue; switch (this._state) { case ParserState.NORMAL: if (ch in normalStateHandler) { normalStateHandler[ch](this, this._inputHandler); } else { this._inputHandler.addChar(ch, code); } break; case ParserState.ESCAPED: if (ch in escapedStateHandler) { escapedStateHandler[ch](this, this._terminal); // Skip switch as it was just handled break; } switch (ch) { // ESC (,),*,+,-,. Designate G0-G2 Character Set. case '(': // <-- this seems to get all the attention case ')': case '*': case '+': case '-': case '.': switch (ch) { case '(': this._terminal.gcharset = 0; break; case ')': this._terminal.gcharset = 1; break; case '*': this._terminal.gcharset = 2; break; case '+': this._terminal.gcharset = 3; break; case '-': this._terminal.gcharset = 1; break; case '.': this._terminal.gcharset = 2; break; } this._state = ParserState.CHARSET; break; // Designate G3 Character Set (VT300). // A = ISO Latin-1 Supplemental. // Not implemented. case '/': this._terminal.gcharset = 3; this._state = ParserState.CHARSET; this._position--; break; // ESC N // Single Shift Select of G2 Character Set // ( SS2 is 0x8e). This affects next character only. case 'N': break; // ESC O // Single Shift Select of G3 Character Set // ( SS3 is 0x8f). This affects next character only. case 'O': break; // ESC n // Invoke the G2 Character Set as GL (LS2). case 'n': this._terminal.setgLevel(2); break; // ESC o // Invoke the G3 Character Set as GL (LS3). case 'o': this._terminal.setgLevel(3); break; // ESC | // Invoke the G3 Character Set as GR (LS3R). case '|': this._terminal.setgLevel(3); break; // ESC } // Invoke the G2 Character Set as GR (LS2R). case '}': this._terminal.setgLevel(2); break; // ESC ~ // Invoke the G1 Character Set as GR (LS1R). case '~': this._terminal.setgLevel(1); break; // ESC 7 Save Cursor (DECSC). case '7': this._inputHandler.saveCursor(); this._state = ParserState.NORMAL; break; // ESC 8 Restore Cursor (DECRC). case '8': this._inputHandler.restoreCursor(); this._state = ParserState.NORMAL; break; // ESC # 3 DEC line height/width case '#': this._state = ParserState.NORMAL; this._position++; break; // ESC H Tab Set (HTS is 0x88). case 'H': this._terminal.tabSet(); this._state = ParserState.NORMAL; break; // ESC = Application Keypad (DECKPAM). case '=': this._terminal.log('Serial port requested application keypad.'); this._terminal.applicationKeypad = true; this._terminal.viewport.syncScrollArea(); this._state = ParserState.NORMAL; break; // ESC > Normal Keypad (DECKPNM). case '>': this._terminal.log('Switching back to normal keypad.'); this._terminal.applicationKeypad = false; this._terminal.viewport.syncScrollArea(); this._state = ParserState.NORMAL; break; default: this._state = ParserState.NORMAL; this._terminal.error('Unknown ESC control: %s.', ch); break; } break; case ParserState.CHARSET: if (ch in CHARSETS) { cs = CHARSETS[ch]; if (ch === '/') { // ISOLatin is actually /A this.skipNextChar(); } } else { cs = DEFAULT_CHARSET; } this._terminal.setgCharset(this._terminal.gcharset, cs); this._terminal.gcharset = null; this._state = ParserState.NORMAL; break; case ParserState.OSC: // OSC Ps ; Pt ST // OSC Ps ; Pt BEL // Set Text Parameters. if (ch === C0.ESC || ch === C0.BEL) { if (ch === C0.ESC) this._position++; this._terminal.params.push(this._terminal.currentParam); switch (this._terminal.params[0]) { case 0: case 1: case 2: if (this._terminal.params[1]) { this._terminal.title = this._terminal.params[1]; this._terminal.handleTitle(this._terminal.title); } break; case 3: // set X property break; case 4: case 5: // change dynamic colors break; case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: // change dynamic ui colors break; case 46: // change log file break; case 50: // dynamic font break; case 51: // emacs shell break; case 52: // manipulate selection data break; case 104: case 105: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: // reset colors break; } this._terminal.params = []; this._terminal.currentParam = 0; this._state = ParserState.NORMAL; } else { if (!this._terminal.params.length) { if (ch >= '0' && ch <= '9') { this._terminal.currentParam = this._terminal.currentParam * 10 + ch.charCodeAt(0) - 48; } else if (ch === ';') { this._terminal.params.push(this._terminal.currentParam); this._terminal.currentParam = ''; } } else { this._terminal.currentParam += ch; } } break; case ParserState.CSI_PARAM: if (ch in csiParamStateHandler) { csiParamStateHandler[ch](this); break; } this.finalizeParam(); // Fall through the CSI as this character should be the CSI code. this._state = ParserState.CSI; case ParserState.CSI: if (ch in csiStateHandler) { csiStateHandler[ch](this._inputHandler, this._terminal.params, this._terminal.prefix, this._terminal.postfix, this); } else { this._terminal.error('Unknown CSI code: %s.', ch); } this._state = ParserState.NORMAL; this._terminal.prefix = ''; this._terminal.postfix = ''; break; case ParserState.DCS: if (ch === C0.ESC || ch === C0.BEL) { if (ch === C0.ESC) this._position++; let pt; let valid: boolean; switch (this._terminal.prefix) { // User-Defined Keys (DECUDK). case '': break; // Request Status String (DECRQSS). // test: echo -e '\eP$q"p\e\\' case '$q': pt = this._terminal.currentParam; valid = false; switch (pt) { // DECSCA case '"q': pt = '0"q'; break; // DECSCL case '"p': pt = '61"p'; break; // DECSTBM case 'r': pt = '' + (this._terminal.scrollTop + 1) + ';' + (this._terminal.scrollBottom + 1) + 'r'; break; // SGR case 'm': pt = '0m'; break; default: this._terminal.error('Unknown DCS Pt: %s.', pt); pt = ''; break; } this._terminal.send(C0.ESC + 'P' + +valid + '$r' + pt + C0.ESC + '\\'); break; // Set Termcap/Terminfo Data (xterm, experimental). case '+p': break; // Request Termcap/Terminfo String (xterm, experimental) // Regular xterm does not even respond to this sequence. // This can cause a small glitch in vim. // test: echo -ne '\eP+q6b64\e\\' case '+q': pt = this._terminal.currentParam; valid = false; this._terminal.send(C0.ESC + 'P' + +valid + '+r' + pt + C0.ESC + '\\'); break; default: this._terminal.error('Unknown DCS prefix: %s.', this._terminal.prefix); break; } this._terminal.currentParam = 0; this._terminal.prefix = ''; this._state = ParserState.NORMAL; } else if (!this._terminal.currentParam) { if (!this._terminal.prefix && ch !== '$' && ch !== '+') { this._terminal.currentParam = ch; } else if (this._terminal.prefix.length === 2) { this._terminal.currentParam = ch; } else { this._terminal.prefix += ch; } } else { this._terminal.currentParam += ch; } break; case ParserState.IGNORE: // For PM and APC. if (ch === C0.ESC || ch === C0.BEL) { if (ch === C0.ESC) this._position++; this._state = ParserState.NORMAL; } break; } } return this._state; } /** * Set the parser's current parsing state. * * @param state The new state. */ public setState(state: ParserState): void { this._state = state; } /** * Sets the parsier's current prefix. CSI codes can have prefixes of '?', '>' * or '!'. * * @param prefix The prefix. */ public setPrefix(prefix: string): void { this._terminal.prefix = prefix; } /** * Sets the parsier's current prefix. CSI codes can have postfixes of '$', * '"', ' ', '\''. * * @param postfix The postfix. */ public setPostfix(postfix: string): void { this._terminal.postfix = postfix; } /** * Sets the parser's current parameter. * * @param param the parameter. */ public setParam(param: number) { this._terminal.currentParam = param; } /** * Gets the parser's current parameter. */ public getParam(): number { return this._terminal.currentParam; } /** * Finalizes the parser's current parameter, adding it to the list of * parameters and setting the new current parameter to 0. */ public finalizeParam(): void { this._terminal.params.push(this._terminal.currentParam); this._terminal.currentParam = 0; } /** * Tell the parser to skip the next character. */ public skipNextChar(): void { this._position++; } /** * Tell the parser to repeat parsing the current character (for example if it * needs parsing using a different state. */ // public repeatChar(): void { // this._position--; // } } xterm.js-2.7.0/src/Renderer.ts000066400000000000000000000250441311554223300162030ustar00rootroot00000000000000/** * @license MIT */ import { ITerminal } from './Interfaces'; import { DomElementObjectPool } from './utils/DomElementObjectPool'; /** * The maximum number of refresh frames to skip when the write buffer is non- * empty. Note that these frames may be intermingled with frames that are * skipped via requestAnimationFrame's mechanism. */ const MAX_REFRESH_FRAME_SKIP = 5; /** * Flags used to render terminal text properly. */ enum FLAGS { BOLD = 1, UNDERLINE = 2, BLINK = 4, INVERSE = 8, INVISIBLE = 16 }; let brokenBold: boolean = null; export class Renderer { /** A queue of the rows to be refreshed */ private _refreshRowsQueue: {start: number, end: number}[] = []; private _refreshFramesSkipped = 0; private _refreshAnimationFrame = null; private _spanElementObjectPool = new DomElementObjectPool('span'); constructor(private _terminal: ITerminal) { // Figure out whether boldness affects // the character width of monospace fonts. if (brokenBold === null) { brokenBold = checkBoldBroken((this._terminal).element); } this._spanElementObjectPool = new DomElementObjectPool('span'); // TODO: Pull more DOM interactions into Renderer.constructor, element for // example should be owned by Renderer (and also exposed by Terminal due to // to established public API). } /** * Queues a refresh between two rows (inclusive), to be done on next animation * frame. * @param {number} start The start row. * @param {number} end The end row. */ public queueRefresh(start: number, end: number): void { this._refreshRowsQueue.push({ start: start, end: end }); if (!this._refreshAnimationFrame) { this._refreshAnimationFrame = window.requestAnimationFrame(this._refreshLoop.bind(this)); } } /** * Performs the refresh loop callback, calling refresh only if a refresh is * necessary before queueing up the next one. */ private _refreshLoop(): void { // Skip MAX_REFRESH_FRAME_SKIP frames if the writeBuffer is non-empty as it // will need to be immediately refreshed anyway. This saves a lot of // rendering time as the viewport DOM does not need to be refreshed, no // scroll events, no layouts, etc. const skipFrame = this._terminal.writeBuffer.length > 0 && this._refreshFramesSkipped++ <= MAX_REFRESH_FRAME_SKIP; if (skipFrame) { this._refreshAnimationFrame = window.requestAnimationFrame(this._refreshLoop.bind(this)); return; } this._refreshFramesSkipped = 0; let start; let end; if (this._refreshRowsQueue.length > 4) { // Just do a full refresh when 5+ refreshes are queued start = 0; end = this._terminal.rows - 1; } else { // Get start and end rows that need refreshing start = this._refreshRowsQueue[0].start; end = this._refreshRowsQueue[0].end; for (let i = 1; i < this._refreshRowsQueue.length; i++) { if (this._refreshRowsQueue[i].start < start) { start = this._refreshRowsQueue[i].start; } if (this._refreshRowsQueue[i].end > end) { end = this._refreshRowsQueue[i].end; } } } this._refreshRowsQueue = []; this._refreshAnimationFrame = null; this._refresh(start, end); } /** * Refreshes (re-renders) terminal content within two rows (inclusive) * * Rendering Engine: * * In the screen buffer, each character is stored as a an array with a character * and a 32-bit integer: * - First value: a utf-16 character. * - Second value: * - Next 9 bits: background color (0-511). * - Next 9 bits: foreground color (0-511). * - Next 14 bits: a mask for misc. flags: * - 1=bold * - 2=underline * - 4=blink * - 8=inverse * - 16=invisible * * @param {number} start The row to start from (between 0 and terminal's height terminal - 1) * @param {number} end The row to end at (between fromRow and terminal's height terminal - 1) */ private _refresh(start: number, end: number): void { // If this is a big refresh, remove the terminal rows from the DOM for faster calculations let parent; if (end - start >= this._terminal.rows / 2) { parent = this._terminal.element.parentNode; if (parent) { this._terminal.element.removeChild(this._terminal.rowContainer); } } let width = this._terminal.cols; let y = start; if (end >= this._terminal.rows) { this._terminal.log('`end` is too large. Most likely a bad CSR.'); end = this._terminal.rows - 1; } for (; y <= end; y++) { let row = y + this._terminal.ydisp; let line = this._terminal.lines.get(row); let x; if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp) && this._terminal.cursorState && !this._terminal.cursorHidden) { x = this._terminal.x; } else { x = -1; } let attr = this._terminal.defAttr; const documentFragment = document.createDocumentFragment(); let innerHTML = ''; let currentElement; // Return the row's spans to the pool while (this._terminal.children[y].children.length) { const child = this._terminal.children[y].children[0]; this._terminal.children[y].removeChild(child); this._spanElementObjectPool.release(child); } for (let i = 0; i < width; i++) { // TODO: Could data be a more specific type? let data: any = line[i][0]; const ch = line[i][1]; const ch_width: any = line[i][2]; if (!ch_width) { continue; } if (i === x) { data = -1; } if (data !== attr) { if (attr !== this._terminal.defAttr) { if (innerHTML) { currentElement.innerHTML = innerHTML; innerHTML = ''; } documentFragment.appendChild(currentElement); currentElement = null; } if (data !== this._terminal.defAttr) { if (innerHTML && !currentElement) { currentElement = this._spanElementObjectPool.acquire(); } if (currentElement) { if (innerHTML) { currentElement.innerHTML = innerHTML; innerHTML = ''; } documentFragment.appendChild(currentElement); } currentElement = this._spanElementObjectPool.acquire(); if (data === -1) { currentElement.classList.add('reverse-video', 'terminal-cursor'); } else { let bg = data & 0x1ff; let fg = (data >> 9) & 0x1ff; let flags = data >> 18; if (flags & FLAGS.BOLD) { if (!brokenBold) { currentElement.classList.add('xterm-bold'); } // See: XTerm*boldColors if (fg < 8) { fg += 8; } } if (flags & FLAGS.UNDERLINE) { currentElement.classList.add('xterm-underline'); } if (flags & FLAGS.BLINK) { currentElement.classList.add('xterm-blink'); } // If inverse flag is on, then swap the foreground and background variables. if (flags & FLAGS.INVERSE) { let temp = bg; bg = fg; fg = temp; // Should inverse just be before the above boldColors effect instead? if ((flags & 1) && fg < 8) { fg += 8; } } if (flags & FLAGS.INVISIBLE) { currentElement.classList.add('xterm-hidden'); } /** * Weird situation: Invert flag used black foreground and white background results * in invalid background color, positioned at the 256 index of the 256 terminal * color map. Pin the colors manually in such a case. * * Source: https://github.com/sourcelair/xterm.js/issues/57 */ if (flags & FLAGS.INVERSE) { if (bg === 257) { bg = 15; } if (fg === 256) { fg = 0; } } if (bg < 256) { currentElement.classList.add(`xterm-bg-color-${bg}`); } if (fg < 256) { currentElement.classList.add(`xterm-color-${fg}`); } } } } if (ch_width === 2) { // Wrap wide characters so they're sized correctly. It's more difficult to release these // from the object pool so just create new ones via innerHTML. innerHTML += `${ch}`; } else if (ch.charCodeAt(0) > 255) { // Wrap any non-wide unicode character as some fonts size them badly innerHTML += `${ch}`; } else { switch (ch) { case '&': innerHTML += '&'; break; case '<': innerHTML += '<'; break; case '>': innerHTML += '>'; break; default: if (ch <= ' ') { innerHTML += ' '; } else { innerHTML += ch; } break; } } attr = data; } if (innerHTML && !currentElement) { currentElement = this._spanElementObjectPool.acquire(); } if (currentElement) { if (innerHTML) { currentElement.innerHTML = innerHTML; innerHTML = ''; } documentFragment.appendChild(currentElement); currentElement = null; } this._terminal.children[y].appendChild(documentFragment); } if (parent) { this._terminal.element.appendChild(this._terminal.rowContainer); } this._terminal.emit('refresh', {element: this._terminal.element, start: start, end: end}); }; } // If bold is broken, we can't use it in the terminal. function checkBoldBroken(terminal) { const document = terminal.ownerDocument; const el = document.createElement('span'); el.innerHTML = 'hello world'; terminal.appendChild(el); const w1 = el.offsetWidth; const h1 = el.offsetHeight; el.style.fontWeight = 'bold'; const w2 = el.offsetWidth; const h2 = el.offsetHeight; terminal.removeChild(el); return w1 !== w2 || h1 !== h2; } xterm.js-2.7.0/src/Types.ts000066400000000000000000000006531311554223300155400ustar00rootroot00000000000000/** * @license MIT */ export type LinkMatcher = { id: number, regex: RegExp, handler: LinkMatcherHandler, matchIndex?: number, validationCallback?: LinkMatcherValidationCallback, priority?: number }; export type LinkMatcherHandler = (event: MouseEvent, uri: string) => boolean | void; export type LinkMatcherValidationCallback = (uri: string, element: HTMLElement, callback: (isValid: boolean) => void) => void; xterm.js-2.7.0/src/Viewport.test.ts000066400000000000000000000047401311554223300172320ustar00rootroot00000000000000import { assert } from 'chai'; import { Viewport } from './Viewport'; describe('Viewport', () => { let terminal; let viewportElement; let charMeasure; let viewport; let scrollAreaElement; const CHARACTER_HEIGHT = 10; beforeEach(() => { terminal = { lines: [], rows: 0, ydisp: 0, on: () => {}, rowContainer: { style: { lineHeight: 0 } } }; viewportElement = { addEventListener: () => {}, style: { height: 0, lineHeight: 0 } }; scrollAreaElement = { style: { height: 0 } }; charMeasure = { height: CHARACTER_HEIGHT }; viewport = new Viewport(terminal, viewportElement, scrollAreaElement, charMeasure); }); describe('refresh', () => { it('should set the line-height of the terminal', done => { // Allow CharMeasure to be initialized setTimeout(() => { assert.equal(viewportElement.style.lineHeight, CHARACTER_HEIGHT + 'px'); assert.equal(terminal.rowContainer.style.lineHeight, CHARACTER_HEIGHT + 'px'); charMeasure.height = 1; viewport.refresh(); assert.equal(viewportElement.style.lineHeight, '1px'); assert.equal(terminal.rowContainer.style.lineHeight, '1px'); done(); }, 0); }); it('should set the height of the viewport when the line-height changed', () => { terminal.lines.push(''); terminal.lines.push(''); terminal.rows = 1; viewport.refresh(); assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px'); charMeasure.height = 20; viewport.refresh(); assert.equal(viewportElement.style.height, 20 + 'px'); }); }); describe('syncScrollArea', () => { it('should sync the scroll area', done => { // Allow CharMeasure to be initialized setTimeout(() => { terminal.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(''); viewport.syncScrollArea(); assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px'); assert.equal(scrollAreaElement.style.height, 2 * CHARACTER_HEIGHT + 'px'); done(); }, 0); }); }); }); xterm.js-2.7.0/src/Viewport.ts000066400000000000000000000106071311554223300162530ustar00rootroot00000000000000/** * @license MIT */ import { ITerminal } from './Interfaces'; import { CharMeasure } from './utils/CharMeasure'; /** * Represents the viewport of a terminal, the visible area within the larger buffer of output. * Logic for the virtual scroll bar is included in this object. */ export class Viewport { private currentRowHeight: number; private lastRecordedBufferLength: number; private lastRecordedViewportHeight: number; /** * Creates a new Viewport. * @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. */ constructor( private terminal: ITerminal, private viewportElement: HTMLElement, private scrollArea: HTMLElement, private charMeasure: CharMeasure ) { this.currentRowHeight = 0; this.lastRecordedBufferLength = 0; this.lastRecordedViewportHeight = 0; this.terminal.on('scroll', this.syncScrollArea.bind(this)); this.terminal.on('resize', this.syncScrollArea.bind(this)); this.viewportElement.addEventListener('scroll', this.onScroll.bind(this)); // Perform this async to ensure the CharMeasure is ready. setTimeout(() => this.syncScrollArea(), 0); } /** * 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) { const rowHeightChanged = this.charMeasure.height !== this.currentRowHeight; if (rowHeightChanged) { this.currentRowHeight = this.charMeasure.height; this.viewportElement.style.lineHeight = this.charMeasure.height + 'px'; this.terminal.rowContainer.style.lineHeight = this.charMeasure.height + 'px'; } const viewportHeightChanged = this.lastRecordedViewportHeight !== this.terminal.rows; if (rowHeightChanged || viewportHeightChanged) { this.lastRecordedViewportHeight = this.terminal.rows; this.viewportElement.style.height = this.charMeasure.height * this.terminal.rows + 'px'; } this.scrollArea.style.height = (this.charMeasure.height * this.lastRecordedBufferLength) + 'px'; } } /** * Updates dimensions and synchronizes the scroll area if necessary. */ public syncScrollArea(): void { if (this.lastRecordedBufferLength !== this.terminal.lines.length) { // If buffer height changed this.lastRecordedBufferLength = this.terminal.lines.length; this.refresh(); } else if (this.lastRecordedViewportHeight !== this.terminal.rows) { // If viewport height changed this.refresh(); } else { // If size has changed, refresh viewport if (this.charMeasure.height !== this.currentRowHeight) { this.refresh(); } } // Sync scrollTop const scrollTop = this.terminal.ydisp * this.currentRowHeight; if (this.viewportElement.scrollTop !== scrollTop) { this.viewportElement.scrollTop = scrollTop; } } /** * Handles scroll events on the viewport, calculating the new viewport and requesting the * terminal to scroll to it. * @param ev The scroll event. */ private onScroll(ev: Event) { const newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight); const diff = newRow - this.terminal.ydisp; this.terminal.scrollDisp(diff, true); } /** * Handles mouse wheel events by adjusting the viewport's scrollTop and delegating the actual * scrolling to `onScroll`, this event needs to be attached manually by the consumer of * `Viewport`. * @param ev The mouse wheel event. */ public onWheel(ev: WheelEvent) { if (ev.deltaY === 0) { // Do nothing if it's not a vertical scroll event return; } // Fallback to WheelEvent.DOM_DELTA_PIXEL let multiplier = 1; if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) { multiplier = this.currentRowHeight; } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) { multiplier = this.currentRowHeight * this.terminal.rows; } this.viewportElement.scrollTop += ev.deltaY * multiplier; // Prevent the page from scrolling when the terminal scrolls ev.preventDefault(); }; } xterm.js-2.7.0/src/addons/000077500000000000000000000000001311554223300153305ustar00rootroot00000000000000xterm.js-2.7.0/src/addons/attach/000077500000000000000000000000001311554223300165745ustar00rootroot00000000000000xterm.js-2.7.0/src/addons/attach/attach.js000066400000000000000000000073571311554223300204120ustar00rootroot00000000000000/** * Implements the attach method, that attaches the terminal to a WebSocket stream. * @module xterm/addons/attach/attach * @license MIT */ (function (attach) { if (typeof exports === 'object' && typeof module === 'object') { /* * CommonJS environment */ module.exports = attach(require('../../xterm')); } else if (typeof define == 'function') { /* * Require.js is available */ define(['../../xterm'], attach); } else { /* * Plain browser environment */ attach(window.Terminal); } })(function (Xterm) { 'use strict'; var exports = {}; /** * Attaches the given terminal to the given socket. * * @param {Xterm} term - The terminal to be attached to the given socket. * @param {WebSocket} socket - The socket to attach the current terminal. * @param {boolean} bidirectional - Whether the terminal should send data * to the socket as well. * @param {boolean} buffered - Whether the rendering of incoming data * should happen instantly or at a maximum * frequency of 1 rendering per 10ms. */ exports.attach = function (term, socket, bidirectional, buffered) { bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; term.socket = socket; term._flushBuffer = function () { term.write(term._attachSocketBuffer); term._attachSocketBuffer = null; clearTimeout(term._attachSocketBufferTimer); term._attachSocketBufferTimer = null; }; term._pushToBuffer = function (data) { if (term._attachSocketBuffer) { term._attachSocketBuffer += data; } else { term._attachSocketBuffer = data; setTimeout(term._flushBuffer, 10); } }; term._getMessage = function (ev) { if (buffered) { term._pushToBuffer(ev.data); } else { term.write(ev.data); } }; term._sendData = function (data) { socket.send(data); }; socket.addEventListener('message', term._getMessage); if (bidirectional) { term.on('data', term._sendData); } socket.addEventListener('close', term.detach.bind(term, socket)); socket.addEventListener('error', term.detach.bind(term, socket)); }; /** * Detaches the given terminal from the given socket * * @param {Xterm} term - The terminal to be detached from the given socket. * @param {WebSocket} socket - The socket from which to detach the current * terminal. */ exports.detach = function (term, socket) { term.off('data', term._sendData); socket = (typeof socket == 'undefined') ? term.socket : socket; if (socket) { socket.removeEventListener('message', term._getMessage); } delete term.socket; }; /** * Attaches the current terminal to the given socket * * @param {WebSocket} socket - The socket to attach the current terminal. * @param {boolean} bidirectional - Whether the terminal should send data * to the socket as well. * @param {boolean} buffered - Whether the rendering of incoming data * should happen instantly or at a maximum * frequency of 1 rendering per 10ms. */ Xterm.prototype.attach = function (socket, bidirectional, buffered) { return exports.attach(this, socket, bidirectional, buffered); }; /** * Detaches the current terminal from the given socket. * * @param {WebSocket} socket - The socket from which to detach the current * terminal. */ Xterm.prototype.detach = function (socket) { return exports.detach(this, socket); }; return exports; }); xterm.js-2.7.0/src/addons/attach/index.html000066400000000000000000000043761311554223300206030ustar00rootroot00000000000000

xterm.js: socket attach

Attach the terminal to a WebSocket terminal stream with ease. Perfect for attaching to your Docker containers.

Socket information

xterm.js-2.7.0/src/addons/attach/package.json000066400000000000000000000001071311554223300210600ustar00rootroot00000000000000{ "name": "xterm.attach", "main": "attach.js", "private": true } xterm.js-2.7.0/src/addons/fit/000077500000000000000000000000001311554223300161125ustar00rootroot00000000000000xterm.js-2.7.0/src/addons/fit/fit.js000066400000000000000000000055761311554223300172470ustar00rootroot00000000000000/** * Fit terminal columns and rows to the dimensions of its DOM element. * * ## Approach * - Rows: Truncate the division of the terminal parent element height by the terminal row height. * * - Columns: Truncate the division of the terminal parent element width by the terminal character * width (apply display: inline at the terminal row and truncate its width with the current * number of columns). * @module xterm/addons/fit/fit * @license MIT */ (function (fit) { if (typeof exports === 'object' && typeof module === 'object') { /* * CommonJS environment */ module.exports = fit(require('../../xterm')); } else if (typeof define == 'function') { /* * Require.js is available */ define(['../../xterm'], fit); } else { /* * Plain browser environment */ fit(window.Terminal); } })(function (Xterm) { var exports = {}; exports.proposeGeometry = function (term) { if (!term.element.parentElement) { return null; } var parentElementStyle = window.getComputedStyle(term.element.parentElement), parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')), parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17), elementStyle = window.getComputedStyle(term.element), elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')), elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')), availableHeight = parentElementHeight - elementPaddingVer, availableWidth = parentElementWidth - elementPaddingHor, container = term.rowContainer, subjectRow = term.rowContainer.firstElementChild, contentBuffer = subjectRow.innerHTML, characterHeight, rows, characterWidth, cols, geometry; subjectRow.style.display = 'inline'; subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace characterWidth = subjectRow.getBoundingClientRect().width; subjectRow.style.display = ''; // Revert style before calculating height, since they differ. characterHeight = subjectRow.getBoundingClientRect().height; subjectRow.innerHTML = contentBuffer; rows = parseInt(availableHeight / characterHeight); cols = parseInt(availableWidth / characterWidth); geometry = {cols: cols, rows: rows}; return geometry; }; exports.fit = function (term) { var geometry = exports.proposeGeometry(term); if (geometry) { term.resize(geometry.cols, geometry.rows); } }; Xterm.prototype.proposeGeometry = function () { return exports.proposeGeometry(this); }; Xterm.prototype.fit = function () { return exports.fit(this); }; return exports; }); xterm.js-2.7.0/src/addons/fit/package.json000066400000000000000000000001011311554223300203700ustar00rootroot00000000000000{ "name": "xterm.fit", "main": "fit.js", "private": true } xterm.js-2.7.0/src/addons/fullscreen/000077500000000000000000000000001311554223300174725ustar00rootroot00000000000000xterm.js-2.7.0/src/addons/fullscreen/fullscreen.css000066400000000000000000000002261311554223300223460ustar00rootroot00000000000000.xterm.fullscreen { position: fixed; top: 0; bottom: 0; left: 0; right: 0; width: auto; height: auto; z-index: 255; } xterm.js-2.7.0/src/addons/fullscreen/fullscreen.js000066400000000000000000000023351311554223300221750ustar00rootroot00000000000000/** * Fullscreen addon for xterm.js * @module xterm/addons/fullscreen/fullscreen * @license MIT */ (function (fullscreen) { if (typeof exports === 'object' && typeof module === 'object') { /* * CommonJS environment */ module.exports = fullscreen(require('../../xterm')); } else if (typeof define == 'function') { /* * Require.js is available */ define(['../../xterm'], fullscreen); } else { /* * Plain browser environment */ fullscreen(window.Terminal); } })(function (Xterm) { var exports = {}; /** * Toggle the given terminal's fullscreen mode. * @param {Xterm} term - The terminal to toggle full screen mode * @param {boolean} fullscreen - Toggle fullscreen on (true) or off (false) */ exports.toggleFullScreen = function (term, fullscreen) { var fn; if (typeof fullscreen == 'undefined') { fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add'; } else if (!fullscreen) { fn = 'remove'; } else { fn = 'add'; } term.element.classList[fn]('fullscreen'); }; Xterm.prototype.toggleFullscreen = function (fullscreen) { exports.toggleFullScreen(this, fullscreen); }; return exports; }); xterm.js-2.7.0/src/addons/fullscreen/package.json000066400000000000000000000001171311554223300217570ustar00rootroot00000000000000{ "name": "xterm.fullscreen", "main": "fullscreen.js", "private": true } xterm.js-2.7.0/src/addons/terminado/000077500000000000000000000000001311554223300173125ustar00rootroot00000000000000xterm.js-2.7.0/src/addons/terminado/package.json000066400000000000000000000001151311554223300215750ustar00rootroot00000000000000{ "name": "xterm.terminado", "main": "terminado.js", "private": true } xterm.js-2.7.0/src/addons/terminado/terminado.js000066400000000000000000000101261311554223300216320ustar00rootroot00000000000000/** * This module provides methods for attaching a terminal to a terminado WebSocket stream. * * @module xterm/addons/terminado/terminado * @license MIT */ (function (attach) { if (typeof exports === 'object' && typeof module === 'object') { /* * CommonJS environment */ module.exports = attach(require('../../xterm')); } else if (typeof define == 'function') { /* * Require.js is available */ define(['../../xterm'], attach); } else { /* * Plain browser environment */ attach(window.Terminal); } })(function (Xterm) { 'use strict'; var exports = {}; /** * Attaches the given terminal to the given socket. * * @param {Xterm} term - The terminal to be attached to the given socket. * @param {WebSocket} socket - The socket to attach the current terminal. * @param {boolean} bidirectional - Whether the terminal should send data * to the socket as well. * @param {boolean} buffered - Whether the rendering of incoming data * should happen instantly or at a maximum * frequency of 1 rendering per 10ms. */ exports.terminadoAttach = function (term, socket, bidirectional, buffered) { bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional; term.socket = socket; term._flushBuffer = function () { term.write(term._attachSocketBuffer); term._attachSocketBuffer = null; clearTimeout(term._attachSocketBufferTimer); term._attachSocketBufferTimer = null; }; term._pushToBuffer = function (data) { if (term._attachSocketBuffer) { term._attachSocketBuffer += data; } else { term._attachSocketBuffer = data; setTimeout(term._flushBuffer, 10); } }; term._getMessage = function (ev) { var data = JSON.parse(ev.data) if( data[0] == "stdout" ) { if (buffered) { term._pushToBuffer(data[1]); } else { term.write(data[1]); } } }; term._sendData = function (data) { socket.send(JSON.stringify(['stdin', data])); }; term._setSize = function (size) { socket.send(JSON.stringify(['set_size', size.rows, size.cols])); }; socket.addEventListener('message', term._getMessage); if (bidirectional) { term.on('data', term._sendData); } term.on('resize', term._setSize); socket.addEventListener('close', term.terminadoDetach.bind(term, socket)); socket.addEventListener('error', term.terminadoDetach.bind(term, socket)); }; /** * Detaches the given terminal from the given socket * * @param {Xterm} term - The terminal to be detached from the given socket. * @param {WebSocket} socket - The socket from which to detach the current * terminal. */ exports.terminadoDetach = function (term, socket) { term.off('data', term._sendData); socket = (typeof socket == 'undefined') ? term.socket : socket; if (socket) { socket.removeEventListener('message', term._getMessage); } delete term.socket; }; /** * Attaches the current terminal to the given socket * * @param {WebSocket} socket - The socket to attach the current terminal. * @param {boolean} bidirectional - Whether the terminal should send data * to the socket as well. * @param {boolean} buffered - Whether the rendering of incoming data * should happen instantly or at a maximum * frequency of 1 rendering per 10ms. */ Xterm.prototype.terminadoAttach = function (socket, bidirectional, buffered) { return exports.terminadoAttach(this, socket, bidirectional, buffered); }; /** * Detaches the current terminal from the given socket. * * @param {WebSocket} socket - The socket from which to detach the current * terminal. */ Xterm.prototype.terminadoDetach = function (socket) { return exports.terminadoDetach(this, socket); }; return exports; }); xterm.js-2.7.0/src/handlers/000077500000000000000000000000001311554223300156605ustar00rootroot00000000000000xterm.js-2.7.0/src/handlers/Clipboard.test.ts000066400000000000000000000021221311554223300211020ustar00rootroot00000000000000import { assert } from 'chai'; import * as Terminal from '../xterm'; import * as Clipboard from './Clipboard'; describe('evaluateCopiedTextProcessing', function () { it('should strip trailing whitespaces and replace nbsps with spaces', function () { let nonBreakingSpace = String.fromCharCode(160), copiedText = 'echo' + nonBreakingSpace + 'hello' + nonBreakingSpace, processedText = Clipboard.prepareTextForClipboard(copiedText); // No trailing spaces assert.equal(processedText.match(/\s+$/), null); // No non-breaking space assert.equal(processedText.indexOf(nonBreakingSpace), -1); }); }); describe('evaluatePastedTextProcessing', function () { it('should replace carriage return + line feed with line feed on windows', function () { const pastedText = 'foo\r\nbar\r\n', processedText = Clipboard.prepareTextForTerminal(pastedText, false), windowsProcessedText = Clipboard.prepareTextForTerminal(pastedText, true); assert.equal(processedText, 'foo\r\nbar\r\n'); assert.equal(windowsProcessedText, 'foo\nbar\n'); }); }); xterm.js-2.7.0/src/handlers/Clipboard.ts000066400000000000000000000123701311554223300201320ustar00rootroot00000000000000/** * Clipboard handler module: exports methods for handling all clipboard-related events in the * terminal. * @module xterm/handlers/Clipboard * @license MIT */ import { ITerminal } from '../Interfaces'; interface IWindow extends Window { clipboardData?: { getData(format: string): string; setData(format: string, data: string); }; } declare var window: IWindow; /** * Prepares text copied from terminal selection, to be saved in the clipboard by: * 1. stripping all trailing white spaces * 2. converting all non-breaking spaces to regular spaces * @param {string} text The copied text that needs processing for storing in clipboard * @returns {string} */ export function prepareTextForClipboard(text: string): string { let space = String.fromCharCode(32), nonBreakingSpace = String.fromCharCode(160), allNonBreakingSpaces = new RegExp(nonBreakingSpace, 'g'), processedText = text.split('\n').map(function (line) { // Strip all trailing white spaces and convert all non-breaking spaces // to regular spaces. let processedLine = line.replace(/\s+$/g, '').replace(allNonBreakingSpaces, space); return processedLine; }).join('\n'); return processedText; } /** * Prepares text to be pasted into the terminal by normalizing the line endings * @param text The pasted text that needs processing before inserting into the terminal */ export function prepareTextForTerminal(text: string, isMSWindows: boolean): string { if (isMSWindows) { return text.replace(/\r?\n/g, '\n'); } return text; } /** * Binds copy functionality to the given terminal. * @param {ClipboardEvent} ev The original copy event to be handled */ export function copyHandler(ev: ClipboardEvent, term: ITerminal) { // We cast `window` to `any` type, because TypeScript has not declared the `clipboardData` // property that we use below for Internet Explorer. let copiedText = window.getSelection().toString(), text = prepareTextForClipboard(copiedText); if (term.browser.isMSIE) { window.clipboardData.setData('Text', text); } else { ev.clipboardData.setData('text/plain', text); } ev.preventDefault(); // Prevent or the original text will be copied. } /** * Redirect the clipboard's data to the terminal's input handler. * @param {ClipboardEvent} ev The original paste event to be handled * @param {Terminal} term The terminal on which to apply the handled paste event */ export function pasteHandler(ev: ClipboardEvent, term: ITerminal) { ev.stopPropagation(); let text: string; let dispatchPaste = function(text) { text = prepareTextForTerminal(text, term.browser.isMSWindows); term.handler(text); term.textarea.value = ''; term.emit('paste', text); return term.cancel(ev); }; if (term.browser.isMSIE) { if (window.clipboardData) { text = window.clipboardData.getData('Text'); dispatchPaste(text); } } else { if (ev.clipboardData) { text = ev.clipboardData.getData('text/plain'); dispatchPaste(text); } } } /** * Bind to right-click event and allow right-click copy and paste. * * **Logic** * If text is selected and right-click happens on selected text, then * do nothing to allow seamless copying. * If no text is selected or right-click is outside of the selection * area, then bring the terminal's input below the cursor, in order to * trigger the event on the textarea and allow-right click paste, without * caring about disappearing selection. * @param {MouseEvent} ev The original right click event to be handled * @param {Terminal} term The terminal on which to apply the handled paste event */ export function rightClickHandler(ev: MouseEvent, term: ITerminal) { let s = document.getSelection(), selectedText = prepareTextForClipboard(s.toString()), clickIsOnSelection = false, x = ev.clientX, y = ev.clientY; if (s.rangeCount) { let r = s.getRangeAt(0), cr = r.getClientRects(); for (let i = 0; i < cr.length; i++) { let rect = cr[i]; clickIsOnSelection = ( (x > rect.left) && (x < rect.right) && (y > rect.top) && (y < rect.bottom) ); if (clickIsOnSelection) { break; } } // If we clicked on selection and selection is not a single space, // then mark the right click as copy-only. We check for the single // space selection, as this can happen when clicking on an   // and there is not much pointing in copying a single space. if (selectedText.match(/^\s$/) || !selectedText.length) { clickIsOnSelection = false; } } // Bring textarea at the cursor position if (!clickIsOnSelection) { term.textarea.style.position = 'fixed'; term.textarea.style.width = '20px'; term.textarea.style.height = '20px'; term.textarea.style.left = (x - 10) + 'px'; term.textarea.style.top = (y - 10) + 'px'; term.textarea.style.zIndex = '1000'; term.textarea.focus(); // Reset the terminal textarea's styling setTimeout(function () { term.textarea.style.position = null; term.textarea.style.width = null; term.textarea.style.height = null; term.textarea.style.left = null; term.textarea.style.top = null; term.textarea.style.zIndex = null; }, 4); } } xterm.js-2.7.0/src/test/000077500000000000000000000000001311554223300150375ustar00rootroot00000000000000xterm.js-2.7.0/src/test/addons/000077500000000000000000000000001311554223300163075ustar00rootroot00000000000000xterm.js-2.7.0/src/test/addons/test.js000066400000000000000000000005221311554223300176230ustar00rootroot00000000000000var assert = require('chai').assert; var Terminal = require('../../xterm'); describe('xterm.js addons', function() { it('should load addons with Terminal.loadAddon', function () { Terminal.loadAddon('attach'); // Test that addon was loaded successfully assert.equal(typeof Terminal.prototype.attach, 'function'); }); }); xterm.js-2.7.0/src/test/escape-sequences-test.js000066400000000000000000000100111311554223300215740ustar00rootroot00000000000000var glob = require('glob'); var fs = require('fs'); var os = require('os'); var pty = require('node-pty'); var sleep = require('sleep'); var Terminal = require('../xterm'); if (os.platform() === 'win32') { // Skip tests on Windows since pty.open isn't supported return; } var CONSOLE_LOG = console.log; // expect files need terminal at 80x25! var COLS = 80; var ROWS = 25; /** some helpers for pty interaction */ // we need a pty in between to get the termios decorations // for the basic test cases a raw pty device is enough var primitive_pty = pty.native.open(COLS, ROWS); // fake sychronous pty write - read // we just pipe the data from slave to master as a child program would do // pty.js opens pipe fds with O_NONBLOCK // just wait 10ms instead of setting fds to blocking mode function pty_write_read(s) { fs.writeSync(primitive_pty.slave, s); sleep.usleep(10000); var b = Buffer(64000); var bytes = fs.readSync(primitive_pty.master, b, 0, 64000); return b.toString('utf8', 0, bytes); } // make sure raw pty is at x=0 and has no pending data function pty_reset() { pty_write_read('\r\n'); } /* debug helpers */ // generate colorful noisy output to compare xterm and emulator cell states function formatError(in_, out_, expected) { function addLineNumber(start, color) { var counter = start || 0; return function(s) { counter += 1; return '\x1b[33m' + (' ' + counter).slice(-2) + color + s; } } var line80 = '12345678901234567890123456789012345678901234567890123456789012345678901234567890'; var s = ''; s += '\n\x1b[34m' + JSON.stringify(in_); s += '\n\x1b[33m ' + line80 + '\n'; s += out_.split('\n').map(addLineNumber(0, '\x1b[31m')).join('\n'); s += '\n\x1b[33m ' + line80 + '\n'; s += expected.split('\n').map(addLineNumber(0, '\x1b[32m')).join('\n'); return s; } // simple debug output of terminal cells function terminalToString(term) { var result = ''; var line_s = ''; for (var line = term.ybase; line < term.ybase + term.rows; line++) { line_s = ''; for (var cell=0; cell= 0) { continue; } (function(filename) { it(filename.split('/').slice(-1)[0], function () { pty_reset(); var in_file = fs.readFileSync(filename, 'utf8'); var from_pty = pty_write_read(in_file); // uncomment this to get log from terminal //console.log = function(){}; // Perform a synchronous .write(data) xterm.writeBuffer.push(from_pty); xterm.innerWrite(); var from_emulator = terminalToString(xterm); console.log = CONSOLE_LOG; var expected = fs.readFileSync(filename.split('.')[0] + '.text', 'utf8'); // Some of the tests have whitespace on the right of lines, we trim all the linex // from xterm.js so ignore this for now at least. var expectedRightTrimmed = expected.split('\n').map(function (l) { return l.replace(/\s+$/, ''); }).join('\n'); if (from_emulator != expectedRightTrimmed) { // uncomment to get noisy output throw new Error(formatError(in_file, from_emulator, expected)); // throw new Error('mismatch'); } }); })(files[i]); } }); xterm.js-2.7.0/src/test/escape_sequence_files/000077500000000000000000000000001311554223300213515ustar00rootroot00000000000000xterm.js-2.7.0/src/test/escape_sequence_files/NOTES000066400000000000000000000011711311554223300221640ustar00rootroot00000000000000All tests are made for 80x25 terminal. Make sure to run tests with 80x25. Create .text files from xterm (expected output) - open xterm - resize xterm to 80x25 - run `python run_tests.py` - copy & paste whole window output into editor - add 26th empty line (due to line handling in toString) - not a bug, a feature ;) - advance to next test with ^D Known problems ############## t0031-HBP: - no documentation at all about CSIj found - skipping t0050-ICH: - bug in xterm? (cant ICH last real char, always sticks to last col) - text used from https://github.com/MarkLodato/vt100-parser/blob/master/test/t0050-ICH.text xterm.js-2.7.0/src/test/escape_sequence_files/t0001-all_printable.in000066400000000000000000000001451311554223300252530ustar00rootroot00000000000000 !"#$%&'()*+,-./ 0123456789:;<=>? @ABCDEFGHIJKLMNO PQRSTUVWXYZ[\]^_ `abcdefghijklmno pqrstuvwxyz{|}~ xterm.js-2.7.0/src/test/escape_sequence_files/t0001-all_printable.text000066400000000000000000000001701311554223300256270ustar00rootroot00000000000000 !"#$%&'()*+,-./ 0123456789:;<=>? @ABCDEFGHIJKLMNO PQRSTUVWXYZ[\]^_ `abcdefghijklmno pqrstuvwxyz{|}~ xterm.js-2.7.0/src/test/escape_sequence_files/t0002-history.in000066400000000000000000000002761311554223300241520ustar00rootroot00000000000000 ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ xterm.js-2.7.0/src/test/escape_sequence_files/t0002-history.text000066400000000000000000000000611311554223300245200ustar00rootroot00000000000000g h i j k l m n o p q r s t u v w x y z { | } ~ xterm.js-2.7.0/src/test/escape_sequence_files/t0002j-simple_string.in000066400000000000000000000000441311554223300254730ustar00rootroot00000000000000abcdefghijklmnopqrstuvwxyz0123456789xterm.js-2.7.0/src/test/escape_sequence_files/t0002j-simple_string.text000066400000000000000000000000751311554223300260550ustar00rootroot00000000000000abcdefghijklmnopqrstuvwxyz0123456789 xterm.js-2.7.0/src/test/escape_sequence_files/t0003-line_wrap.in000066400000000000000000000067611311554223300244370ustar00rootroot00000000000000a ab abc abcd abcde abcdef abcdefg abcdefgh abcdefghi abcdefghij abcdefghijk abcdefghijkl abcdefghijklm abcdefghijklmn abcdefghijklmno abcdefghijklmnop abcdefghijklmnopq abcdefghijklmnopqr abcdefghijklmnopqrs abcdefghijklmnopqrst abcdefghijklmnopqrstu abcdefghijklmnopqrstuv abcdefghijklmnopqrstuvw abcdefghijklmnopqrstuvwx abcdefghijklmnopqrstuvwxy abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyzA abcdefghijklmnopqrstuvwxyzAB abcdefghijklmnopqrstuvwxyzABC abcdefghijklmnopqrstuvwxyzABCD abcdefghijklmnopqrstuvwxyzABCDE abcdefghijklmnopqrstuvwxyzABCDEF abcdefghijklmnopqrstuvwxyzABCDEFG abcdefghijklmnopqrstuvwxyzABCDEFGH abcdefghijklmnopqrstuvwxyzABCDEFGHI abcdefghijklmnopqrstuvwxyzABCDEFGHIJ abcdefghijklmnopqrstuvwxyzABCDEFGHIJK abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLM abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890a abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890ab abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abc abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcd abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcde abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdef abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefg abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefgh abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghi abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghij abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijk abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijkl abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmn abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmno abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqr abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqrs abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqrst xterm.js-2.7.0/src/test/escape_sequence_files/t0003-line_wrap.text000066400000000000000000000030261311554223300250040ustar00rootroot00000000000000abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890a abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890ab abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abc abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcd abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcde abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdef abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefg abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefgh abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghi abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghij abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijk abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijkl abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmn abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmno abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq r abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq rs abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq rst xterm.js-2.7.0/src/test/escape_sequence_files/t0003j-LF.in000066400000000000000000000001051311554223300231140ustar00rootroot000000000000001 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 xterm.js-2.7.0/src/test/escape_sequence_files/t0003j-LF.text000066400000000000000000000001021311554223300234670ustar00rootroot000000000000003 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 xterm.js-2.7.0/src/test/escape_sequence_files/t0004-LF.in000066400000000000000000000002461311554223300227510ustar00rootroot00000000000000a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t xterm.js-2.7.0/src/test/escape_sequence_files/t0004-LF.text000066400000000000000000000000611311554223300233220ustar00rootroot000000000000007 8 9 0 a b c d e f g h i j k l m n o p q r s t xterm.js-2.7.0/src/test/escape_sequence_files/t0004j-CR.in000066400000000000000000000003021311554223300231170ustar00rootroot000000000000001 x 2 x 3 x 4 x 5 x 6 x 7 xxterm.js-2.7.0/src/test/escape_sequence_files/t0004j-CR.text000066400000000000000000000003071311554223300235020ustar00rootroot00000000000000x x2 x 3 x 4 x 5 x 6 x 7 xterm.js-2.7.0/src/test/escape_sequence_files/t0005-CR.in000066400000000000000000000072231311554223300227570ustar00rootroot00000000000000b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a xterm.js-2.7.0/src/test/escape_sequence_files/t0005-CR.text000066400000000000000000000030761311554223300233370ustar00rootroot00000000000000a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a ab xterm.js-2.7.0/src/test/escape_sequence_files/t0006-IND.in000066400000000000000000000003701311554223300230620ustar00rootroot00000000000000aDbDcDdDeDfDgDhDiDjDkDlDmDnDoDpDqDrDsDtDuDvDwDxDyDzDADBDCDDDEDFDGDHDIDJDKDLDMDNDODPDQDRDSDTDUDVDWDXDYDZD0D1D2D3D4D5D6D7D8D9D0DaDbDcDdDeDfDgDhDiDjDkDlDmDnDoDpDqDrDsDt xterm.js-2.7.0/src/test/escape_sequence_files/t0006-IND.text000066400000000000000000000033071311554223300234430ustar00rootroot00000000000000 7 8 9 0 a b c d e f g h i j k l m n o p q r s t xterm.js-2.7.0/src/test/escape_sequence_files/t0007-space_at_end.in000066400000000000000000000005601311554223300250570ustar00rootroot000000000000000 space: 1 space: 2 space: 3 space: 70 space: 71 space: 72 space: 73 space: xterm.js-2.7.0/src/test/escape_sequence_files/t0007-space_at_end.text000066400000000000000000000006011311554223300254310ustar00rootroot000000000000000 space: 1 space: 2 space: 3 space: 70 space: 71 space: 72 space: 73 space: xterm.js-2.7.0/src/test/escape_sequence_files/t0008-BS.in000066400000000000000000000006221311554223300227560ustar00rootroot00000000000000abcdefghijklmnopqrstuvwxyz! abc@ # abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop$ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq% abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqr^ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqrs& xterm.js-2.7.0/src/test/escape_sequence_files/t0008-BS.text000066400000000000000000000005711311554223300233370ustar00rootroot00000000000000abcdefghijklmnopqrst!vwxyz @bc # abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghij$lmnop abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghij%lmnopq abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq ^ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq &s xterm.js-2.7.0/src/test/escape_sequence_files/t0009-NEL.in000066400000000000000000000071031311554223300230720ustar00rootroot00000000000000aEabEabcEabcdEabcdeEabcdefEabcdefgEabcdefghEabcdefghiEabcdefghijEabcdefghijkEabcdefghijklEabcdefghijklmEabcdefghijklmnEabcdefghijklmnoEabcdefghijklmnopEabcdefghijklmnopqEabcdefghijklmnopqrEabcdefghijklmnopqrsEabcdefghijklmnopqrstEabcdefghijklmnopqrstuEabcdefghijklmnopqrstuvEabcdefghijklmnopqrstuvwEabcdefghijklmnopqrstuvwxEabcdefghijklmnopqrstuvwxyEabcdefghijklmnopqrstuvwxyzEabcdefghijklmnopqrstuvwxyzAEabcdefghijklmnopqrstuvwxyzABEabcdefghijklmnopqrstuvwxyzABCEabcdefghijklmnopqrstuvwxyzABCDEabcdefghijklmnopqrstuvwxyzABCDEEabcdefghijklmnopqrstuvwxyzABCDEFEabcdefghijklmnopqrstuvwxyzABCDEFGEabcdefghijklmnopqrstuvwxyzABCDEFGHEabcdefghijklmnopqrstuvwxyzABCDEFGHIEabcdefghijklmnopqrstuvwxyzABCDEFGHIJEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQREabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0EabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01EabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012EabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123EabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234EabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345EabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456EabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567EabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678EabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789EabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890EabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890aEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdeEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefgEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghiEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijkEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnoEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqrEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqrsEabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqrst xterm.js-2.7.0/src/test/escape_sequence_files/t0009-NEL.text000066400000000000000000000030261311554223300234500ustar00rootroot00000000000000abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890a abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890ab abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abc abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcd abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcde abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdef abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefg abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefgh abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghi abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghij abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijk abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijkl abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmn abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmno abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq r abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq rs abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq rst xterm.js-2.7.0/src/test/escape_sequence_files/t0010-RI.in000066400000000000000000000001501311554223300227510ustar00rootroot00000000000000a b c dMeMfMg h i j....................................................................kMlMmMn xterm.js-2.7.0/src/test/escape_sequence_files/t0010-RI.text000066400000000000000000000004671311554223300233420ustar00rootroot00000000000000a g n h f m ie l j....................................................................k xterm.js-2.7.0/src/test/escape_sequence_files/t0011-RI_scroll.in000066400000000000000000000003641311554223300243370ustar00rootroot00000000000000And the third. This should be the last line. This one should be lost. This one's a goner, too. MMMMMMMMMMMMMMMMMMMMMMMMThis is second line. MThis should be the first line. xterm.js-2.7.0/src/test/escape_sequence_files/t0011-RI_scroll.text000066400000000000000000000002161311554223300247110ustar00rootroot00000000000000This should be the first line. This is second line. And the third. This should be the last line. This one should be lost. xterm.js-2.7.0/src/test/escape_sequence_files/t0012-VT.in000066400000000000000000000002471311554223300230010ustar00rootroot00000000000000a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t xterm.js-2.7.0/src/test/escape_sequence_files/t0012-VT.text000066400000000000000000000033071311554223300233570ustar00rootroot00000000000000 7 8 9 0 a b c d e f g h i j k l m n o p q r s t xterm.js-2.7.0/src/test/escape_sequence_files/t0013-FF.in000066400000000000000000000002501311554223300227360ustar00rootroot00000000000000a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t xterm.js-2.7.0/src/test/escape_sequence_files/t0013-FF.text000066400000000000000000000032131311554223300233160ustar00rootroot00000000000000 8 9 0 a b c d e f g h i j k l m n o p q r s t xterm.js-2.7.0/src/test/escape_sequence_files/t0014-CAN.in000066400000000000000000000001631311554223300230500ustar00rootroot00000000000000abcdDefgh abcdDefgh abcd!Defgh abcd!*Defgh abcd[Defgh abcd[!Defgh abcd[2Defgh abcd[*2;Defgh xterm.js-2.7.0/src/test/escape_sequence_files/t0014-CAN.text000066400000000000000000000001411311554223300234220ustar00rootroot00000000000000abcdDefgh abcdDefgh abcdDefgh abcdDefgh abcdDefgh abcdDefgh abcdDefgh abcdDefgh xterm.js-2.7.0/src/test/escape_sequence_files/t0015-SUB.in000066400000000000000000000001631311554223300231010ustar00rootroot00000000000000abcdDefgh abcdDefgh abcd!Defgh abcd!*Defgh abcd[Defgh abcd[!Defgh abcd[2Defgh abcd[*2;Defgh xterm.js-2.7.0/src/test/escape_sequence_files/t0015-SUB.text000066400000000000000000000001411311554223300234530ustar00rootroot00000000000000abcdDefgh abcdDefgh abcdDefgh abcdDefgh abcdDefgh abcdDefgh abcdDefgh abcdDefgh xterm.js-2.7.0/src/test/escape_sequence_files/t0016-SU.in000066400000000000000000000015771311554223300230120ustar00rootroot00000000000000HelloGoodbye UpDown x  -----------------------------------------------------------------------------x ------------------------------------------------------------------------------x -------------------------------------------------------------------------------x --------------------------------------------------------------------------------x ---------------------------------------------------------------------------------x .............................................................................x ..............................................................................x ...............................................................................x ................................................................................x .................................................................................x  The End. xterm.js-2.7.0/src/test/escape_sequence_files/t0016-SU.text000066400000000000000000000000411311554223300233510ustar00rootroot00000000000000 The End. xterm.js-2.7.0/src/test/escape_sequence_files/t0017-SD.in000066400000000000000000000020561311554223300227630ustar00rootroot00000000000000A B C D E F G H I J K L M N O P Q R S T U V W X a b c d e f g h ------------------------------------------------------------------------------1 -------------------------------------------------------------------------------2 --------------------------------------------------------------------------------3 ---------------------------------------------------------------------------------4 ..............................................................................5 ...............................................................................6 ................................................................................7 .................................................................................8 xterm.js-2.7.0/src/test/escape_sequence_files/t0017-SD.text000066400000000000000000000011251311554223300233350ustar00rootroot00000000000000 a b f g h 1 2 3 -4------------------------------------------------------------------------------ 5 6 7 8............................................................................... xterm.js-2.7.0/src/test/escape_sequence_files/t0020-CUF.in000066400000000000000000000013501311554223300230600ustar00rootroot00000000000000abcdefghijkl abcdefghijkl abcdefghijkl abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmno@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqr@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm@ x x abcd xterm.js-2.7.0/src/test/escape_sequence_files/t0020-CUF.text000066400000000000000000000015711311554223300234430ustar00rootroot00000000000000abcdefg hijkl abcdefg hijkl abcdefg hijkl abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmno @ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq r @ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm @ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm @ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm @ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm @ x x abcd xterm.js-2.7.0/src/test/escape_sequence_files/t0021-CUB.in000066400000000000000000000006031311554223300230550ustar00rootroot00000000000000abcdefg!@ abcdefg!@ abcdefg!@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmno@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqr@ x xterm.js-2.7.0/src/test/escape_sequence_files/t0021-CUB.text000066400000000000000000000005561311554223300234420ustar00rootroot00000000000000abcdef!@ !@cdefg abcde!@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmn@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmno@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmno@q abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq @ x xterm.js-2.7.0/src/test/escape_sequence_files/t0022-CUU.in000066400000000000000000000002231311554223300230770ustar00rootroot00000000000000a b c defg h i j....................................................................klmn 0123 xterm.js-2.7.0/src/test/escape_sequence_files/t0022-CUU.text000066400000000000000000000005011311554223300234540ustar00rootroot00000000000000a g n h f m ie l j....................................................................k 3 2 1 0 xterm.js-2.7.0/src/test/escape_sequence_files/t0023-CUU_scroll.in000066400000000000000000000003421311554223300244600ustar00rootroot00000000000000This is the first line. This is the second line. And the third. This line should be deleted. Penultimate line. This should be the last line. I have gone up all the way... xterm.js-2.7.0/src/test/escape_sequence_files/t0023-CUU_scroll.text000066400000000000000000000002001311554223300250270ustar00rootroot00000000000000I have gone up all the way... This line should be deleted. Penultimate line. This should be the last line. xterm.js-2.7.0/src/test/escape_sequence_files/t0024-CUD.in000066400000000000000000000002321311554223300230600ustar00rootroot00000000000000a b c d e f g h i j k l m n o p q r s t u v w x012345Bottom line. ABCDE  xterm.js-2.7.0/src/test/escape_sequence_files/t0024-CUD.text000066400000000000000000000007411311554223300234430ustar00rootroot00000000000000b 1 c 2 d 3 e f 4 g h i 5 j k l m n o p q A r B s C t D u E v w x Bottom line. xterm.js-2.7.0/src/test/escape_sequence_files/t0025-CUP.in000066400000000000000000000000751311554223300231020ustar00rootroot00000000000000abcdefg xterm.js-2.7.0/src/test/escape_sequence_files/t0025-CUP.text000066400000000000000000000002071311554223300234550ustar00rootroot00000000000000 b e d g f xterm.js-2.7.0/src/test/escape_sequence_files/t0026-CNL.in000066400000000000000000000001721311554223300230660ustar00rootroot00000000000000abcdefghi -------------------------------------------------------------------------abcdefghijlast line xterm.js-2.7.0/src/test/escape_sequence_files/t0026-CNL.text000066400000000000000000000001731311554223300234450ustar00rootroot00000000000000def ghi -------------------------------------------------------------------------abcdefg hij last line xterm.js-2.7.0/src/test/escape_sequence_files/t0027-CPL.in000066400000000000000000000000571311554223300230730ustar00rootroot00000000000000erasedreplacement line fourline two xterm.js-2.7.0/src/test/escape_sequence_files/t0027-CPL.text000066400000000000000000000000651311554223300234500ustar00rootroot00000000000000replacement line two line four xterm.js-2.7.0/src/test/escape_sequence_files/t0030-HPR.in000066400000000000000000000013501311554223300230750ustar00rootroot00000000000000abcdefghijkl abcdefghijkl abcdefghijkl abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmno@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqr@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm@ x x abcd xterm.js-2.7.0/src/test/escape_sequence_files/t0030-HPR.text000066400000000000000000000015711311554223300234600ustar00rootroot00000000000000abcdefg hijkl abcdefg hijkl abcdefg hijkl abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmno @ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq r @ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm @ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm @ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm @ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklm @ x x abcd xterm.js-2.7.0/src/test/escape_sequence_files/t0031-HPB.in_000066400000000000000000000006031311554223300232150ustar00rootroot00000000000000abcdefg!@ abcdefg!@ abcdefg!@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmno@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopqr@ x xterm.js-2.7.0/src/test/escape_sequence_files/t0031-HPB.text000066400000000000000000000005671311554223300234450ustar00rootroot00000000000000abcdefg!@ abcdefg!@ abcdefg!@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmno@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq @ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq r@ x xterm.js-2.7.0/src/test/escape_sequence_files/t0032-VPB.in000066400000000000000000000002231311554223300230730ustar00rootroot00000000000000a b c defg h i j....................................................................klmn 0123 xterm.js-2.7.0/src/test/escape_sequence_files/t0032-VPB.text000066400000000000000000000001561311554223300234560ustar00rootroot00000000000000b c defg h i j....................................................................klmn 0123 xterm.js-2.7.0/src/test/escape_sequence_files/t0033-VPB_scroll.in000066400000000000000000000003421311554223300244540ustar00rootroot00000000000000This is the first line. This is the second line. And the third. This line should be deleted. Penultimate line. This should be the last line. I have gone up all the way... xterm.js-2.7.0/src/test/escape_sequence_files/t0033-VPB_scroll.text000066400000000000000000000000661311554223300250350ustar00rootroot00000000000000I have gone up all the way... xterm.js-2.7.0/src/test/escape_sequence_files/t0034-VPR.in000066400000000000000000000002321311554223300231150ustar00rootroot00000000000000a b c d e f g h i j k l m n o p q r s t u v w x012345Bottom line. ABCDE  xterm.js-2.7.0/src/test/escape_sequence_files/t0034-VPR.text000066400000000000000000000007411311554223300235000ustar00rootroot00000000000000b 1 c 2 d 3 e f 4 g h i 5 j k l m n o p q A r B s C t D u E v w x Bottom line. xterm.js-2.7.0/src/test/escape_sequence_files/t0035-HVP.in000066400000000000000000000000751311554223300231110ustar00rootroot00000000000000abcdefg xterm.js-2.7.0/src/test/escape_sequence_files/t0035-HVP.text000066400000000000000000000002071311554223300234640ustar00rootroot00000000000000 b e d g f xterm.js-2.7.0/src/test/escape_sequence_files/t0040-REP.in000066400000000000000000000004441311554223300230760ustar00rootroot00000000000000x < abcdefg abcdefg! @ . ?- xterm.js-2.7.0/src/test/escape_sequence_files/t0040-REP.text000066400000000000000000000004601311554223300234520ustar00rootroot00000000000000xxxxxx < abcdefg abcd!fg @@@@@@@@@ @@@@@@@@@@@@ . .... ? ?- xterm.js-2.7.0/src/test/escape_sequence_files/t0050-ICH.in000066400000000000000000000027121311554223300230540ustar00rootroot00000000000000abcdefghijklmnopqrstuvwxyz[15@ abcdefghijklmnopqrstuvwxyz[80@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789[17@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789[18@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789[19@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789[20@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789[21@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop[5@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq[5@ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq[5@ ICH at end:[5@ abcdefghijklmnopqrstuvwxyz[15@!@# abcdefghijklmnopqrstuvwxyz[80@!@# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789[17@!@# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789[18@!@# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789[19@!@# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789[20@!@# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789[21@!@# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop[5@!@# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq[5@!@# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnopq[5@!@# ICH at end:[5@!@# xterm.js-2.7.0/src/test/escape_sequence_files/t0050-ICH.text000066400000000000000000000024761311554223300234410ustar00rootroot00000000000000abcdefghijklmnopqrstu abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567 89 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567 89 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567 8 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW XYZ01234567890abcdefghijkl ICH at end: abcdefghijklmnopqrstu!@# vwxyz abcdefghijklmnopqrstu!@# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567!@# 89 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567!@# 89 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567!@# 8 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567!@# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567!@# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop! @# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghijklmnop! @# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW!@# XYZ01234567890abcdefghijkl ICH at end:!@# xterm.js-2.7.0/src/test/escape_sequence_files/t0051-IL.in000066400000000000000000000003241311554223300227530ustar00rootroot00000000000000ab cd ef gh ij kl mn opQRST 1 2 3 4 5------------------------------------------------------------------------------ab 6 7 8 9 10 11 12 13 14 15 xterm.js-2.7.0/src/test/escape_sequence_files/t0051-IL.text000066400000000000000000000002061311554223300233300ustar00rootroot00000000000000 ef gh ij QR kl mn op 1 2 3 b 4------------------------------------------------------------------------------a 5 6 7 8 9 10 11 12 xterm.js-2.7.0/src/test/escape_sequence_files/t0052-DL.in000066400000000000000000000000731311554223300227500ustar00rootroot00000000000000a b c d e f g hijklmnop 1 2 3 4 x xterm.js-2.7.0/src/test/escape_sequence_files/t0052-DL.text000066400000000000000000000000511311554223300233220ustar00rootroot00000000000000a b c ijklmnop g h 1 x 4 xterm.js-2.7.0/src/test/escape_sequence_files/t0053-DCH.in000066400000000000000000000016411311554223300230520ustar00rootroot00000000000000abcdefghijklmnopqrstuvwxyz> abcdefghijklmnopqrstuvwxyz>! abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh>! abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh>! ------------------------------------------------------------------------------? -------------------------------------------------------------------------------? -------------------------------------------------------------------------------? ---------------------------------------------------------------------------------? .............................................................................. ............................................................................... ............................................................................... ................................................................................. xterm.js-2.7.0/src/test/escape_sequence_files/t0053-DCH.text000066400000000000000000000015231311554223300234270ustar00rootroot00000000000000abcdefghijklmnopqr>vwxyz abcdefghijklmnopqr>!wxyz >!mnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh abcdefghijklmnopqrstuvwxyz0123456789ABC>!PQRSTUVWXYZ0123456789abcdefgh ------------------------------------------------------------------------------? -------------------------------------------------------------------------------? -------------------------------------------------------------------------------? -------------------------------------------------------------------------------- -? .............................................................................. ............................................................................... ............................................................................... ................................................................................ . xterm.js-2.7.0/src/test/escape_sequence_files/t0054-ECH.in000066400000000000000000000016411311554223300230540ustar00rootroot00000000000000abcdefghijklmnopqrstuvwxyz> abcdefghijklmnopqrstuvwxyz>! abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh>! abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh>! ------------------------------------------------------------------------------? -------------------------------------------------------------------------------? -------------------------------------------------------------------------------? ---------------------------------------------------------------------------------? .............................................................................. ............................................................................... ............................................................................... ................................................................................. xterm.js-2.7.0/src/test/escape_sequence_files/t0054-ECH.text000066400000000000000000000015531311554223300234340ustar00rootroot00000000000000abcdefghijklmnopqr> vwxyz abcdefghijklmnopqr>! vwxyz >! lmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh abcdefghijklmnopqrstuvwxyz0123456789ABC>! OPQRSTUVWXYZ0123456789abcdefgh ------------------------------------------------------------------------------? -------------------------------------------------------------------------------? -------------------------------------------------------------------------------? -------------------------------------------------------------------------------- -? .............................................................................. ............................................................................... ............................................................................... ................................................................................ . xterm.js-2.7.0/src/test/escape_sequence_files/t0055-EL.in000066400000000000000000000013411311554223300227530ustar00rootroot00000000000000abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh>< abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh>< abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh>< abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh>< abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh><! abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh><! abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh><! abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh! xterm.js-2.7.0/src/test/escape_sequence_files/t0055-EL.text000066400000000000000000000006531311554223300233360ustar00rootroot00000000000000abcdefghijklmnopqrstuvwxyz0123456789ABC> abcdefghijklmnopqrstuvwxyz0123456789ABC> FGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh abcdefghijklmnopqrstuvwxyz0123456789ABC>! !FGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh ! abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefg! xterm.js-2.7.0/src/test/escape_sequence_files/t0056-ED.in000066400000000000000000000023761311554223300227550ustar00rootroot00000000000000a ab abc abcd abcde abcdef abcdefg abcdefgh abcdefghi abcdefghij abcdefghijk abcdefghijkl abcdefghijklm abcdefghijklmn abcdefghijklmno abcdefghijklmnop abcdefghijklmnopq abcdefghijklmnopqr abcdefghijklmnopqrs abcdefghijklmnopqrst abcdefghijklmnopqrstu abcdefghijklmnopqrstuv abcdefghijklmnopqrstuvw abcdefghijklmnopqrstuvwx abcdefghijklmnopqrstuvwxy abcdefghijklmnopqrstuvwxyz A AB ABC ABCD ABCDE ABCDEF ABCDEFG ABCDEFGH ABCDEFGHI ABCDEFGHIJ ABCDEFGHIJK ABCDEFGHIJKL ABCDEFGHIJKLM ABCDEFGHIJKLMN ABCDEFGHIJKLMNO ABCDEFGHIJKLMNOP ABCDEFGHIJKLMNOPQ ABCDEFGHIJKLMNOPQR ABCDEFGHIJKLMNOPQRS ABCDEFGHIJKLMNOPQRST ABCDEFGHIJKLMNOPQRSTU ABCDEFGHIJKLMNOPQRSTUV ABCDEFGHIJKLMNOPQRSTUVW ABCDEFGHIJKLMNOPQRSTUVWX ABCDEFGHIJKLMNOPQRSTUVWXY!  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaav^ the end xterm.js-2.7.0/src/test/escape_sequence_files/t0056-ED.text000066400000000000000000000005461311554223300233300ustar00rootroot00000000000000 ! aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaav aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^ the end xterm.js-2.7.0/src/test/escape_sequence_files/t0057-ED3.in000066400000000000000000000013531311554223300230330ustar00rootroot00000000000000a ab abc abcd abcde abcdef abcdefg abcdefgh abcdefghi abcdefghij abcdefghijk abcdefghijkl abcdefghijklm abcdefghijklmn abcdefghijklmno abcdefghijklmnop abcdefghijklmnopq abcdefghijklmnopqr abcdefghijklmnopqrs abcdefghijklmnopqrst abcdefghijklmnopqrstu abcdefghijklmnopqrstuv abcdefghijklmnopqrstuvw abcdefghijklmnopqrstuvwx abcdefghijklmnopqrstuvwxy abcdefghijklmnopqrstuvwxyz A AB ABC ABCD ABCDE ABCDEF ABCDEFG ABCDEFGH ABCDEFGHI ABCDEFGHIJ ABCDEFGHIJK ABCDEFGHIJKL ABCDEFGHIJKLM ABCDEFGHIJKLMN ABCDEFGHIJKLMNO ABCDEFGHIJKLMNOP ABCDEFGHIJKLMNOPQ ABCDEFGHIJKLMNOPQR ABCDEFGHIJKLMNOPQRS ABCDEFGHIJKLMNOPQRST ABCDEFGHIJKLMNOPQRSTU ABCDEFGHIJKLMNOPQRSTUV ABCDEFGHIJKLMNOPQRSTUVW ABCDEFGHIJKLMNOPQRSTUVWX ABCDEFGHIJKLMNOPQRSTUVWXY this is the end xterm.js-2.7.0/src/test/escape_sequence_files/t0057-ED3.note000066400000000000000000000005771311554223300234010ustar00rootroot00000000000000Xterm behaves oddly with CSI 3 J. This function is supposed to clear the saved lines in history. Xterm does this, but a small number of lines of history are not cleared. The number seems to vary with how high the window is and how much output has recently been saved. There is no reason to simulate this behavior, so the expected outputs are as if the entire history was erased. xterm.js-2.7.0/src/test/escape_sequence_files/t0057-ED3.text000066400000000000000000000005331311554223300234100ustar00rootroot00000000000000ABCDEF ABCDEFG ABCDEFGH ABCDEFGHI ABCDEFGHIJ ABCDEFGHIJK ABCDEFGHIJKL ABCDEFGHIJKLM ABCDEFGHIJKLMN ABCDEFGHIJKLMNO ABCDEFGHIJKLMNOP ABCDEFGHIJKLMNOPQ ABCDEFGHIJKLMNOPQR ABCDEFGHIJKLMNOPQRS ABCDEFGHIJKLMNOPQRST ABCDEFGHIJKLMNOPQRSTU ABCDEFGHIJKLMNOPQRSTUV ABCDEFGHIJKLMNOPQRSTUVW ABCDEFGHIJKLMNOPQRSTUVWX ABCDEFGHIJKLMNOPQRSTUVWXY this is the end xterm.js-2.7.0/src/test/escape_sequence_files/t0060-DECSC.in000066400000000000000000000002021311554223300232630ustar00rootroot00000000000000 7v 12 38^ v7 ...ooo8^ xterm.js-2.7.0/src/test/escape_sequence_files/t0060-DECSC.text000066400000000000000000000003001311554223300236400ustar00rootroot00000000000000 3 v ... ^ ooo xterm.js-2.7.0/src/test/escape_sequence_files/t0061-CSI_s.in000066400000000000000000000002061311554223300234070ustar00rootroot00000000000000 v 12 3^ v ...ooo^ xterm.js-2.7.0/src/test/escape_sequence_files/t0061-CSI_s.text000066400000000000000000000003001311554223300237600ustar00rootroot00000000000000 3 v ... ^ ooo xterm.js-2.7.0/src/test/escape_sequence_files/t0070-DECSTBM_LF.in000066400000000000000000000001541311554223300241130ustar00rootroot000000000000001 2 3 4 5 6 7 8 9ABCDEFa b c d e f g h i j k l m n o p q r s t uvwxyz  The end. xterm.js-2.7.0/src/test/escape_sequence_files/t0070-DECSTBM_LF.text000066400000000000000000000006241311554223300244730ustar00rootroot000000000000001 2 6 7 8 9 ABC DEF a b c d e f g h i j k l m n o p yz qrstu vwx The end. xterm.js-2.7.0/src/test/escape_sequence_files/t0071-DECSTBM_IND.in000066400000000000000000000002101311554223300242160ustar00rootroot000000000000001D2D3D4D5D6D7D8D9ABCDEFaDbDcDdDeDfDgDhDiDjDkDlDmDnDoDpDqDrDsDtDuvwxyz  The end. xterm.js-2.7.0/src/test/escape_sequence_files/t0071-DECSTBM_IND.text000066400000000000000000000006371311554223300246110ustar00rootroot00000000000000 2 6 7 8 9 ABC DEF a b c d e f g h i j k l m n o p q The end. rstu vwx xterm.js-2.7.0/src/test/escape_sequence_files/t0072-DECSTBM_NEL.in000066400000000000000000000001621311554223300242310ustar00rootroot000000000000001E2E3E4E5E6E7E8E9aEbEcEdEeEfEgEhEiEjEkElEmEnEoEpEqErEsEtEu The end. xterm.js-2.7.0/src/test/escape_sequence_files/t0072-DECSTBM_NEL.text000066400000000000000000000000711311554223300246060ustar00rootroot000000000000002 5 6 7 8 9 a b c d e f g h i j k l m n o p q The end. xterm.js-2.7.0/src/test/escape_sequence_files/t0073-DECSTBM_RI.in000066400000000000000000000005321311554223300241270ustar00rootroot00000000000000TOP 1 TOP 2 TOP 3 TOP 4 TOP 5 TOP 6 - GONE BOTTOM 6 - GONE BOTTOM 5 BOTTOM 4 BOTTOM 3 BOTTOM 2 BOTTOM 1 And the third. This should be the last line. This one should be lost. This one's a goner, too. MMMMMMMMMMMMMMThis is second line. MThis should be the first line. The end. xterm.js-2.7.0/src/test/escape_sequence_files/t0073-DECSTBM_RI.text000066400000000000000000000002721311554223300245060ustar00rootroot00000000000000TOP 2 TOP 3 TOP 4 TOP 5 This should be the first line. This is second line. And the third. This should be the last line. BOTTOM 5 BOTTOM 4 BOTTOM 3 BOTTOM 2 BOTTOM 1 The end. xterm.js-2.7.0/src/test/escape_sequence_files/t0074-DECSTBM_SU_SD.in000066400000000000000000000001151311554223300245300ustar00rootroot00000000000000a b c d e f g h i j k l m n o p q r s t u v w x xterm.js-2.7.0/src/test/escape_sequence_files/t0074-DECSTBM_SU_SD.text000066400000000000000000000004001311554223300251030ustar00rootroot00000000000000a b c d f g h i j k l m n o p q r s w x xterm.js-2.7.0/src/test/escape_sequence_files/t0075-DECSTBM_CUU_CUD.in000066400000000000000000000001211311554223300247400ustar00rootroot00000000000000a b c d e f g h i j k l m n o p q r s t u v w x12 xterm.js-2.7.0/src/test/escape_sequence_files/t0075-DECSTBM_CUU_CUD.text000066400000000000000000000000621311554223300253220ustar00rootroot00000000000000a b c d e f g h i j2 k l m n o p q r 1 t u v w x xterm.js-2.7.0/src/test/escape_sequence_files/t0076-DECSTBM_IL_DL.in000066400000000000000000000011111311554223300244750ustar00rootroot00000000000000 1 (IL on line 2, expect nothing) 2 (DL on line 22, expect nothing) 3 vvvv IL on line 5, expected: A_BC 4 A 5 B 6 C 7 D 8 ^^^^ 9 vvvv DL on line 11, expected: ACD_ 10 A 11 B 12 C 13 D 14 ^^^^ 15 vvvv IL on line 17, expected: A_ 16 A 17 B 18 ^^^^ 19 vvvv IL on line 21, expected: A_ 20 A 21 B 22 ^^^^ 23 vvvv IL on line 24, expected: _A 24 A  25 B 26 ^^^^ 27 vvvv DL on line 28, expected: B_ 28 A 29 B 30 ^^^^ 31 32 xterm.js-2.7.0/src/test/escape_sequence_files/t0076-DECSTBM_IL_DL.text000066400000000000000000000004171311554223300250630ustar00rootroot00000000000000 8 ^^^^ 9 vvvv DL on line 11, expected: ACD_ 10 A 12 C 13 D 14 ^^^^ 15 vvvv IL on line 17, expected: A_ 16 A 18 ^^^^ 19 vvvv IL on line 21, expected: A_ 20 A 22 ^^^^ 23 vvvv IL on line 24, expected: _A 25 B 26 ^^^^ 28 A 29 B 30 ^^^^ 31 32 xterm.js-2.7.0/src/test/escape_sequence_files/t0077-DECSTBM_quirks.in000066400000000000000000000003571311554223300251440ustar00rootroot00000000000000 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24A B C D E F G  Done. xterm.js-2.7.0/src/test/escape_sequence_files/t0077-DECSTBM_quirks.text000066400000000000000000000001511311554223300255120ustar00rootroot00000000000000 3 4 A 5 7 C 8 9 10 11 12 13 14 18 19 20 21 23 24 B D F G Done. xterm.js-2.7.0/src/test/escape_sequence_files/t0080-HT.in000066400000000000000000000010171311554223300227640ustar00rootroot00000000000000a b c d e f g h i j k l x 1 2 3 Tab before EOL: no tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefgh@ tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefgh @ tab (2):abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefg @ Tab at EOL: no tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghi@ tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghi @ with clipping: 4567890abcdefghi MD@ xterm.js-2.7.0/src/test/escape_sequence_files/t0080-HT.text000066400000000000000000000012201311554223300233360ustar00rootroot00000000000000a b c d e f g h i j k l x 1 3 2 Tab before EOL: no tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefgh@ tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefgh@ tab (2):abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefg @ Tab at EOL: no tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghi @ tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghi @ with clipping: 4567890abcdefgh@ xterm.js-2.7.0/src/test/escape_sequence_files/t0081-TBC.in000066400000000000000000000005541311554223300230670ustar00rootroot00000000000000default: > 1 2 3 4 5 6 7 8 9 0 clear non-existant: x x > 1 2 3 4 5 6 7 8 9 0 clear 2 and 4: x x > 1 3 5 6 7 8 9 0 clear 0: x > 1 3 5 6 7 8 9 0 clear after 0: .x > 1 3 5 6 7 8 9 0 clear all: > 0done TBC at end with clipping: ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdeMD! xterm.js-2.7.0/src/test/escape_sequence_files/t0081-TBC.text000066400000000000000000000015161311554223300234440ustar00rootroot00000000000000default: > 1 2 3 4 5 6 7 8 9 0 clear non-existant: x x > 1 2 3 4 5 6 7 8 9 0 clear 2 and 4: x x > 1 3 5 6 7 8 9 0 clear 0: x > 1 3 5 6 7 8 9 0 clear after 0: . x > 1 3 5 6 7 8 9 0 clear all: > 0 done TBC at end with clipping: ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcd! xterm.js-2.7.0/src/test/escape_sequence_files/t0082-HTS.in000066400000000000000000000004001311554223300231040ustar00rootroot00000000000000 1 2 3 4 abcdeHFghijklmnopqrstuvHWxyz H 1 2 W 3 4 HTS at end: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdeHfgh H 1 2 W 3 4 5 6 7 8 9 a b HTS at end with clipping: ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdeHMD! xterm.js-2.7.0/src/test/escape_sequence_files/t0082-HTS.text000066400000000000000000000005511311554223300234710ustar00rootroot00000000000000 1 2 3 4 abcdeFghijklmnopqrstuvWxyz H 1 2 W 3 4 HTS at end: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcde fgh H 1 2 W 3 4 5 6 7 8 9 a b HTS at end with clipping: ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcd! xterm.js-2.7.0/src/test/escape_sequence_files/t0083-CHT.in000066400000000000000000000011301311554223300230660ustar00rootroot00000000000000abcdefghijkl x 12 3 CHT before EOL: no tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefgh@ tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefgh@ tab (2):abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefg@ CHT at EOL: no tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghi@ tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghi@ with clipping: 4567890abcdefghiMD@ aeg e h x xterm.js-2.7.0/src/test/escape_sequence_files/t0083-CHT.text000066400000000000000000000015121311554223300234500ustar00rootroot00000000000000a b c d e f g h i j k l x 1 3 2 CHT before EOL: no tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefgh@ tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefgh@ tab (2):abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefg @ CHT at EOL: no tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghi @ tab: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890abcdefghi @ with clipping: 4567890abcdefgh@ a e g e h x xterm.js-2.7.0/src/test/escape_sequence_files/t0084-CBT.in000066400000000000000000000010661311554223300230710ustar00rootroot00000000000000a b c d e f g h i j k <Iihfa a default tab stops: near end: abcdefg! at end: abcdefgh! at end (2): abcdefgh! at end with clipping: abcdefghMD! at end with clipping (2): abcdefghMD! set tab stop at column 80: Hv at end: abcdefgh! at end (2): abcdefgh! at end with clipping: abcdefghMD! at end with clipping (2): abcdefghMD! xterm.js-2.7.0/src/test/escape_sequence_files/t0084-CBT.text000066400000000000000000000017441311554223300234520ustar00rootroot00000000000000a b c d e f g h i j k a f h i < a default tab stops: near end: !bcdefg at end: abcdefgh ! at end (2): abcdefgh ! at end with clipping: !bcdefgh at end with clipping (2): ! abcdefgh set tab stop at column 80: v at end: abcdefgh ! at end (2): abcdefgh ! at end with clipping: !bcdefgh at end with clipping (2): ! abcdefgh xterm.js-2.7.0/src/test/escape_sequence_files/t0084-CBT.text-xterm000066400000000000000000000017371311554223300246110ustar00rootroot00000000000000a b c d e f g h i j k a f h i < a default tab stops: near end: !bcdefg at end: abcdefgh ! at end (2): abcdefgh ! at end with clipping: !bcdefgh at end with clipping (2): ! abcdefgh set tab stop at column 80: v at end: abcdefgh ! at end (2): abcdefgh ! at end with clipping: !bcdefgh at end with clipping (2): ! abcdefgh xterm.js-2.7.0/src/test/escape_sequence_files/t0090-alt_screen.in000066400000000000000000000005121311554223300245700ustar00rootroot00000000000000a[?47h b c d e f g h i j k l m n o p q r s t u v w x y[?47lz A[?47h B C D E F G H I J K L M N O P Q R S T U V W X Y[?47lZ --->[?47hhello[?47l<-- --->[?47h[?47l<--- fin xterm.js-2.7.0/src/test/escape_sequence_files/t0090-alt_screen.text000066400000000000000000000003041311554223300251450ustar00rootroot00000000000000 z AZ <-- ---> ---> <--- fin xterm.js-2.7.0/src/test/escape_sequence_files/t0091-alt_screen_ED3.in000066400000000000000000000001731311554223300252270ustar00rootroot00000000000000a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 10 [?47h one two three four five six  [?47l 11 xterm.js-2.7.0/src/test/escape_sequence_files/t0091-alt_screen_ED3.text000066400000000000000000000012261311554223300256050ustar00rootroot00000000000000 n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 10 11 xterm.js-2.7.0/src/test/escape_sequence_files/t0092-alt_screen_DECSC.in000066400000000000000000000001161311554223300254730ustar00rootroot00000000000000a b7 c[?47h >7 xxxxxxx8[?47l!8< The end. xterm.js-2.7.0/src/test/escape_sequence_files/t0092-alt_screen_DECSC.text000066400000000000000000000000651311554223300260540ustar00rootroot00000000000000a b< c ! The end. xterm.js-2.7.0/src/test/escape_sequence_files/t0100-IRM.in000066400000000000000000000006731311554223300231000ustar00rootroot00000000000000-------- insert single '!' --------------------------------------------abcdefghi jklmnop! -------- insert 0-9, with wraparound ----------------------------------abcdefghi jklmnop0123456789 -------- repeat 3 '!' -------------------------------------------------abcdefghi jklmnop! -------- repeat 10 '!', with wraparound -------------------------------abcdefghi jklmnop! xterm.js-2.7.0/src/test/escape_sequence_files/t0100-IRM.text000066400000000000000000000005751311554223300234570ustar00rootroot00000000000000-------- insert single '!' --------------------------------------------abc!defgh jklmnop -------- insert 0-9, with wraparound ----------------------------------abc012345 6789jklmnop -------- repeat 3 '!' -------------------------------------------------abc!!!def jklmnop -------- repeat 10 '!', with wraparound -------------------------------abc!!!!!! !!!!jklmnop xterm.js-2.7.0/src/test/escape_sequence_files/t0101-NLM.in000066400000000000000000000000531311554223300230700ustar00rootroot00000000000000a b c d e f g h i j k l m n o p xterm.js-2.7.0/src/test/escape_sequence_files/t0101-NLM.text000066400000000000000000000000521311554223300234450ustar00rootroot00000000000000a b c d e f g h k l m n o p xterm.js-2.7.0/src/test/escape_sequence_files/t0102-DECAWM.in000066400000000000000000000005021311554223300234020ustar00rootroot00000000000000-------- default: wraparound ----------------------------------------------abcdefgh[?7h -------- set: wraparound ----------------------------------------------abcdefgh[?7l -------- unset: no wraparound -------------------------------------------abcdefgh this should be immediately below "no wraparound"[?7h xterm.js-2.7.0/src/test/escape_sequence_files/t0102-DECAWM.text000066400000000000000000000005041311554223300237620ustar00rootroot00000000000000-------- default: wraparound ----------------------------------------------abcd efgh -------- set: wraparound ----------------------------------------------abcd efgh -------- unset: no wraparound -------------------------------------------abcd this should be immediately below "no wraparound" xterm.js-2.7.0/src/test/escape_sequence_files/t0103-reverse_wrap.in000066400000000000000000000000721311554223300251510ustar00rootroot00000000000000[?45ha bA c-B dC!the endreally![?45l xterm.js-2.7.0/src/test/escape_sequence_files/t0103-reverse_wrap.text000066400000000000000000000003011311554223300255220ustar00rootroot00000000000000c C ! the end really! xterm.js-2.7.0/src/test/escape_sequence_files/t0200-SGR.html000066400000000000000000000015741311554223300234440ustar00rootroot00000000000000
Implemented non-color attributes:

 1: This is bold.

 3: This is italic.

 4: This is underlined.

 5: This is slowly blinking.

 6: This is rapidly blinking.

 7: This is inverse.

 8: This is hidden.

 9: This is struck out.

21: This is double underlined.

53: This is overlined.



Unimplemented non-color attributes:

 2: weight:feint

20: style:fraktur

51: frame:box

52: frame:circle
xterm.js-2.7.0/src/test/escape_sequence_files/t0200-SGR.in_000066400000000000000000000007211311554223300232360ustar00rootroot00000000000000Implemented non-color attributes: 1: This is bold. 3: This is italic. 4: This is underlined. 5: This is slowly blinking. 6: This is rapidly blinking. 7: This is inverse. 8: This is hidden. 9: This is struck out. 21: This is double underlined. 53: This is overlined. Unimplemented non-color attributes: 2: weight:feint 20: style:fraktur 51: frame:box 52: frame:circle xterm.js-2.7.0/src/test/escape_sequence_files/t0220-SGR_inverse.html000066400000000000000000000013431311554223300251730ustar00rootroot00000000000000
This is inverse text with default fg and bg.
This is inverse text with red fg and default bg.
This is inverse text with default fg and red bg.
This is inverse text with green fg and red bg.
xterm.js-2.7.0/src/test/escape_sequence_files/t0220-SGR_inverse.in_000066400000000000000000000003751311554223300250000ustar00rootroot00000000000000This is inverse text with default fg and bg. This is inverse text with red fg and default bg. This is inverse text with default fg and red bg. This is inverse text with green fg and red bg. xterm.js-2.7.0/src/test/escape_sequence_files/t0500-bash_long_line.in000066400000000000000000000007541311554223300254200ustar00rootroot00000000000000Script started on Fri 27 Mar 2009 08:53:29 PM EDT dircolors: /etc/DIR_COLORS: No such file or directory ]0;mark@mark-desktop:~/vt100-to-htmlmark@mark-desktop:~/vt100-to-html$ bcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST UVWXYZ1234567890abcdefghijklmnopqrstuvcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuv ]0;mark@mark-desktop:~/vt100-to-htmlmark@mark-desktop:~/vt100-to-html$ exit Script done on Fri 27 Mar 2009 08:53:33 PM EDT xterm.js-2.7.0/src/test/escape_sequence_files/t0500-bash_long_line.text000066400000000000000000000005111311554223300257650ustar00rootroot00000000000000Script started on Fri 27 Mar 2009 08:53:29 PM EDT dircolors: /etc/DIR_COLORS: No such file or directory mark@mark-desktop:~/vt100-to-html$ cdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU VWXYZ1234567890abcdefghijklmnopqrstuv mark@mark-desktop:~/vt100-to-html$ exit Script done on Fri 27 Mar 2009 08:53:33 PM EDT xterm.js-2.7.0/src/test/escape_sequence_files/t0501-bash_ls.in000066400000000000000000000012431311554223300240630ustar00rootroot00000000000000Script started on Sun 17 May 2009 06:20:41 PM EDT dircolors: /etc/DIR_COLORS: No such file or directory ]0;mark@mark-desktop:~/vt100-to-html/scriptsmark@mark-desktop:~/vt100-to-html/scripts$ ls bash.script ]0;mark@mark-desktop:~/vt100-to-html/scriptsmark@mark-desktop:~/vt100-to-html/scripts$ ls / bin dev initrd.img lib64 opt selinux usr boot etc initrd.img.old lost+found proc srv var boot2 home lib media root sys vmlinuz cdrom initrd lib32 mnt sbin tmp vmlinuz.old ]0;mark@mark-desktop:~/vt100-to-html/scriptsmark@mark-desktop:~/vt100-to-html/scripts$ exit Script done on Sun 17 May 2009 06:20:52 PM EDT xterm.js-2.7.0/src/test/escape_sequence_files/t0501-bash_ls.text000066400000000000000000000011031311554223300244340ustar00rootroot00000000000000Script started on Sun 17 May 2009 06:20:41 PM EDT dircolors: /etc/DIR_COLORS: No such file or directory mark@mark-desktop:~/vt100-to-html/scripts$ ls bash.script mark@mark-desktop:~/vt100-to-html/scripts$ ls / bin dev initrd.img lib64 opt selinux usr boot etc initrd.img.old lost+found proc srv var boot2 home lib media root sys vmlinuz cdrom initrd lib32 mnt sbin tmp vmlinuz.old mark@mark-desktop:~/vt100-to-html/scripts$ exit Script done on Sun 17 May 2009 06:20:52 PM EDT xterm.js-2.7.0/src/test/escape_sequence_files/t0502-bash_ls_color.in000066400000000000000000000017311311554223300252640ustar00rootroot00000000000000Script started on Sun 17 May 2009 06:21:05 PM EDT dircolors: /etc/DIR_COLORS: No such file or directory ]0;mark@mark-desktop:~/vt100-to-html/scriptsmark@mark-desktop:~/vt100-to-html/scripts$ ls --color=auto / bin dev initrd.img lib64 opt selinux usr boot etc initrd.img.old lost+found proc srv var boot2 home lib media root sys vmlinuz cdrom initrd lib32 mnt sbin tmp vmlinuz.old ]0;mark@mark-desktop:~/vt100-to-html/scriptsmark@mark-desktop:~/vt100-to-html/scripts$ exit Script done on Sun 17 May 2009 06:21:11 PM EDT xterm.js-2.7.0/src/test/escape_sequence_files/t0502-bash_ls_color.text000066400000000000000000000010301311554223300256320ustar00rootroot00000000000000Script started on Sun 17 May 2009 06:21:05 PM EDT dircolors: /etc/DIR_COLORS: No such file or directory mark@mark-desktop:~/vt100-to-html/scripts$ ls --color=auto / bin dev initrd.img lib64 opt selinux usr boot etc initrd.img.old lost+found proc srv var boot2 home lib media root sys vmlinuz cdrom initrd lib32 mnt sbin tmp vmlinuz.old mark@mark-desktop:~/vt100-to-html/scripts$ exit Script done on Sun 17 May 2009 06:21:11 PM EDT xterm.js-2.7.0/src/test/escape_sequence_files/t0503-zsh_ls_color.in000066400000000000000000000023001311554223300251450ustar00rootroot00000000000000Script started on Sun 17 May 2009 06:21:21 PM EDT ]2;mark-desktop - ~/vt100-to-html/scripts% $ ~/vt100-to-html/scriptslls / ]2;mark-desktop - ls /bin dev initrd.img lib64 opt selinux usr boot etc initrd.img.old lost+found proc srv var boot2 home lib media root sys vmlinuz cdrom initrd lib32 mnt sbin tmp vmlinuz.old ]2;mark-desktop - ~/vt100-to-html/scripts% $ ~/vt100-to-html/scripts Script done on Sun 17 May 2009 06:21:27 PM EDT xterm.js-2.7.0/src/test/escape_sequence_files/t0503-zsh_ls_color.text000066400000000000000000000010261311554223300255270ustar00rootroot00000000000000Script started on Sun 17 May 2009 06:21:21 PM EDT $ ls / ~/vt100-to-html/scripts bin dev initrd.img lib64 opt selinux usr boot etc initrd.img.old lost+found proc srv var boot2 home lib media root sys vmlinuz cdrom initrd lib32 mnt sbin tmp vmlinuz.old $ ~/vt100-to-html/scripts Script done on Sun 17 May 2009 06:21:27 PM EDT xterm.js-2.7.0/src/test/escape_sequence_files/t0504-vim.in000066400000000000000000000336471311554223300232630ustar00rootroot00000000000000Script started on Sun 15 Aug 2010 11:53:27 PM EDT ]0;mark-desktop - ~/vt100-to-html/test% $ ~/vt100-to-html/testlls ]0;mark-desktop - lsexpected_text t0016-SU.text t0050-ICH.text input t0017-SD.in t0051-IL.in run_all.py t0017-SD.text t0051-IL.text t0001-all_printable.in t0020-CUF.in t0052-DL.in t0001-all_printable.text t0020-CUF.text t0052-DL.text t0002-history.in t0021-CUB.in t0053-DCH.in t0002-history.text t0021-CUB.text t0053-DCH.text t0003-line_wrap.in t0022-CUU.in t0054-ECH.in t0003-line_wrap.text t0022-CUU.text t0054-ECH.text t0004-LF.in t0023-CUU_scroll.in t0055-EL.in t0004-LF.text t0023-CUU_scroll.text t0055-EL.text t0005-CR.in t0024-CUD.in t0056-ED.in t0005-CR.text t0024-CUD.text t0056-ED.text t0006-IND.in t0025-CUP.in t0057-ED3.in t0006-IND.text t0025-CUP.text t0057-ED3.note t0007-space_at_end.in t0026-CNL.in t0057-ED3.text t0007-space_at_end.text t0026-CNL.text t0060-DECSC.in t0008-BS.in t0027-CPL.in t0060-DECSC.text t0008-BS.text t0027-CPL.text t0061-CSI_s.in t0009-NEL.in t0030-HPR.in t0061-CSI_s.text t0009-NEL.text t0030-HPR.text t008x-alt_screen_ED.in t0010-RI.in t0031-HPB.in t008x-IRM.in t0010-RI.text t0031-HPB.text t008x-NLM.in t0011-RI_scroll.in t0032-VPB.in t008x-save_cursor_mode.in t0011-RI_scroll.text t0032-VPB.text t0500-bash_long_line.in t0012-VT.in t0033-VPB_scroll.in t0500-bash_long_line.text t0012-VT.text t0033-VPB_scroll.text t0501-bash_ls.in t0013-FF.in t0034-VPR.in t0501-bash_ls.text t0013-FF.text t0034-VPR.text t0502-bash_ls_color.in t0014-CAN.in t0035-HVP.in t0502-bash_ls_color.text t0014-CAN.text t0035-HVP.text t0503-zsh_ls_color.in t0015-SUB.in t0040-REP.in t0503-zsh_ls_color.text t0015-SUB.text t0040-REP.text typescript t0016-SU.in t0050-ICH.in ]0;mark-desktop - ~/vt100-to-html/test% $ ~/vt100-to-html/testvvim ]0;mark-desktop - vim[?1000h[?1049h[?1h=[?12;25h[?12l[?25h[>c[?25l~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ [No Name] 0,0-1 AllVIM - Vi IMprovedversion 7.2.267by Bram Moolenaar et al.Vim is open source and freely distributableBecome a registered Vim user!type :help register for information type :q to exit type :help or  for on-line helptype :help version7 for version info]2;[No Name] - VIM]1;[No Name][?12l[?25h[?1000l[?1002hP+q436f\P+q6b75\P+q6b64\P+q6b72\P+q6b6c\P+q2332\P+q2334\P+q2569\P+q2a37\P+q6b31\[?25l-- INSERT --1 [?12l[?25h[?25lT         [+]1,2 ]2;[No Name] + - VIM]1;[No Name][?12l[?25h[?25lTh3 [?12l[?25h[?25lhi4 [?12l[?25h[?25lis5 [?12l[?25h[?25l6 [?12l[?25h[?25l i7 [?12l[?25h[?25lis8 [?12l[?25h[?25l9 [?12l[?25h[?25l a10[?12l[?25h[?25l1 [?12l[?25h[?25l t2 [?12l[?25h[?25lte3 [?12l[?25h[?25les4 [?12l[?25h[?25lst5 [?12l[?25h[?25lt.6 [?12l[?25h[?25l2,1 [?12l[?25h[?25l3,[?12l[?25h[?25lH2 [?12l[?25h[?25lHo3 [?12l[?25h[?25loe4 [?12l[?25h[?25l5 [?12l[?25h[?25l f6 [?12l[?25h[?25lfu7 [?12l[?25h[?25l6 [?12l[?25h[?25l5 [?12l[?25h[?25l4 [?12l[?25h[?25l3 [?12l[?25h[?25lop4 [?12l[?25h[?25lpe5 [?12l[?25h[?25lef6 [?12l[?25h[?25lfu7 [?12l[?25h[?25lul8 [?12l[?25h[?25lll9 [?12l[?25h[?25lly10[?12l[?25h[?25l1 [?12l[?25h[?25l i2 [?12l[?25h[?25lit3 [?12l[?25h[?25l4 [?12l[?25h[?25l w5 [?12l[?25h[?25lwi6 [?12l[?25h[?25lil7 [?12l[?25h[?25lll8 [?12l[?25h[?25l9 [?12l[?25h[?25l w20 [?12l[?25h[?25lwo1 [?12l[?25h[?25lor2 [?12l[?25h[?25lrk3 [?12l[?25h[?25lk.4 [?12l[?25h[?25l4,1 [?12l[?25h[?25l5,[?12l[?25h[?25l6,[?12l[?25h[?25l7,[?12l[?25h[?25l8,[?12l[?25h[?25l9,[?12l[?25h[?25l10,1[?12l[?25h[?25l1,[?12l[?25h[?25l2,[?12l[?25h[?25l3,[?12l[?25h[?25l4,[?12l[?25h[?25l5,[?12l[?25h[?25l6,[?12l[?25h[?25l7,[?12l[?25h[?25l8,[?12l[?25h[?25l9,[?12l[?25h[?25l20,[?12l[?25h[?25l1,[?12l[?25h[?25l2,[?12l[?25h[?25l 3,Bot[?12l[?25h[?25l 4,[?12l[?25h[?25l 5,[?12l[?25h[?25l 6,[?12l[?25h[?25l 7,[?12l[?25h[?25l 8,[?12l[?25h[?25l 9,[?12l[?25h[?25l 30,[?12l[?25h[?25l 1,[?12l[?25h[?25l 2,[?12l[?25h[?25l 3,[?12l[?25h[?25lI2 [?12l[?25h[?25l3 [?12l[?25h[?25l b4 [?12l[?25h[?25lbe5 [?12l[?25h[?25let6 [?12l[?25h[?25l7 [?12l[?25h[?25l i8 [?12l[?25h[?25lit9 [?12l[?25h[?25l10[?12l[?25h[?25l w1 [?12l[?25h[?25lwi2 [?12l[?25h[?25lil3 [?12l[?25h[?25lll4 [?12l[?25h[?25ll.5 [?12l[?25h[?25l4 [?12l[?25h[?25lThis is a test. Hopefully it will work.1,1 Top[?12l[?25h[?25lI bet it will. ~ ~ ~ ~ ~ ~ ~ ~ ~ [No Name] [+] 21,0-1 Bot[?12l[?25h[?25l0,[?12l[?25h[?25l19,[?12l[?25h[?25l8,[?12l[?25h[?25l7,[?12l[?25h[?25l6,[?12l[?25h[?25l5,[?12l[?25h[?25l:[?12l[?25hw[?25l[?12l[?25hq[?25l[?12l[?25h [?25lE32: No file name[?12l[?25h[?25l:[?12l[?25hw[?25l[?12l[?25h[?25l [?12l[?25hf[?25l[?12l[?25ho[?25l[?12l[?25ho[?25l[?12l[?25h [?25l"foo" [New] 33L, 85C writtenfoo ]2;foo (~/vt100-to-html/test) - VIM]1;foo[?12l[?25h[?25l:[?12l[?25hq[?25l[?12l[?25h [?25l[?1002l]2;mark-desktop - vim]1;mark-desktop - vim[?1l>[?12l[?25h[?1049l]0;mark-desktop - ~/vt100-to-html/test% $ ~/vt100-to-html/testeecho Yes! ]0;mark-desktop - echo Yes!Yes! ]0;mark-desktop - ~/vt100-to-html/test% $ ~/vt100-to-html/test Script done on Sun 15 Aug 2010 11:54:14 PM EDT xterm.js-2.7.0/src/test/escape_sequence_files/t0504-vim.text000066400000000000000000000032141311554223300236240ustar00rootroot00000000000000t0005-CR.in t0024-CUD.in t0056-ED.in t0005-CR.text t0024-CUD.text t0056-ED.text t0006-IND.in t0025-CUP.in t0057-ED3.in t0006-IND.text t0025-CUP.text t0057-ED3.note t0007-space_at_end.in t0026-CNL.in t0057-ED3.text t0007-space_at_end.text t0026-CNL.text t0060-DECSC.in t0008-BS.in t0027-CPL.in t0060-DECSC.text t0008-BS.text t0027-CPL.text t0061-CSI_s.in t0009-NEL.in t0030-HPR.in t0061-CSI_s.text t0009-NEL.text t0030-HPR.text t008x-alt_screen_ED.in t0010-RI.in t0031-HPB.in t008x-IRM.in t0010-RI.text t0031-HPB.text t008x-NLM.in t0011-RI_scroll.in t0032-VPB.in t008x-save_cursor_mode.in t0011-RI_scroll.text t0032-VPB.text t0500-bash_long_line.in t0012-VT.in t0033-VPB_scroll.in t0500-bash_long_line.text t0012-VT.text t0033-VPB_scroll.text t0501-bash_ls.in t0013-FF.in t0034-VPR.in t0501-bash_ls.text t0013-FF.text t0034-VPR.text t0502-bash_ls_color.in t0014-CAN.in t0035-HVP.in t0502-bash_ls_color.text t0014-CAN.text t0035-HVP.text t0503-zsh_ls_color.in t0015-SUB.in t0040-REP.in t0503-zsh_ls_color.text t0015-SUB.text t0040-REP.text typescript t0016-SU.in t0050-ICH.in $ vim ~/vt100-to-html/test Script done on Sun 15 Aug 2010 11:54:14 PM EDT ~/vt100-to-html/test xterm.js-2.7.0/src/test/test.js000066400000000000000000001030101311554223300163470ustar00rootroot00000000000000var assert = require('chai').assert; var expect = require('chai').expect; var Terminal = require('../xterm'); describe('xterm.js', function() { var xterm; beforeEach(function () { xterm = new Terminal(); xterm.refresh = function(){}; xterm.viewport = { syncScrollArea: function(){} }; xterm.compositionHelper = { keydown: function(){ return true; } }; // Force synchronous writes xterm.write = function(data) { xterm.writeBuffer.push(data); xterm.innerWrite(); }; xterm.element = { classList: { toggle: function(){}, remove: function(){} } }; }); describe('getOption', function() { it('should retrieve the option correctly', function() { // In the `options` namespace. xterm.options.cursorBlink = true; assert.equal(xterm.getOption('cursorBlink'), true); // On the Terminal instance delete xterm.options.cursorBlink; xterm.cursorBlink = false; assert.equal(xterm.getOption('cursorBlink'), false); }); it('should throw when retrieving a non-existant option', function() { assert.throws(xterm.getOption.bind(xterm, 'fake', true)); }); }); describe('setOption', function() { it('should set the option correctly', function() { xterm.setOption('cursorBlink', true); assert.equal(xterm.cursorBlink, true); assert.equal(xterm.options.cursorBlink, true); xterm.setOption('cursorBlink', false); assert.equal(xterm.cursorBlink, false); assert.equal(xterm.options.cursorBlink, false); }); it('should throw when setting a non-existant option', function() { assert.throws(xterm.setOption.bind(xterm, 'fake', true)); }); }); describe('clear', function() { it('should clear a buffer equal to rows', function() { var promptLine = xterm.lines.get(xterm.ybase + xterm.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); for (var i = 1; i < xterm.rows; i++) { assert.deepEqual(xterm.lines.get(i), xterm.blankLine()); } }); it('should clear a buffer larger than rows', function() { // Fill the buffer with dummy rows for (var i = 0; i < xterm.rows * 2; i++) { xterm.write('test\n'); } var promptLine = xterm.lines.get(xterm.ybase + xterm.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); for (var i = 1; i < xterm.rows; i++) { assert.deepEqual(xterm.lines.get(i), xterm.blankLine()); } }); it('should not break the prompt when cleared twice', function() { var promptLine = xterm.lines.get(xterm.ybase + xterm.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); for (var i = 1; i < xterm.rows; i++) { assert.deepEqual(xterm.lines.get(i), xterm.blankLine()); } }); }); describe('scroll', function() { describe('scrollDisp', function() { var startYDisp; beforeEach(function() { for (var i = 0; i < xterm.rows * 2; i++) { xterm.writeln('test'); } startYDisp = xterm.rows + 1; }); it('should scroll a single line', function() { assert.equal(xterm.ydisp, startYDisp); xterm.scrollDisp(-1); assert.equal(xterm.ydisp, startYDisp - 1); xterm.scrollDisp(1); assert.equal(xterm.ydisp, startYDisp); }); it('should scroll multiple lines', function() { assert.equal(xterm.ydisp, startYDisp); xterm.scrollDisp(-5); assert.equal(xterm.ydisp, startYDisp - 5); xterm.scrollDisp(5); assert.equal(xterm.ydisp, startYDisp); }); it('should not scroll beyond the bounds of the buffer', function() { assert.equal(xterm.ydisp, startYDisp); xterm.scrollDisp(1); assert.equal(xterm.ydisp, startYDisp); for (var i = 0; i < startYDisp; i++) { xterm.scrollDisp(-1); } assert.equal(xterm.ydisp, 0); xterm.scrollDisp(-1); assert.equal(xterm.ydisp, 0); }); }); describe('scrollPages', function() { var startYDisp; beforeEach(function() { for (var i = 0; i < xterm.rows * 3; i++) { xterm.writeln('test'); } startYDisp = (xterm.rows * 2) + 1; }); it('should scroll a single page', function() { assert.equal(xterm.ydisp, startYDisp); xterm.scrollPages(-1); assert.equal(xterm.ydisp, startYDisp - (xterm.rows - 1)); xterm.scrollPages(1); assert.equal(xterm.ydisp, startYDisp); }); it('should scroll a multiple pages', function() { assert.equal(xterm.ydisp, startYDisp); xterm.scrollPages(-2); assert.equal(xterm.ydisp, startYDisp - (xterm.rows - 1) * 2); xterm.scrollPages(2); assert.equal(xterm.ydisp, startYDisp); }); }); describe('scrollToTop', function() { beforeEach(function() { for (var i = 0; i < xterm.rows * 3; i++) { xterm.writeln('test'); } }); it('should scroll to the top', function() { assert.notEqual(xterm.ydisp, 0); xterm.scrollToTop(); assert.equal(xterm.ydisp, 0); }); }); describe('scrollToBottom', function() { var startYDisp; beforeEach(function() { for (var i = 0; i < xterm.rows * 3; i++) { xterm.writeln('test'); } startYDisp = (xterm.rows * 2) + 1; }); it('should scroll to the bottom', function() { xterm.scrollDisp(-1); xterm.scrollToBottom(); assert.equal(xterm.ydisp, startYDisp); xterm.scrollPages(-1); xterm.scrollToBottom(); assert.equal(xterm.ydisp, startYDisp); xterm.scrollToTop(); xterm.scrollToBottom(); assert.equal(xterm.ydisp, startYDisp); }); }); describe('keyDown', function () { it('should scroll down, when a key is pressed and terminal is scrolled up', function () { // Override evaluateKeyEscapeSequence to return cancel code xterm.evaluateKeyEscapeSequence = function() { return { key: 'a' }; }; var event = { type: 'keydown', keyCode: 0, preventDefault: function(){}, stopPropagation: function(){} }; xterm.ydisp = 0; xterm.ybase = 40; assert.notEqual(xterm.ydisp, xterm.ybase); xterm.keyDown(event); // Ensure that now the terminal is scrolled to bottom assert.equal(xterm.ydisp, xterm.ybase); }); it('should not scroll down, when a custom keydown handler prevents the event', function () { // Add some output to the terminal for (var i = 0; i < xterm.rows * 3; i++) { xterm.writeln('test'); } var startYDisp = (xterm.rows * 2) + 1; xterm.attachCustomKeydownHandler(function () { return false; }); assert.equal(xterm.ydisp, startYDisp); xterm.scrollDisp(-1); assert.equal(xterm.ydisp, startYDisp - 1); xterm.keyDown({ keyCode: 0 }); assert.equal(xterm.ydisp, startYDisp - 1); }); }); }); describe('evaluateKeyEscapeSequence', function() { it('should return the correct escape sequence for unmodified keys', function() { // Backspace assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 8 }).key, '\x7f'); // ^? // Tab assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 9 }).key, '\t'); // Return/enter assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 13 }).key, '\r'); // CR // Escape assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 27 }).key, '\x1b'); // Page up, page down assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 33 }).key, '\x1b[5~'); // CSI 5 ~ assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 34 }).key, '\x1b[6~'); // CSI 6 ~ // End, Home assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 35 }).key, '\x1b[F'); // SS3 F assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 36 }).key, '\x1b[H'); // SS3 H // Left, up, right, down arrows assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 37 }).key, '\x1b[D'); // CSI D assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 38 }).key, '\x1b[A'); // CSI A assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 39 }).key, '\x1b[C'); // CSI C assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 40 }).key, '\x1b[B'); // CSI B // Insert assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 45 }).key, '\x1b[2~'); // CSI 2 ~ // Delete assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 46 }).key, '\x1b[3~'); // CSI 3 ~ // F1-F12 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 112 }).key, '\x1bOP'); // SS3 P assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 113 }).key, '\x1bOQ'); // SS3 Q assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 114 }).key, '\x1bOR'); // SS3 R assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 115 }).key, '\x1bOS'); // SS3 S assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 116 }).key, '\x1b[15~'); // CSI 1 5 ~ assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 117 }).key, '\x1b[17~'); // CSI 1 7 ~ assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 118 }).key, '\x1b[18~'); // CSI 1 8 ~ assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 119 }).key, '\x1b[19~'); // CSI 1 9 ~ assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 120 }).key, '\x1b[20~'); // CSI 2 0 ~ assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 121 }).key, '\x1b[21~'); // CSI 2 1 ~ assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 122 }).key, '\x1b[23~'); // CSI 2 3 ~ assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 123 }).key, '\x1b[24~'); // CSI 2 4 ~ }); it('should return \\x1b[3;5~ for ctrl+delete', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 46 }).key, '\x1b[3;5~'); }); it('should return \\x1b[3;2~ for shift+delete', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 46 }).key, '\x1b[3;2~'); }); it('should return \\x1b[3;3~ for alt+delete', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 46 }).key, '\x1b[3;3~'); }); it('should return \\x1b[5D for ctrl+left', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D }); it('should return \\x1b[5C for ctrl+right', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C }); it('should return \\x1b[5A for ctrl+up', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A }); it('should return \\x1b[5B for ctrl+down', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 40 }).key, '\x1b[1;5B'); // CSI 5 B }); describe('On non-macOS platforms', function() { beforeEach(function() { xterm.browser.isMac = false; }); // Evalueate alt + arrow key movement, which is a feature of terminal emulators but not VT100 // http://unix.stackexchange.com/a/108106 it('should return \\x1b[5D for alt+left', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D }); it('should return \\x1b[5C for alt+right', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C }); }); describe('On macOS platforms', function() { beforeEach(function() { xterm.browser.isMac = true; }); it('should return \\x1bb for alt+left', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 37 }).key, '\x1bb'); // CSI 5 D }); it('should return \\x1bf for alt+right', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1bf'); // CSI 5 C }); }); it('should return \\x1b[5A for alt+up', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A }); it('should return \\x1b[5B for alt+down', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 40 }).key, '\x1b[1;5B'); // CSI 5 B }); it('should return the correct escape sequence for modified F1-F12 keys', function() { assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 112 }).key, '\x1b[1;2P'); assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 113 }).key, '\x1b[1;2Q'); assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 114 }).key, '\x1b[1;2R'); assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 115 }).key, '\x1b[1;2S'); assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 116 }).key, '\x1b[15;2~'); assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 117 }).key, '\x1b[17;2~'); assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 118 }).key, '\x1b[18;2~'); assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 119 }).key, '\x1b[19;2~'); assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 120 }).key, '\x1b[20;2~'); assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 121 }).key, '\x1b[21;2~'); assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 122 }).key, '\x1b[23;2~'); assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 123 }).key, '\x1b[24;2~'); assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 112 }).key, '\x1b[1;3P'); assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 113 }).key, '\x1b[1;3Q'); assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 114 }).key, '\x1b[1;3R'); assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 115 }).key, '\x1b[1;3S'); assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 116 }).key, '\x1b[15;3~'); assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 117 }).key, '\x1b[17;3~'); assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 118 }).key, '\x1b[18;3~'); assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 119 }).key, '\x1b[19;3~'); assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 120 }).key, '\x1b[20;3~'); assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 121 }).key, '\x1b[21;3~'); assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 122 }).key, '\x1b[23;3~'); assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 123 }).key, '\x1b[24;3~'); assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 112 }).key, '\x1b[1;5P'); assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 113 }).key, '\x1b[1;5Q'); assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 114 }).key, '\x1b[1;5R'); assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 115 }).key, '\x1b[1;5S'); assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 116 }).key, '\x1b[15;5~'); assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 117 }).key, '\x1b[17;5~'); assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 118 }).key, '\x1b[18;5~'); assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 119 }).key, '\x1b[19;5~'); assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 120 }).key, '\x1b[20;5~'); assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 121 }).key, '\x1b[21;5~'); assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 122 }).key, '\x1b[23;5~'); assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 123 }).key, '\x1b[24;5~'); }); }); describe('attachCustomEventHandler', function () { var evKeyDown = { preventDefault: function() {}, stopPropagation: function() {}, type: 'keydown' } beforeEach(function() { xterm.handler = function() {}; xterm.showCursor = function() {}; xterm.clearSelection = function() {}; xterm.compositionHelper = { keydown: { bind: function() { return function () { return true; } } } } }); it('should process the keydown event based on what the handler returns', function () { assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), true); xterm.attachCustomKeydownHandler(function (ev) { return ev.keyCode === 77; }); assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), true); xterm.attachCustomKeydownHandler(function (ev) { return ev.keyCode !== 77; }); assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), false); }); it('should alive after reset(ESC c Full Reset (RIS))', function () { xterm.attachCustomKeydownHandler(function (ev) { return ev.keyCode !== 77; }); assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), false); xterm.reset(); assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), false); }); }); describe('Third level shift', function() { var evKeyDown = { preventDefault: function() {}, stopPropagation: function() {}, type: 'keydown' }, evKeyPress = { preventDefault: function() {}, stopPropagation: function() {}, type: 'keypress' }; beforeEach(function() { xterm.handler = function() {}; xterm.showCursor = function() {}; xterm.clearSelection = function() {}; xterm.compositionHelper = { isComposing: false, keydown: { bind: function() { return function() { return true; }; } } }; }); describe('On Mac OS', function() { beforeEach(function() { xterm.browser.isMac = true; }); it('should not interfere with the alt key on keyDown', function() { assert.equal( xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, keyCode: 81 })), true ); assert.equal( xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, keyCode: 192 })), true ); }); it('should interefere with the alt + arrow keys', function() { assert.equal( xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, keyCode: 37 })), false ); assert.equal( xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, keyCode: 39 })), false ); }); it('should emit key with alt + key on keyPress', function(done) { var keys = ['@', '@', '\\', '\\', '|', '|']; xterm.on('keypress', function(key) { if (key) { var index = keys.indexOf(key); assert(index !== -1, "Emitted wrong key: " + key); keys.splice(index, 1); } if (keys.length === 0) done(); }); xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 64 })); // @ // Firefox xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, charCode: 64, keyCode: 0 })); xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 92 })); // \ xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, charCode: 92, keyCode: 0 })); xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 124 })); // | xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, charCode: 124, keyCode: 0 })); }); }); describe('On MS Windows', function() { beforeEach(function() { xterm.browser.isMSWindows = true; }); it('should not interfere with the alt + ctrl key on keyDown', function() { assert.equal( xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, ctrlKey: true, keyCode: 81 })), true ); assert.equal( xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, ctrlKey: true, keyCode: 192 })), true ); }); it('should interefere with the alt + ctrl + arrow keys', function() { assert.equal( xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, ctrlKey: true, keyCode: 37 })), false ); assert.equal( xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, ctrlKey: true, keyCode: 39 })), false ); }); it('should emit key with alt + ctrl + key on keyPress', function(done) { var keys = ['@', '@', '\\', '\\', '|', '|']; xterm.on('keypress', function(key) { if (key) { var index = keys.indexOf(key); assert(index !== -1, "Emitted wrong key: " + key); keys.splice(index, 1); } if (keys.length === 0) done(); }); xterm.keyPress( Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 64 }) ); // @ xterm.keyPress( Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, charCode: 64, keyCode: 0 }) ); xterm.keyPress( Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 92 }) ); // \ xterm.keyPress( Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, charCode: 92, keyCode: 0 }) ); xterm.keyPress( Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 124 }) ); // | xterm.keyPress( Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, charCode: 124, keyCode: 0 }) ); }); }); }); describe('unicode - surrogates', function() { it('2 characters per cell', function () { this.timeout(10000); // This is needed because istanbul patches code and slows it down 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]; 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(' '); 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.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(' '); 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.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(' '); 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.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(' '); xterm.reset(); } }); it('splitted surrogates', function() { var high = String.fromCharCode(0xD800); for (var i=0xDC00; i<=0xDCFF; ++i) { xterm.write(high); xterm.write(String.fromCharCode(i)); var tchar = xterm.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(' '); 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); }); it('café - end of line', function() { xterm.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); }); it('multiple combined é', function() { xterm.wraparoundMode = true; xterm.write(Array(100).join('e\u0301')); for (var i=0; i { let window: Window; let document: Document; let container: HTMLElement; let charMeasure: ICharMeasure; beforeEach(done => { jsdom.env('', (err, w) => { window = w; document = window.document; container = document.createElement('div'); document.body.appendChild(container); charMeasure = new CharMeasure(document, container); done(); }); }); describe('measure', () => { it('should set _measureElement on first call', () => { charMeasure.measure(); assert.isDefined((charMeasure)._measureElement, 'CharMeasure.measure should have created _measureElement'); }); it('should be performed async on first call', done => { assert.equal(charMeasure.width, null); charMeasure.measure(); // Mock getBoundingClientRect since jsdom doesn't have a layout engine (charMeasure)._measureElement.getBoundingClientRect = () => { return { width: 1, height: 1 }; }; assert.equal(charMeasure.width, null); setTimeout(() => { assert.equal(charMeasure.width, 1); done(); }, 0); }); it('should be performed sync on successive calls', done => { charMeasure.measure(); // Mock getBoundingClientRect since jsdom doesn't have a layout engine (charMeasure)._measureElement.getBoundingClientRect = () => { return { width: 1, height: 1 }; }; setTimeout(() => { const firstWidth = charMeasure.width; // Mock getBoundingClientRect since jsdom doesn't have a layout engine (charMeasure)._measureElement.getBoundingClientRect = () => { return { width: 2, height: 2 }; }; charMeasure.measure(); assert.equal(charMeasure.width, firstWidth * 2); done(); }, 0); }); it('should NOT do a measure when the parent is hidden', done => { charMeasure.measure(); setTimeout(() => { const firstWidth = charMeasure.width; container.style.display = 'none'; container.style.fontSize = '2em'; charMeasure.measure(); assert.equal(charMeasure.width, firstWidth); done(); }, 0); }); }); }); xterm.js-2.7.0/src/utils/CharMeasure.ts000066400000000000000000000034551311554223300177760ustar00rootroot00000000000000/** * @module xterm/utils/CharMeasure * @license MIT */ import { EventEmitter } from '../EventEmitter.js'; /** * Utility class that measures the size of a character. */ export class CharMeasure extends EventEmitter { private _document: Document; private _parentElement: HTMLElement; private _measureElement: HTMLElement; private _width: number; private _height: number; constructor(document: Document, parentElement: HTMLElement) { super(); this._document = document; this._parentElement = parentElement; } public get width(): number { return this._width; } public get height(): number { return this._height; } public measure(): void { if (!this._measureElement) { this._measureElement = this._document.createElement('span'); this._measureElement.style.position = 'absolute'; this._measureElement.style.top = '0'; this._measureElement.style.left = '-9999em'; this._measureElement.textContent = 'W'; this._measureElement.setAttribute('aria-hidden', 'true'); this._parentElement.appendChild(this._measureElement); // Perform _doMeasure async if the element was just attached as sometimes // getBoundingClientRect does not return accurate values without this. setTimeout(() => this._doMeasure(), 0); } else { this._doMeasure(); } } private _doMeasure(): void { const geometry = this._measureElement.getBoundingClientRect(); // The element is likely currently display:none, we should retain the // previous value. if (geometry.width === 0 || geometry.height === 0) { return; } if (this._width !== geometry.width || this._height !== geometry.height) { this._width = geometry.width; this._height = geometry.height; this.emit('charsizechanged'); } } } xterm.js-2.7.0/src/utils/CircularList.test.ts000066400000000000000000000173201311554223300211510ustar00rootroot00000000000000import { assert } from 'chai'; import { CircularList } from './CircularList'; describe('CircularList', () => { describe('push', () => { it('should push values onto the array', () => { const list = new CircularList(5); list.push('1'); list.push('2'); list.push('3'); list.push('4'); list.push('5'); assert.equal(list.get(0), '1'); assert.equal(list.get(1), '2'); assert.equal(list.get(2), '3'); assert.equal(list.get(3), '4'); assert.equal(list.get(4), '5'); }); it('should push old values from the start out of the array when max length is reached', () => { const list = new CircularList(2); list.push('1'); list.push('2'); assert.equal(list.get(0), '1'); assert.equal(list.get(1), '2'); list.push('3'); assert.equal(list.get(0), '2'); assert.equal(list.get(1), '3'); list.push('4'); assert.equal(list.get(0), '3'); assert.equal(list.get(1), '4'); }); }); describe('maxLength', () => { it('should increase the size of the list', () => { const list = new CircularList(2); list.push('1'); list.push('2'); assert.equal(list.get(0), '1'); assert.equal(list.get(1), '2'); list.maxLength = 4; list.push('3'); list.push('4'); assert.equal(list.get(0), '1'); assert.equal(list.get(1), '2'); assert.equal(list.get(2), '3'); assert.equal(list.get(3), '4'); list.push('wrapped'); assert.equal(list.get(0), '2'); assert.equal(list.get(1), '3'); assert.equal(list.get(2), '4'); assert.equal(list.get(3), 'wrapped'); }); it('should return the maximum length of the list', () => { const list = new CircularList(2); assert.equal(list.maxLength, 2); list.push('1'); list.push('2'); assert.equal(list.maxLength, 2); list.push('3'); assert.equal(list.maxLength, 2); list.maxLength = 4; assert.equal(list.maxLength, 4); }); }); describe('length', () => { it('should return the current length of the list, capped at the maximum length', () => { const list = new CircularList(2); assert.equal(list.length, 0); list.push('1'); assert.equal(list.length, 1); list.push('2'); assert.equal(list.length, 2); list.push('3'); assert.equal(list.length, 2); }); }); describe('splice', () => { it('should delete items', () => { const list = new CircularList(2); list.push('1'); list.push('2'); list.splice(0, 1); assert.equal(list.length, 1); assert.equal(list.get(0), '2'); list.push('3'); list.splice(1, 1); assert.equal(list.length, 1); assert.equal(list.get(0), '2'); }); it('should insert items', () => { const list = new CircularList(2); list.push('1'); list.splice(0, 0, '2'); assert.equal(list.length, 2); assert.equal(list.get(0), '2'); assert.equal(list.get(1), '1'); list.splice(1, 0, '3'); assert.equal(list.length, 2); assert.equal(list.get(0), '3'); assert.equal(list.get(1), '1'); }); it('should delete items then insert items', () => { const list = new CircularList(3); list.push('1'); list.push('2'); list.splice(0, 1, '3', '4'); assert.equal(list.length, 3); assert.equal(list.get(0), '3'); assert.equal(list.get(1), '4'); assert.equal(list.get(2), '2'); }); it('should wrap the array correctly when more items are inserted than deleted', () => { const list = new CircularList(3); list.push('1'); list.push('2'); list.splice(1, 0, '3', '4'); assert.equal(list.length, 3); assert.equal(list.get(0), '3'); assert.equal(list.get(1), '4'); assert.equal(list.get(2), '2'); }); }); describe('trimStart', () => { it('should remove items from the beginning of the list', () => { const list = new CircularList(5); list.push('1'); list.push('2'); list.push('3'); list.push('4'); list.push('5'); list.trimStart(1); assert.equal(list.length, 4); assert.deepEqual(list.get(0), '2'); assert.deepEqual(list.get(1), '3'); assert.deepEqual(list.get(2), '4'); assert.deepEqual(list.get(3), '5'); list.trimStart(2); assert.equal(list.length, 2); assert.deepEqual(list.get(0), '4'); assert.deepEqual(list.get(1), '5'); }); it('should remove all items if the requested trim amount is larger than the list\'s length', () => { const list = new CircularList(5); list.push('1'); list.trimStart(2); assert.equal(list.length, 0); }); }); describe('shiftElements', () => { it('should not mutate the list when count is 0', () => { const list = new CircularList(5); list.push(1); list.push(2); list.shiftElements(0, 0, 1); assert.equal(list.length, 2); assert.equal(list.get(0), 1); assert.equal(list.get(1), 2); }); it('should throw for invalid args', () => { const list = new CircularList(5); list.push(1); assert.throws(() => list.shiftElements(-1, 1, 1), 'start argument out of range'); assert.throws(() => list.shiftElements(1, 1, 1), 'start argument out of range'); assert.throws(() => list.shiftElements(0, 1, -1), 'Cannot shift elements in list beyond index 0'); }); it('should shift an element forward', () => { const list = new CircularList(5); list.push(1); list.push(2); list.shiftElements(0, 1, 1); assert.equal(list.length, 2); assert.equal(list.get(0), 1); assert.equal(list.get(1), 1); }); it('should shift elements forward', () => { const list = new CircularList(5); list.push(1); list.push(2); list.push(3); list.push(4); list.shiftElements(0, 2, 2); assert.equal(list.length, 4); assert.equal(list.get(0), 1); assert.equal(list.get(1), 2); assert.equal(list.get(2), 1); assert.equal(list.get(3), 2); }); it('should shift elements forward, expanding the list if needed', () => { const list = new CircularList(5); list.push(1); list.push(2); list.shiftElements(0, 2, 2); assert.equal(list.length, 4); assert.equal(list.get(0), 1); assert.equal(list.get(1), 2); assert.equal(list.get(2), 1); assert.equal(list.get(3), 2); }); it('should shift elements forward, wrapping the list if needed', () => { const list = new CircularList(5); list.push(1); list.push(2); list.push(3); list.push(4); list.push(5); list.shiftElements(2, 2, 3); assert.equal(list.length, 5); assert.equal(list.get(0), 3); assert.equal(list.get(1), 4); assert.equal(list.get(2), 5); assert.equal(list.get(3), 3); assert.equal(list.get(4), 4); }); it('should shift an element backwards', () => { const list = new CircularList(5); list.push(1); list.push(2); list.shiftElements(1, 1, -1); assert.equal(list.length, 2); assert.equal(list.get(0), 2); assert.equal(list.get(1), 2); }); it('should shift elements backwards', () => { const list = new CircularList(5); list.push(1); list.push(2); list.push(3); list.push(4); list.shiftElements(2, 2, -2); assert.equal(list.length, 4); assert.equal(list.get(0), 3); assert.equal(list.get(1), 4); assert.equal(list.get(2), 3); assert.equal(list.get(3), 4); }); }); }); xterm.js-2.7.0/src/utils/CircularList.ts000066400000000000000000000130201311554223300201640ustar00rootroot00000000000000/** * Represents a circular list; a list with a maximum size that wraps around when push is called, * overriding values at the start of the list. * @module xterm/utils/CircularList * @license MIT */ export class CircularList { private _array: T[]; private _startIndex: number; private _length: number; constructor(maxLength: number) { this._array = new Array(maxLength); this._startIndex = 0; this._length = 0; } public get maxLength(): number { return this._array.length; } public set maxLength(newMaxLength: number) { // Reconstruct array, starting at index 0. Only transfer values from the // indexes 0 to length. let newArray = new Array(newMaxLength); for (let i = 0; i < Math.min(newMaxLength, this.length); i++) { newArray[i] = this._array[this._getCyclicIndex(i)]; } this._array = newArray; this._startIndex = 0; } public get length(): number { return this._length; } public set length(newLength: number) { if (newLength > this._length) { for (let i = this._length; i < newLength; i++) { this._array[i] = undefined; } } this._length = newLength; } public get forEach(): (callbackfn: (value: T, index: number, array: T[]) => void) => void { return this._array.forEach; } /** * Gets the value at an index. * * Note that for performance reasons there is no bounds checking here, the index reference is * circular so this should always return a value and never throw. * @param index The index of the value to get. * @return The value corresponding to the index. */ public get(index: number): T { return this._array[this._getCyclicIndex(index)]; } /** * Sets the value at an index. * * Note that for performance reasons there is no bounds checking here, the index reference is * circular so this should always return a value and never throw. * @param index The index to set. * @param value The value to set. */ public set(index: number, value: T): void { this._array[this._getCyclicIndex(index)] = value; } /** * Pushes a new value onto the list, wrapping around to the start of the array, overriding index 0 * if the maximum length is reached. * @param value The value to push onto the list. */ public push(value: T): void { this._array[this._getCyclicIndex(this._length)] = value; if (this._length === this.maxLength) { this._startIndex++; if (this._startIndex === this.maxLength) { this._startIndex = 0; } } else { this._length++; } } /** * Removes and returns the last value on the list. * @return The popped value. */ public pop(): T { return this._array[this._getCyclicIndex(this._length-- - 1)]; } /** * Deletes and/or inserts items at a particular index (in that order). Unlike * Array.prototype.splice, this operation does not return the deleted items as a new array in * order to save creating a new array. Note that this operation may shift all values in the list * in the worst case. * @param start The index to delete and/or insert. * @param deleteCount The number of elements to delete. * @param items The items to insert. */ public splice(start: number, deleteCount: number, ...items: T[]): void { if (deleteCount) { for (let i = start; i < this._length - deleteCount; i++) { this._array[this._getCyclicIndex(i)] = this._array[this._getCyclicIndex(i + deleteCount)]; } this._length -= deleteCount; } if (items && items.length) { for (let i = this._length - 1; i >= start; i--) { this._array[this._getCyclicIndex(i + items.length)] = this._array[this._getCyclicIndex(i)]; } for (let i = 0; i < items.length; i++) { this._array[this._getCyclicIndex(start + i)] = items[i]; } if (this._length + items.length > this.maxLength) { this._startIndex += (this._length + items.length) - this.maxLength; this._length = this.maxLength; } else { this._length += items.length; } } } /** * Trims a number of items from the start of the list. * @param count The number of items to remove. */ public trimStart(count: number): void { if (count > this._length) { count = this._length; } this._startIndex += count; this._length -= count; } public shiftElements(start: number, count: number, offset: number): void { if (count <= 0) { return; } if (start < 0 || start >= this._length) { throw new Error('start argument out of range'); } if (start + offset < 0) { throw new Error('Cannot shift elements in list beyond index 0'); } if (offset > 0) { for (let i = count - 1; i >= 0; i--) { this.set(start + i + offset, this.get(start + i)); } const expandListBy = (start + count + offset) - this._length; if (expandListBy > 0) { this._length += expandListBy; while (this._length > this.maxLength) { this._length--; this._startIndex++; } } } else { for (let i = 0; i < count; i++) { this.set(start + i + offset, this.get(start + i)); } } } /** * Gets the cyclic index for the specified regular index. The cyclic index can then be used on the * backing array to get the element associated with the regular index. * @param index The regular index. * @returns The cyclic index. */ private _getCyclicIndex(index: number): number { return (this._startIndex + index) % this.maxLength; } } xterm.js-2.7.0/src/utils/DomElementObjectPool.test.ts000066400000000000000000000026271311554223300225670ustar00rootroot00000000000000import { assert } from 'chai'; import { DomElementObjectPool } from './DomElementObjectPool'; class MockDocument { private _attr: {[key: string]: string} = {}; constructor() {} public getAttribute(key: string): string { return this._attr[key]; }; public setAttribute(key: string, value: string): void { this._attr[key] = value; } } describe('DomElementObjectPool', () => { let pool: DomElementObjectPool; beforeEach(() => { pool = new DomElementObjectPool('span'); (global).document = { createElement: () => new MockDocument() }; }); it('should acquire distinct elements', () => { const element1 = pool.acquire(); const element2 = pool.acquire(); assert.notEqual(element1, element2); }); it('should acquire released elements', () => { const element = pool.acquire(); pool.release(element); assert.equal(pool.acquire(), element); }); it('should handle a series of acquisitions and releases', () => { const element1 = pool.acquire(); const element2 = pool.acquire(); pool.release(element1); assert.equal(pool.acquire(), element1); pool.release(element1); pool.release(element2); assert.equal(pool.acquire(), element2); assert.equal(pool.acquire(), element1); }); it('should throw when releasing an element that was not acquired', () => { assert.throws(() => pool.release(document.createElement('span'))); }); }); xterm.js-2.7.0/src/utils/DomElementObjectPool.ts000066400000000000000000000041051311554223300216020ustar00rootroot00000000000000/** * @module xterm/utils/DomElementObjectPool * @license MIT */ /** * An object pool that manages acquisition and releasing of DOM elements for * when reuse is desirable. */ export class DomElementObjectPool { private static readonly OBJECT_ID_ATTRIBUTE = 'data-obj-id'; private static _objectCount = 0; private _type: string; private _pool: HTMLElement[]; private _inUse: {[key: string]: HTMLElement}; /** * @param type The DOM element type (div, span, etc.). */ constructor(private type: string) { this._type = type; this._pool = []; this._inUse = {}; } /** * Acquire an element from the pool, creating it if the pool is empty. */ public acquire(): HTMLElement { let element: HTMLElement; if (this._pool.length === 0) { element = this._createNew(); } else { element = this._pool.pop(); } this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)] = element; return element; } /** * Release an element back into the pool. It's up to the caller of this * function to ensure that all external references to the element have been * removed. * @param element The element being released. */ public release(element: HTMLElement): void { if (!this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)]) { throw new Error('Could not release an element not yet acquired'); } delete this._inUse[element.getAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE)]; this._cleanElement(element); this._pool.push(element); } /** * Creates a new element for the pool. */ private _createNew(): HTMLElement { const element = document.createElement(this._type); const id = DomElementObjectPool._objectCount++; element.setAttribute(DomElementObjectPool.OBJECT_ID_ATTRIBUTE, id.toString(10)); return element; } /** * Resets an element back to a "clean state". * @param element The element to be cleaned. */ private _cleanElement(element: HTMLElement): void { element.className = ''; element.innerHTML = ''; } } xterm.js-2.7.0/src/utils/Generic.ts000066400000000000000000000006541311554223300171510ustar00rootroot00000000000000/** * Generic utilities module with methods that can be helpful at different parts of the code base. * @module xterm/utils/Generic * @license MIT */ /** * Return if the given array contains the given element * @param {Array} array The array to search for the given element. * @param {Object} el The element to look for into the array */ export function contains(arr: any[], el: any) { return arr.indexOf(el) >= 0; }; xterm.js-2.7.0/src/utils/Mouse.ts000066400000000000000000000042231311554223300166610ustar00rootroot00000000000000/** * @license MIT */ import { CharMeasure } from './CharMeasure'; /** * Gets coordinates within the terminal for a particular mouse event. The result * is returned as an array in the form [x, y] instead of an object as it's a * little faster and this function is used in some low level code. * @param event The mouse event. * @param rowContainer The terminal's row container. * @param charMeasure The char measure object used to determine character sizes. */ export function getCoords(event: MouseEvent, rowContainer: HTMLElement, charMeasure: CharMeasure): [number, number] { // Ignore browsers that don't support MouseEvent.pageX if (event.pageX == null) { return null; } let x = event.pageX; let y = event.pageY; let el = rowContainer; // Converts the coordinates from being relative to the document to being // relative to the terminal. while (el && el !== self.document.documentElement) { x -= el.offsetLeft; y -= el.offsetTop; el = 'offsetParent' in el ? el.offsetParent : el.parentElement; } // Convert to cols/rows x = Math.ceil(x / charMeasure.width); y = Math.ceil(y / charMeasure.height); return [x, y]; } /** * Gets coordinates within the terminal for a particular mouse event, wrapping * them to the bounds of the terminal and adding 32 to both the x and y values * as expected by xterm. * @param event The mouse event. * @param rowContainer The terminal's row container. * @param charMeasure The char measure object used to determine character sizes. * @param colCount The number of columns in the terminal. * @param rowCount The number of rows in the terminal. */ export function getRawByteCoords(event: MouseEvent, rowContainer: HTMLElement, charMeasure: CharMeasure, colCount: number, rowCount: number): { x: number, y: number } { const coords = getCoords(event, rowContainer, charMeasure); let x = coords[0]; let y = coords[1]; // Ensure coordinates are within the terminal viewport. x = Math.min(Math.max(x, 0), colCount); y = Math.min(Math.max(y, 0), rowCount); // xterm sends raw bytes and starts at 32 (SP) for each. x += 32; y += 32; return { x, y }; } xterm.js-2.7.0/src/xterm.css000066400000000000000000001047761311554223300157500ustar00rootroot00000000000000/** * xterm.js: xterm, in the browser * Copyright (c) 2014-2016, SourceLair Private Company (www.sourcelair.com (MIT License) * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) * https://github.com/chjj/term.js * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * Originally forked from (with the author's permission): * Fabrice Bellard's javascript vt100 for jslinux: * http://bellard.org/jslinux/ * Copyright (c) 2011 Fabrice Bellard * The original design remains. The terminal itself * has been extended to include xterm CSI codes, among * other features. */ /* * Default style for xterm.js */ .terminal { background-color: #000; color: #fff; font-family: courier-new, courier, monospace; font-feature-settings: "liga" 0; position: relative; } .terminal.focus, .terminal:focus { outline: none; } .terminal .xterm-helpers { position: absolute; top: 0; } .terminal .xterm-helper-textarea { /* * HACK: to fix IE's blinking cursor * Move textarea out of the screen to the far left, so that the cursor is not visible. */ position: absolute; opacity: 0; left: -9999em; top: 0; width: 0; height: 0; z-index: -10; /** Prevent wrapping so the IME appears against the textarea at the correct position */ white-space: nowrap; overflow: hidden; resize: none; } .terminal a { color: inherit; text-decoration: none; } .terminal a:hover { cursor: pointer; text-decoration: underline; } .terminal a.xterm-invalid-link:hover { cursor: text; text-decoration: none; } .terminal.focus:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar) .terminal-cursor { background-color: #fff; color: #000; } .terminal:not(.focus) .terminal-cursor { outline: 1px solid #fff; outline-offset: -1px; background-color: transparent; } .terminal:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar).focus.xterm-cursor-blink-on .terminal-cursor { background-color: transparent; color: inherit; } .terminal.xterm-cursor-style-bar .terminal-cursor, .terminal.xterm-cursor-style-underline .terminal-cursor { position: relative; } .terminal.xterm-cursor-style-bar .terminal-cursor::before, .terminal.xterm-cursor-style-underline .terminal-cursor::before { content: ""; display: block; position: absolute; background-color: #fff; } .terminal.xterm-cursor-style-bar .terminal-cursor::before { top: 0; bottom: 0; left: 0; width: 1px; } .terminal.xterm-cursor-style-underline .terminal-cursor::before { bottom: 0; left: 0; right: 0; height: 1px; } .terminal.xterm-cursor-style-bar.focus.xterm-cursor-blink.xterm-cursor-blink-on .terminal-cursor::before, .terminal.xterm-cursor-style-underline.focus.xterm-cursor-blink.xterm-cursor-blink-on .terminal-cursor::before { background-color: transparent; } .terminal.xterm-cursor-style-bar.focus.xterm-cursor-blink .terminal-cursor::before, .terminal.xterm-cursor-style-underline.focus.xterm-cursor-blink .terminal-cursor::before { background-color: #fff; } .terminal .composition-view { background: #000; color: #FFF; display: none; position: absolute; white-space: nowrap; z-index: 1; } .terminal .composition-view.active { display: block; } .terminal .xterm-viewport { /* On OS X this is required in order for the scroll bar to appear fully opaque */ background-color: #000; overflow-y: scroll; } .terminal .xterm-wide-char, .terminal .xterm-normal-char { display: inline-block; } .terminal .xterm-rows { position: absolute; left: 0; top: 0; } .terminal .xterm-rows > div { /* Lines containing spans and text nodes ocassionally wrap despite being the same width (#327) */ white-space: nowrap; } .terminal .xterm-scroll-area { visibility: hidden; } .terminal .xterm-char-measure-element { display: inline-block; visibility: hidden; position: absolute; left: -9999em; } /* * Determine default colors for xterm.js */ .terminal .xterm-bold { font-weight: bold; } .terminal .xterm-underline { text-decoration: underline; } .terminal .xterm-blink { text-decoration: blink; } .terminal .xterm-hidden { visibility: hidden; } .terminal .xterm-color-0 { color: #2e3436; } .terminal .xterm-bg-color-0 { background-color: #2e3436; } .terminal .xterm-color-1 { color: #cc0000; } .terminal .xterm-bg-color-1 { background-color: #cc0000; } .terminal .xterm-color-2 { color: #4e9a06; } .terminal .xterm-bg-color-2 { background-color: #4e9a06; } .terminal .xterm-color-3 { color: #c4a000; } .terminal .xterm-bg-color-3 { background-color: #c4a000; } .terminal .xterm-color-4 { color: #3465a4; } .terminal .xterm-bg-color-4 { background-color: #3465a4; } .terminal .xterm-color-5 { color: #75507b; } .terminal .xterm-bg-color-5 { background-color: #75507b; } .terminal .xterm-color-6 { color: #06989a; } .terminal .xterm-bg-color-6 { background-color: #06989a; } .terminal .xterm-color-7 { color: #d3d7cf; } .terminal .xterm-bg-color-7 { background-color: #d3d7cf; } .terminal .xterm-color-8 { color: #555753; } .terminal .xterm-bg-color-8 { background-color: #555753; } .terminal .xterm-color-9 { color: #ef2929; } .terminal .xterm-bg-color-9 { background-color: #ef2929; } .terminal .xterm-color-10 { color: #8ae234; } .terminal .xterm-bg-color-10 { background-color: #8ae234; } .terminal .xterm-color-11 { color: #fce94f; } .terminal .xterm-bg-color-11 { background-color: #fce94f; } .terminal .xterm-color-12 { color: #729fcf; } .terminal .xterm-bg-color-12 { background-color: #729fcf; } .terminal .xterm-color-13 { color: #ad7fa8; } .terminal .xterm-bg-color-13 { background-color: #ad7fa8; } .terminal .xterm-color-14 { color: #34e2e2; } .terminal .xterm-bg-color-14 { background-color: #34e2e2; } .terminal .xterm-color-15 { color: #eeeeec; } .terminal .xterm-bg-color-15 { background-color: #eeeeec; } .terminal .xterm-color-16 { color: #000000; } .terminal .xterm-bg-color-16 { background-color: #000000; } .terminal .xterm-color-17 { color: #00005f; } .terminal .xterm-bg-color-17 { background-color: #00005f; } .terminal .xterm-color-18 { color: #000087; } .terminal .xterm-bg-color-18 { background-color: #000087; } .terminal .xterm-color-19 { color: #0000af; } .terminal .xterm-bg-color-19 { background-color: #0000af; } .terminal .xterm-color-20 { color: #0000d7; } .terminal .xterm-bg-color-20 { background-color: #0000d7; } .terminal .xterm-color-21 { color: #0000ff; } .terminal .xterm-bg-color-21 { background-color: #0000ff; } .terminal .xterm-color-22 { color: #005f00; } .terminal .xterm-bg-color-22 { background-color: #005f00; } .terminal .xterm-color-23 { color: #005f5f; } .terminal .xterm-bg-color-23 { background-color: #005f5f; } .terminal .xterm-color-24 { color: #005f87; } .terminal .xterm-bg-color-24 { background-color: #005f87; } .terminal .xterm-color-25 { color: #005faf; } .terminal .xterm-bg-color-25 { background-color: #005faf; } .terminal .xterm-color-26 { color: #005fd7; } .terminal .xterm-bg-color-26 { background-color: #005fd7; } .terminal .xterm-color-27 { color: #005fff; } .terminal .xterm-bg-color-27 { background-color: #005fff; } .terminal .xterm-color-28 { color: #008700; } .terminal .xterm-bg-color-28 { background-color: #008700; } .terminal .xterm-color-29 { color: #00875f; } .terminal .xterm-bg-color-29 { background-color: #00875f; } .terminal .xterm-color-30 { color: #008787; } .terminal .xterm-bg-color-30 { background-color: #008787; } .terminal .xterm-color-31 { color: #0087af; } .terminal .xterm-bg-color-31 { background-color: #0087af; } .terminal .xterm-color-32 { color: #0087d7; } .terminal .xterm-bg-color-32 { background-color: #0087d7; } .terminal .xterm-color-33 { color: #0087ff; } .terminal .xterm-bg-color-33 { background-color: #0087ff; } .terminal .xterm-color-34 { color: #00af00; } .terminal .xterm-bg-color-34 { background-color: #00af00; } .terminal .xterm-color-35 { color: #00af5f; } .terminal .xterm-bg-color-35 { background-color: #00af5f; } .terminal .xterm-color-36 { color: #00af87; } .terminal .xterm-bg-color-36 { background-color: #00af87; } .terminal .xterm-color-37 { color: #00afaf; } .terminal .xterm-bg-color-37 { background-color: #00afaf; } .terminal .xterm-color-38 { color: #00afd7; } .terminal .xterm-bg-color-38 { background-color: #00afd7; } .terminal .xterm-color-39 { color: #00afff; } .terminal .xterm-bg-color-39 { background-color: #00afff; } .terminal .xterm-color-40 { color: #00d700; } .terminal .xterm-bg-color-40 { background-color: #00d700; } .terminal .xterm-color-41 { color: #00d75f; } .terminal .xterm-bg-color-41 { background-color: #00d75f; } .terminal .xterm-color-42 { color: #00d787; } .terminal .xterm-bg-color-42 { background-color: #00d787; } .terminal .xterm-color-43 { color: #00d7af; } .terminal .xterm-bg-color-43 { background-color: #00d7af; } .terminal .xterm-color-44 { color: #00d7d7; } .terminal .xterm-bg-color-44 { background-color: #00d7d7; } .terminal .xterm-color-45 { color: #00d7ff; } .terminal .xterm-bg-color-45 { background-color: #00d7ff; } .terminal .xterm-color-46 { color: #00ff00; } .terminal .xterm-bg-color-46 { background-color: #00ff00; } .terminal .xterm-color-47 { color: #00ff5f; } .terminal .xterm-bg-color-47 { background-color: #00ff5f; } .terminal .xterm-color-48 { color: #00ff87; } .terminal .xterm-bg-color-48 { background-color: #00ff87; } .terminal .xterm-color-49 { color: #00ffaf; } .terminal .xterm-bg-color-49 { background-color: #00ffaf; } .terminal .xterm-color-50 { color: #00ffd7; } .terminal .xterm-bg-color-50 { background-color: #00ffd7; } .terminal .xterm-color-51 { color: #00ffff; } .terminal .xterm-bg-color-51 { background-color: #00ffff; } .terminal .xterm-color-52 { color: #5f0000; } .terminal .xterm-bg-color-52 { background-color: #5f0000; } .terminal .xterm-color-53 { color: #5f005f; } .terminal .xterm-bg-color-53 { background-color: #5f005f; } .terminal .xterm-color-54 { color: #5f0087; } .terminal .xterm-bg-color-54 { background-color: #5f0087; } .terminal .xterm-color-55 { color: #5f00af; } .terminal .xterm-bg-color-55 { background-color: #5f00af; } .terminal .xterm-color-56 { color: #5f00d7; } .terminal .xterm-bg-color-56 { background-color: #5f00d7; } .terminal .xterm-color-57 { color: #5f00ff; } .terminal .xterm-bg-color-57 { background-color: #5f00ff; } .terminal .xterm-color-58 { color: #5f5f00; } .terminal .xterm-bg-color-58 { background-color: #5f5f00; } .terminal .xterm-color-59 { color: #5f5f5f; } .terminal .xterm-bg-color-59 { background-color: #5f5f5f; } .terminal .xterm-color-60 { color: #5f5f87; } .terminal .xterm-bg-color-60 { background-color: #5f5f87; } .terminal .xterm-color-61 { color: #5f5faf; } .terminal .xterm-bg-color-61 { background-color: #5f5faf; } .terminal .xterm-color-62 { color: #5f5fd7; } .terminal .xterm-bg-color-62 { background-color: #5f5fd7; } .terminal .xterm-color-63 { color: #5f5fff; } .terminal .xterm-bg-color-63 { background-color: #5f5fff; } .terminal .xterm-color-64 { color: #5f8700; } .terminal .xterm-bg-color-64 { background-color: #5f8700; } .terminal .xterm-color-65 { color: #5f875f; } .terminal .xterm-bg-color-65 { background-color: #5f875f; } .terminal .xterm-color-66 { color: #5f8787; } .terminal .xterm-bg-color-66 { background-color: #5f8787; } .terminal .xterm-color-67 { color: #5f87af; } .terminal .xterm-bg-color-67 { background-color: #5f87af; } .terminal .xterm-color-68 { color: #5f87d7; } .terminal .xterm-bg-color-68 { background-color: #5f87d7; } .terminal .xterm-color-69 { color: #5f87ff; } .terminal .xterm-bg-color-69 { background-color: #5f87ff; } .terminal .xterm-color-70 { color: #5faf00; } .terminal .xterm-bg-color-70 { background-color: #5faf00; } .terminal .xterm-color-71 { color: #5faf5f; } .terminal .xterm-bg-color-71 { background-color: #5faf5f; } .terminal .xterm-color-72 { color: #5faf87; } .terminal .xterm-bg-color-72 { background-color: #5faf87; } .terminal .xterm-color-73 { color: #5fafaf; } .terminal .xterm-bg-color-73 { background-color: #5fafaf; } .terminal .xterm-color-74 { color: #5fafd7; } .terminal .xterm-bg-color-74 { background-color: #5fafd7; } .terminal .xterm-color-75 { color: #5fafff; } .terminal .xterm-bg-color-75 { background-color: #5fafff; } .terminal .xterm-color-76 { color: #5fd700; } .terminal .xterm-bg-color-76 { background-color: #5fd700; } .terminal .xterm-color-77 { color: #5fd75f; } .terminal .xterm-bg-color-77 { background-color: #5fd75f; } .terminal .xterm-color-78 { color: #5fd787; } .terminal .xterm-bg-color-78 { background-color: #5fd787; } .terminal .xterm-color-79 { color: #5fd7af; } .terminal .xterm-bg-color-79 { background-color: #5fd7af; } .terminal .xterm-color-80 { color: #5fd7d7; } .terminal .xterm-bg-color-80 { background-color: #5fd7d7; } .terminal .xterm-color-81 { color: #5fd7ff; } .terminal .xterm-bg-color-81 { background-color: #5fd7ff; } .terminal .xterm-color-82 { color: #5fff00; } .terminal .xterm-bg-color-82 { background-color: #5fff00; } .terminal .xterm-color-83 { color: #5fff5f; } .terminal .xterm-bg-color-83 { background-color: #5fff5f; } .terminal .xterm-color-84 { color: #5fff87; } .terminal .xterm-bg-color-84 { background-color: #5fff87; } .terminal .xterm-color-85 { color: #5fffaf; } .terminal .xterm-bg-color-85 { background-color: #5fffaf; } .terminal .xterm-color-86 { color: #5fffd7; } .terminal .xterm-bg-color-86 { background-color: #5fffd7; } .terminal .xterm-color-87 { color: #5fffff; } .terminal .xterm-bg-color-87 { background-color: #5fffff; } .terminal .xterm-color-88 { color: #870000; } .terminal .xterm-bg-color-88 { background-color: #870000; } .terminal .xterm-color-89 { color: #87005f; } .terminal .xterm-bg-color-89 { background-color: #87005f; } .terminal .xterm-color-90 { color: #870087; } .terminal .xterm-bg-color-90 { background-color: #870087; } .terminal .xterm-color-91 { color: #8700af; } .terminal .xterm-bg-color-91 { background-color: #8700af; } .terminal .xterm-color-92 { color: #8700d7; } .terminal .xterm-bg-color-92 { background-color: #8700d7; } .terminal .xterm-color-93 { color: #8700ff; } .terminal .xterm-bg-color-93 { background-color: #8700ff; } .terminal .xterm-color-94 { color: #875f00; } .terminal .xterm-bg-color-94 { background-color: #875f00; } .terminal .xterm-color-95 { color: #875f5f; } .terminal .xterm-bg-color-95 { background-color: #875f5f; } .terminal .xterm-color-96 { color: #875f87; } .terminal .xterm-bg-color-96 { background-color: #875f87; } .terminal .xterm-color-97 { color: #875faf; } .terminal .xterm-bg-color-97 { background-color: #875faf; } .terminal .xterm-color-98 { color: #875fd7; } .terminal .xterm-bg-color-98 { background-color: #875fd7; } .terminal .xterm-color-99 { color: #875fff; } .terminal .xterm-bg-color-99 { background-color: #875fff; } .terminal .xterm-color-100 { color: #878700; } .terminal .xterm-bg-color-100 { background-color: #878700; } .terminal .xterm-color-101 { color: #87875f; } .terminal .xterm-bg-color-101 { background-color: #87875f; } .terminal .xterm-color-102 { color: #878787; } .terminal .xterm-bg-color-102 { background-color: #878787; } .terminal .xterm-color-103 { color: #8787af; } .terminal .xterm-bg-color-103 { background-color: #8787af; } .terminal .xterm-color-104 { color: #8787d7; } .terminal .xterm-bg-color-104 { background-color: #8787d7; } .terminal .xterm-color-105 { color: #8787ff; } .terminal .xterm-bg-color-105 { background-color: #8787ff; } .terminal .xterm-color-106 { color: #87af00; } .terminal .xterm-bg-color-106 { background-color: #87af00; } .terminal .xterm-color-107 { color: #87af5f; } .terminal .xterm-bg-color-107 { background-color: #87af5f; } .terminal .xterm-color-108 { color: #87af87; } .terminal .xterm-bg-color-108 { background-color: #87af87; } .terminal .xterm-color-109 { color: #87afaf; } .terminal .xterm-bg-color-109 { background-color: #87afaf; } .terminal .xterm-color-110 { color: #87afd7; } .terminal .xterm-bg-color-110 { background-color: #87afd7; } .terminal .xterm-color-111 { color: #87afff; } .terminal .xterm-bg-color-111 { background-color: #87afff; } .terminal .xterm-color-112 { color: #87d700; } .terminal .xterm-bg-color-112 { background-color: #87d700; } .terminal .xterm-color-113 { color: #87d75f; } .terminal .xterm-bg-color-113 { background-color: #87d75f; } .terminal .xterm-color-114 { color: #87d787; } .terminal .xterm-bg-color-114 { background-color: #87d787; } .terminal .xterm-color-115 { color: #87d7af; } .terminal .xterm-bg-color-115 { background-color: #87d7af; } .terminal .xterm-color-116 { color: #87d7d7; } .terminal .xterm-bg-color-116 { background-color: #87d7d7; } .terminal .xterm-color-117 { color: #87d7ff; } .terminal .xterm-bg-color-117 { background-color: #87d7ff; } .terminal .xterm-color-118 { color: #87ff00; } .terminal .xterm-bg-color-118 { background-color: #87ff00; } .terminal .xterm-color-119 { color: #87ff5f; } .terminal .xterm-bg-color-119 { background-color: #87ff5f; } .terminal .xterm-color-120 { color: #87ff87; } .terminal .xterm-bg-color-120 { background-color: #87ff87; } .terminal .xterm-color-121 { color: #87ffaf; } .terminal .xterm-bg-color-121 { background-color: #87ffaf; } .terminal .xterm-color-122 { color: #87ffd7; } .terminal .xterm-bg-color-122 { background-color: #87ffd7; } .terminal .xterm-color-123 { color: #87ffff; } .terminal .xterm-bg-color-123 { background-color: #87ffff; } .terminal .xterm-color-124 { color: #af0000; } .terminal .xterm-bg-color-124 { background-color: #af0000; } .terminal .xterm-color-125 { color: #af005f; } .terminal .xterm-bg-color-125 { background-color: #af005f; } .terminal .xterm-color-126 { color: #af0087; } .terminal .xterm-bg-color-126 { background-color: #af0087; } .terminal .xterm-color-127 { color: #af00af; } .terminal .xterm-bg-color-127 { background-color: #af00af; } .terminal .xterm-color-128 { color: #af00d7; } .terminal .xterm-bg-color-128 { background-color: #af00d7; } .terminal .xterm-color-129 { color: #af00ff; } .terminal .xterm-bg-color-129 { background-color: #af00ff; } .terminal .xterm-color-130 { color: #af5f00; } .terminal .xterm-bg-color-130 { background-color: #af5f00; } .terminal .xterm-color-131 { color: #af5f5f; } .terminal .xterm-bg-color-131 { background-color: #af5f5f; } .terminal .xterm-color-132 { color: #af5f87; } .terminal .xterm-bg-color-132 { background-color: #af5f87; } .terminal .xterm-color-133 { color: #af5faf; } .terminal .xterm-bg-color-133 { background-color: #af5faf; } .terminal .xterm-color-134 { color: #af5fd7; } .terminal .xterm-bg-color-134 { background-color: #af5fd7; } .terminal .xterm-color-135 { color: #af5fff; } .terminal .xterm-bg-color-135 { background-color: #af5fff; } .terminal .xterm-color-136 { color: #af8700; } .terminal .xterm-bg-color-136 { background-color: #af8700; } .terminal .xterm-color-137 { color: #af875f; } .terminal .xterm-bg-color-137 { background-color: #af875f; } .terminal .xterm-color-138 { color: #af8787; } .terminal .xterm-bg-color-138 { background-color: #af8787; } .terminal .xterm-color-139 { color: #af87af; } .terminal .xterm-bg-color-139 { background-color: #af87af; } .terminal .xterm-color-140 { color: #af87d7; } .terminal .xterm-bg-color-140 { background-color: #af87d7; } .terminal .xterm-color-141 { color: #af87ff; } .terminal .xterm-bg-color-141 { background-color: #af87ff; } .terminal .xterm-color-142 { color: #afaf00; } .terminal .xterm-bg-color-142 { background-color: #afaf00; } .terminal .xterm-color-143 { color: #afaf5f; } .terminal .xterm-bg-color-143 { background-color: #afaf5f; } .terminal .xterm-color-144 { color: #afaf87; } .terminal .xterm-bg-color-144 { background-color: #afaf87; } .terminal .xterm-color-145 { color: #afafaf; } .terminal .xterm-bg-color-145 { background-color: #afafaf; } .terminal .xterm-color-146 { color: #afafd7; } .terminal .xterm-bg-color-146 { background-color: #afafd7; } .terminal .xterm-color-147 { color: #afafff; } .terminal .xterm-bg-color-147 { background-color: #afafff; } .terminal .xterm-color-148 { color: #afd700; } .terminal .xterm-bg-color-148 { background-color: #afd700; } .terminal .xterm-color-149 { color: #afd75f; } .terminal .xterm-bg-color-149 { background-color: #afd75f; } .terminal .xterm-color-150 { color: #afd787; } .terminal .xterm-bg-color-150 { background-color: #afd787; } .terminal .xterm-color-151 { color: #afd7af; } .terminal .xterm-bg-color-151 { background-color: #afd7af; } .terminal .xterm-color-152 { color: #afd7d7; } .terminal .xterm-bg-color-152 { background-color: #afd7d7; } .terminal .xterm-color-153 { color: #afd7ff; } .terminal .xterm-bg-color-153 { background-color: #afd7ff; } .terminal .xterm-color-154 { color: #afff00; } .terminal .xterm-bg-color-154 { background-color: #afff00; } .terminal .xterm-color-155 { color: #afff5f; } .terminal .xterm-bg-color-155 { background-color: #afff5f; } .terminal .xterm-color-156 { color: #afff87; } .terminal .xterm-bg-color-156 { background-color: #afff87; } .terminal .xterm-color-157 { color: #afffaf; } .terminal .xterm-bg-color-157 { background-color: #afffaf; } .terminal .xterm-color-158 { color: #afffd7; } .terminal .xterm-bg-color-158 { background-color: #afffd7; } .terminal .xterm-color-159 { color: #afffff; } .terminal .xterm-bg-color-159 { background-color: #afffff; } .terminal .xterm-color-160 { color: #d70000; } .terminal .xterm-bg-color-160 { background-color: #d70000; } .terminal .xterm-color-161 { color: #d7005f; } .terminal .xterm-bg-color-161 { background-color: #d7005f; } .terminal .xterm-color-162 { color: #d70087; } .terminal .xterm-bg-color-162 { background-color: #d70087; } .terminal .xterm-color-163 { color: #d700af; } .terminal .xterm-bg-color-163 { background-color: #d700af; } .terminal .xterm-color-164 { color: #d700d7; } .terminal .xterm-bg-color-164 { background-color: #d700d7; } .terminal .xterm-color-165 { color: #d700ff; } .terminal .xterm-bg-color-165 { background-color: #d700ff; } .terminal .xterm-color-166 { color: #d75f00; } .terminal .xterm-bg-color-166 { background-color: #d75f00; } .terminal .xterm-color-167 { color: #d75f5f; } .terminal .xterm-bg-color-167 { background-color: #d75f5f; } .terminal .xterm-color-168 { color: #d75f87; } .terminal .xterm-bg-color-168 { background-color: #d75f87; } .terminal .xterm-color-169 { color: #d75faf; } .terminal .xterm-bg-color-169 { background-color: #d75faf; } .terminal .xterm-color-170 { color: #d75fd7; } .terminal .xterm-bg-color-170 { background-color: #d75fd7; } .terminal .xterm-color-171 { color: #d75fff; } .terminal .xterm-bg-color-171 { background-color: #d75fff; } .terminal .xterm-color-172 { color: #d78700; } .terminal .xterm-bg-color-172 { background-color: #d78700; } .terminal .xterm-color-173 { color: #d7875f; } .terminal .xterm-bg-color-173 { background-color: #d7875f; } .terminal .xterm-color-174 { color: #d78787; } .terminal .xterm-bg-color-174 { background-color: #d78787; } .terminal .xterm-color-175 { color: #d787af; } .terminal .xterm-bg-color-175 { background-color: #d787af; } .terminal .xterm-color-176 { color: #d787d7; } .terminal .xterm-bg-color-176 { background-color: #d787d7; } .terminal .xterm-color-177 { color: #d787ff; } .terminal .xterm-bg-color-177 { background-color: #d787ff; } .terminal .xterm-color-178 { color: #d7af00; } .terminal .xterm-bg-color-178 { background-color: #d7af00; } .terminal .xterm-color-179 { color: #d7af5f; } .terminal .xterm-bg-color-179 { background-color: #d7af5f; } .terminal .xterm-color-180 { color: #d7af87; } .terminal .xterm-bg-color-180 { background-color: #d7af87; } .terminal .xterm-color-181 { color: #d7afaf; } .terminal .xterm-bg-color-181 { background-color: #d7afaf; } .terminal .xterm-color-182 { color: #d7afd7; } .terminal .xterm-bg-color-182 { background-color: #d7afd7; } .terminal .xterm-color-183 { color: #d7afff; } .terminal .xterm-bg-color-183 { background-color: #d7afff; } .terminal .xterm-color-184 { color: #d7d700; } .terminal .xterm-bg-color-184 { background-color: #d7d700; } .terminal .xterm-color-185 { color: #d7d75f; } .terminal .xterm-bg-color-185 { background-color: #d7d75f; } .terminal .xterm-color-186 { color: #d7d787; } .terminal .xterm-bg-color-186 { background-color: #d7d787; } .terminal .xterm-color-187 { color: #d7d7af; } .terminal .xterm-bg-color-187 { background-color: #d7d7af; } .terminal .xterm-color-188 { color: #d7d7d7; } .terminal .xterm-bg-color-188 { background-color: #d7d7d7; } .terminal .xterm-color-189 { color: #d7d7ff; } .terminal .xterm-bg-color-189 { background-color: #d7d7ff; } .terminal .xterm-color-190 { color: #d7ff00; } .terminal .xterm-bg-color-190 { background-color: #d7ff00; } .terminal .xterm-color-191 { color: #d7ff5f; } .terminal .xterm-bg-color-191 { background-color: #d7ff5f; } .terminal .xterm-color-192 { color: #d7ff87; } .terminal .xterm-bg-color-192 { background-color: #d7ff87; } .terminal .xterm-color-193 { color: #d7ffaf; } .terminal .xterm-bg-color-193 { background-color: #d7ffaf; } .terminal .xterm-color-194 { color: #d7ffd7; } .terminal .xterm-bg-color-194 { background-color: #d7ffd7; } .terminal .xterm-color-195 { color: #d7ffff; } .terminal .xterm-bg-color-195 { background-color: #d7ffff; } .terminal .xterm-color-196 { color: #ff0000; } .terminal .xterm-bg-color-196 { background-color: #ff0000; } .terminal .xterm-color-197 { color: #ff005f; } .terminal .xterm-bg-color-197 { background-color: #ff005f; } .terminal .xterm-color-198 { color: #ff0087; } .terminal .xterm-bg-color-198 { background-color: #ff0087; } .terminal .xterm-color-199 { color: #ff00af; } .terminal .xterm-bg-color-199 { background-color: #ff00af; } .terminal .xterm-color-200 { color: #ff00d7; } .terminal .xterm-bg-color-200 { background-color: #ff00d7; } .terminal .xterm-color-201 { color: #ff00ff; } .terminal .xterm-bg-color-201 { background-color: #ff00ff; } .terminal .xterm-color-202 { color: #ff5f00; } .terminal .xterm-bg-color-202 { background-color: #ff5f00; } .terminal .xterm-color-203 { color: #ff5f5f; } .terminal .xterm-bg-color-203 { background-color: #ff5f5f; } .terminal .xterm-color-204 { color: #ff5f87; } .terminal .xterm-bg-color-204 { background-color: #ff5f87; } .terminal .xterm-color-205 { color: #ff5faf; } .terminal .xterm-bg-color-205 { background-color: #ff5faf; } .terminal .xterm-color-206 { color: #ff5fd7; } .terminal .xterm-bg-color-206 { background-color: #ff5fd7; } .terminal .xterm-color-207 { color: #ff5fff; } .terminal .xterm-bg-color-207 { background-color: #ff5fff; } .terminal .xterm-color-208 { color: #ff8700; } .terminal .xterm-bg-color-208 { background-color: #ff8700; } .terminal .xterm-color-209 { color: #ff875f; } .terminal .xterm-bg-color-209 { background-color: #ff875f; } .terminal .xterm-color-210 { color: #ff8787; } .terminal .xterm-bg-color-210 { background-color: #ff8787; } .terminal .xterm-color-211 { color: #ff87af; } .terminal .xterm-bg-color-211 { background-color: #ff87af; } .terminal .xterm-color-212 { color: #ff87d7; } .terminal .xterm-bg-color-212 { background-color: #ff87d7; } .terminal .xterm-color-213 { color: #ff87ff; } .terminal .xterm-bg-color-213 { background-color: #ff87ff; } .terminal .xterm-color-214 { color: #ffaf00; } .terminal .xterm-bg-color-214 { background-color: #ffaf00; } .terminal .xterm-color-215 { color: #ffaf5f; } .terminal .xterm-bg-color-215 { background-color: #ffaf5f; } .terminal .xterm-color-216 { color: #ffaf87; } .terminal .xterm-bg-color-216 { background-color: #ffaf87; } .terminal .xterm-color-217 { color: #ffafaf; } .terminal .xterm-bg-color-217 { background-color: #ffafaf; } .terminal .xterm-color-218 { color: #ffafd7; } .terminal .xterm-bg-color-218 { background-color: #ffafd7; } .terminal .xterm-color-219 { color: #ffafff; } .terminal .xterm-bg-color-219 { background-color: #ffafff; } .terminal .xterm-color-220 { color: #ffd700; } .terminal .xterm-bg-color-220 { background-color: #ffd700; } .terminal .xterm-color-221 { color: #ffd75f; } .terminal .xterm-bg-color-221 { background-color: #ffd75f; } .terminal .xterm-color-222 { color: #ffd787; } .terminal .xterm-bg-color-222 { background-color: #ffd787; } .terminal .xterm-color-223 { color: #ffd7af; } .terminal .xterm-bg-color-223 { background-color: #ffd7af; } .terminal .xterm-color-224 { color: #ffd7d7; } .terminal .xterm-bg-color-224 { background-color: #ffd7d7; } .terminal .xterm-color-225 { color: #ffd7ff; } .terminal .xterm-bg-color-225 { background-color: #ffd7ff; } .terminal .xterm-color-226 { color: #ffff00; } .terminal .xterm-bg-color-226 { background-color: #ffff00; } .terminal .xterm-color-227 { color: #ffff5f; } .terminal .xterm-bg-color-227 { background-color: #ffff5f; } .terminal .xterm-color-228 { color: #ffff87; } .terminal .xterm-bg-color-228 { background-color: #ffff87; } .terminal .xterm-color-229 { color: #ffffaf; } .terminal .xterm-bg-color-229 { background-color: #ffffaf; } .terminal .xterm-color-230 { color: #ffffd7; } .terminal .xterm-bg-color-230 { background-color: #ffffd7; } .terminal .xterm-color-231 { color: #ffffff; } .terminal .xterm-bg-color-231 { background-color: #ffffff; } .terminal .xterm-color-232 { color: #080808; } .terminal .xterm-bg-color-232 { background-color: #080808; } .terminal .xterm-color-233 { color: #121212; } .terminal .xterm-bg-color-233 { background-color: #121212; } .terminal .xterm-color-234 { color: #1c1c1c; } .terminal .xterm-bg-color-234 { background-color: #1c1c1c; } .terminal .xterm-color-235 { color: #262626; } .terminal .xterm-bg-color-235 { background-color: #262626; } .terminal .xterm-color-236 { color: #303030; } .terminal .xterm-bg-color-236 { background-color: #303030; } .terminal .xterm-color-237 { color: #3a3a3a; } .terminal .xterm-bg-color-237 { background-color: #3a3a3a; } .terminal .xterm-color-238 { color: #444444; } .terminal .xterm-bg-color-238 { background-color: #444444; } .terminal .xterm-color-239 { color: #4e4e4e; } .terminal .xterm-bg-color-239 { background-color: #4e4e4e; } .terminal .xterm-color-240 { color: #585858; } .terminal .xterm-bg-color-240 { background-color: #585858; } .terminal .xterm-color-241 { color: #626262; } .terminal .xterm-bg-color-241 { background-color: #626262; } .terminal .xterm-color-242 { color: #6c6c6c; } .terminal .xterm-bg-color-242 { background-color: #6c6c6c; } .terminal .xterm-color-243 { color: #767676; } .terminal .xterm-bg-color-243 { background-color: #767676; } .terminal .xterm-color-244 { color: #808080; } .terminal .xterm-bg-color-244 { background-color: #808080; } .terminal .xterm-color-245 { color: #8a8a8a; } .terminal .xterm-bg-color-245 { background-color: #8a8a8a; } .terminal .xterm-color-246 { color: #949494; } .terminal .xterm-bg-color-246 { background-color: #949494; } .terminal .xterm-color-247 { color: #9e9e9e; } .terminal .xterm-bg-color-247 { background-color: #9e9e9e; } .terminal .xterm-color-248 { color: #a8a8a8; } .terminal .xterm-bg-color-248 { background-color: #a8a8a8; } .terminal .xterm-color-249 { color: #b2b2b2; } .terminal .xterm-bg-color-249 { background-color: #b2b2b2; } .terminal .xterm-color-250 { color: #bcbcbc; } .terminal .xterm-bg-color-250 { background-color: #bcbcbc; } .terminal .xterm-color-251 { color: #c6c6c6; } .terminal .xterm-bg-color-251 { background-color: #c6c6c6; } .terminal .xterm-color-252 { color: #d0d0d0; } .terminal .xterm-bg-color-252 { background-color: #d0d0d0; } .terminal .xterm-color-253 { color: #dadada; } .terminal .xterm-bg-color-253 { background-color: #dadada; } .terminal .xterm-color-254 { color: #e4e4e4; } .terminal .xterm-bg-color-254 { background-color: #e4e4e4; } .terminal .xterm-color-255 { color: #eeeeee; } .terminal .xterm-bg-color-255 { background-color: #eeeeee; } xterm.js-2.7.0/src/xterm.js000066400000000000000000001672461311554223300155750ustar00rootroot00000000000000/** * xterm.js: xterm, in the browser * Originally forked from (with the author's permission): * Fabrice Bellard's javascript vt100 for jslinux: * http://bellard.org/jslinux/ * Copyright (c) 2011 Fabrice Bellard * The original design remains. The terminal itself * has been extended to include xterm CSI codes, among * other features. * @license MIT */ import { CompositionHelper } from './CompositionHelper'; import { EventEmitter } from './EventEmitter'; import { Viewport } from './Viewport'; import { rightClickHandler, pasteHandler, copyHandler } from './handlers/Clipboard'; import { CircularList } from './utils/CircularList'; import { C0 } from './EscapeSequences'; import { InputHandler } from './InputHandler'; import { Parser } from './Parser'; import { Renderer } from './Renderer'; import { Linkifier } from './Linkifier'; import { CharMeasure } from './utils/CharMeasure'; import * as Browser from './utils/Browser'; import * as Keyboard from './utils/Keyboard'; import { CHARSETS } from './Charsets'; import { getRawByteCoords } from './utils/Mouse'; /** * Terminal Emulation References: * http://vt100.net/ * http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html * http://invisible-island.net/vttest/ * http://www.inwap.com/pdp10/ansicode.txt * http://linux.die.net/man/4/console_codes * http://linux.die.net/man/7/urxvt */ // Let it work inside Node.js for automated testing purposes. var document = (typeof window != 'undefined') ? window.document : null; /** * The amount of write requests to queue before sending an XOFF signal to the * pty process. This number must be small in order for ^C and similar sequences * to be responsive. */ var WRITE_BUFFER_PAUSE_THRESHOLD = 5; /** * The number of writes to perform in a single batch before allowing the * renderer to catch up with a 0ms setTimeout. */ var WRITE_BATCH_SIZE = 300; /** * The time between cursor blinks. This is driven by JS rather than a CSS * animation due to a bug in Chromium that causes it to use excessive CPU time. * See https://github.com/Microsoft/vscode/issues/22900 */ var CURSOR_BLINK_INTERVAL = 600; /** * Terminal */ /** * Creates a new `Terminal` object. * * @param {object} options An object containing a set of options, the available options are: * - `cursorBlink` (boolean): Whether the terminal cursor blinks * - `cols` (number): The number of columns of the terminal (horizontal size) * - `rows` (number): The number of rows of the terminal (vertical size) * * @public * @class Xterm Xterm * @alias module:xterm/src/xterm */ function Terminal(options) { var self = this; if (!(this instanceof Terminal)) { return new Terminal(arguments[0], arguments[1], arguments[2]); } self.browser = Browser; self.cancel = Terminal.cancel; EventEmitter.call(this); if (typeof options === 'number') { options = { cols: arguments[0], rows: arguments[1], handler: arguments[2] }; } options = options || {}; Object.keys(Terminal.defaults).forEach(function(key) { if (options[key] == null) { options[key] = Terminal.options[key]; if (Terminal[key] !== Terminal.defaults[key]) { options[key] = Terminal[key]; } } self[key] = options[key]; }); if (options.colors.length === 8) { options.colors = options.colors.concat(Terminal._colors.slice(8)); } else if (options.colors.length === 16) { options.colors = options.colors.concat(Terminal._colors.slice(16)); } else if (options.colors.length === 10) { options.colors = options.colors.slice(0, -2).concat( Terminal._colors.slice(8, -2), options.colors.slice(-2)); } else if (options.colors.length === 18) { options.colors = options.colors.concat( Terminal._colors.slice(16, -2), options.colors.slice(-2)); } this.colors = options.colors; this.options = options; // this.context = options.context || window; // this.document = options.document || document; this.parent = options.body || options.parent || ( document ? document.getElementsByTagName('body')[0] : null ); this.cols = options.cols || options.geometry[0]; this.rows = options.rows || options.geometry[1]; this.geometry = [this.cols, this.rows]; if (options.handler) { 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.customKeydownHandler = null; this.cursorBlinkInterval = null; // modes this.applicationKeypad = false; this.applicationCursor = false; this.originMode = false; this.insertMode = false; this.wraparoundMode = true; // defaults: xterm - true, vt100 - false this.normal = null; // charset this.charset = null; this.gcharset = null; this.glevel = 0; this.charsets = [null]; // mouse properties this.decLocator; this.x10Mouse; this.vt200Mouse; this.vt300Mouse; this.normalMouse; this.mouseEvents; this.sendFocus; this.utfMouse; this.sgrMouse; this.urxvtMouse; // misc this.element; this.children; this.refreshStart; this.refreshEnd; this.savedX; this.savedY; this.savedCols; // stream this.readable = true; this.writable = true; this.defAttr = (0 << 18) | (257 << 9) | (256 << 0); this.curAttr = this.defAttr; this.params = []; this.currentParam = 0; this.prefix = ''; this.postfix = ''; this.inputHandler = new InputHandler(this); this.parser = new Parser(this.inputHandler, this); // Reuse renderer if the Terminal is being recreated via a Terminal.reset call. this.renderer = this.renderer || null; this.linkifier = this.linkifier || new Linkifier(); // user input states this.writeBuffer = []; this.writeInProgress = false; /** * Whether _xterm.js_ sent XOFF in order to catch up with the pty process. * This is a distinct state from writeStopped so that if the user requested * XOFF via ^S that it will not automatically resume when the writeBuffer goes * below threshold. */ this.xoffSentToCatchUp = false; /** Whether writing has been stopped as a result of XOFF */ this.writeStopped = false; // 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); var i = this.rows; while (i--) { this.lines.push(this.blankLine()); } this.tabs; this.setupStops(); // Store if user went browsing history in scrollback this.userScrolling = false; } inherits(Terminal, EventEmitter); /** * back_color_erase feature for xterm. */ Terminal.prototype.eraseAttr = function() { // if (this.is('screen')) return this.defAttr; return (this.defAttr & ~0x1ff) | (this.curAttr & 0x1ff); }; /** * Colors */ // Colors 0-15 Terminal.tangoColors = [ // dark: '#2e3436', '#cc0000', '#4e9a06', '#c4a000', '#3465a4', '#75507b', '#06989a', '#d3d7cf', // bright: '#555753', '#ef2929', '#8ae234', '#fce94f', '#729fcf', '#ad7fa8', '#34e2e2', '#eeeeec' ]; // Colors 0-15 + 16-255 // Much thanks to TooTallNate for writing this. Terminal.colors = (function() { var colors = Terminal.tangoColors.slice() , r = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff] , i; // 16-231 i = 0; for (; i < 216; i++) { out(r[(i / 36) % 6 | 0], r[(i / 6) % 6 | 0], r[i % 6]); } // 232-255 (grey) i = 0; for (; i < 24; i++) { r = 8 + i * 10; out(r, r, r); } function out(r, g, b) { colors.push('#' + hex(r) + hex(g) + hex(b)); } function hex(c) { c = c.toString(16); return c.length < 2 ? '0' + c : c; } return colors; })(); Terminal._colors = Terminal.colors.slice(); Terminal.vcolors = (function() { var out = [] , colors = Terminal.colors , i = 0 , color; for (; i < 256; i++) { color = parseInt(colors[i].substring(1), 16); out.push([ (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff ]); } return out; })(); /** * Options */ Terminal.defaults = { colors: Terminal.colors, theme: 'default', convertEol: false, termName: 'xterm', geometry: [80, 24], cursorBlink: false, cursorStyle: 'block', visualBell: false, popOnBell: false, scrollback: 1000, screenKeys: false, debug: false, cancelEvents: false, disableStdin: false, useFlowControl: false, tabStopWidth: 8 // programFeatures: false, // focusKeys: false, }; Terminal.options = {}; Terminal.focus = null; each(keys(Terminal.defaults), function(key) { Terminal[key] = Terminal.defaults[key]; Terminal.options[key] = Terminal.defaults[key]; }); /** * Focus the terminal. Delegates focus handling to the terminal's DOM element. */ Terminal.prototype.focus = function() { return this.textarea.focus(); }; /** * Retrieves an option's value from the terminal. * @param {string} key The option key. */ Terminal.prototype.getOption = function(key, value) { if (!(key in Terminal.defaults)) { throw new Error('No option with key "' + key + '"'); } if (typeof this.options[key] !== 'undefined') { return this.options[key]; } return this[key]; }; /** * Sets an option on the terminal. * @param {string} key The option key. * @param {string} value The option value. */ Terminal.prototype.setOption = function(key, value) { if (!(key in Terminal.defaults)) { throw new Error('No option with key "' + key + '"'); } switch (key) { case 'scrollback': if (this.options[key] !== value) { if (this.lines.length > value) { const amountToTrim = this.lines.length - value; const needsRefresh = (this.ydisp - amountToTrim < 0); this.lines.trimStart(amountToTrim); this.ybase = Math.max(this.ybase - amountToTrim, 0); this.ydisp = Math.max(this.ydisp - amountToTrim, 0); if (needsRefresh) { this.refresh(0, this.rows - 1); } } this.lines.maxLength = value; this.viewport.syncScrollArea(); } break; } this[key] = value; this.options[key] = value; switch (key) { case 'cursorBlink': this.setCursorBlinking(value); break; case 'cursorStyle': // Style 'block' applies with no class this.element.classList.toggle(`xterm-cursor-style-underline`, value === 'underline'); this.element.classList.toggle(`xterm-cursor-style-bar`, value === 'bar'); break; case 'tabStopWidth': this.setupStops(); break; } }; Terminal.prototype.restartCursorBlinking = function () { this.setCursorBlinking(this.options.cursorBlink); }; Terminal.prototype.setCursorBlinking = function (enabled) { this.element.classList.toggle('xterm-cursor-blink', enabled); this.clearCursorBlinkingInterval(); if (enabled) { var self = this; this.cursorBlinkInterval = setInterval(function () { self.element.classList.toggle('xterm-cursor-blink-on'); }, CURSOR_BLINK_INTERVAL); } }; Terminal.prototype.clearCursorBlinkingInterval = function () { this.element.classList.remove('xterm-cursor-blink-on'); if (this.cursorBlinkInterval) { clearInterval(this.cursorBlinkInterval); this.cursorBlinkInterval = null; } }; /** * Binds the desired focus behavior on a given terminal object. * * @static */ Terminal.bindFocus = function (term) { on(term.textarea, 'focus', function (ev) { if (term.sendFocus) { term.send(C0.ESC + '[I'); } term.element.classList.add('focus'); term.showCursor(); term.restartCursorBlinking.apply(term); Terminal.focus = term; term.emit('focus', {terminal: term}); }); }; /** * Blur the terminal. Delegates blur handling to the terminal's DOM element. */ Terminal.prototype.blur = function() { return this.textarea.blur(); }; /** * Binds the desired blur behavior on a given terminal object. * * @static */ Terminal.bindBlur = function (term) { on(term.textarea, 'blur', function (ev) { term.refresh(term.y, term.y); if (term.sendFocus) { term.send(C0.ESC + '[O'); } term.element.classList.remove('focus'); term.clearCursorBlinkingInterval.apply(term); Terminal.focus = null; term.emit('blur', {terminal: term}); }); }; /** * Initialize default behavior */ Terminal.prototype.initGlobal = function() { var term = this; Terminal.bindKeys(this); Terminal.bindFocus(this); Terminal.bindBlur(this); // Bind clipboard functionality on(this.element, 'copy', function (ev) { copyHandler.call(this, ev, term); }); on(this.textarea, 'paste', function (ev) { pasteHandler.call(this, ev, term); }); on(this.element, 'paste', function (ev) { pasteHandler.call(this, ev, term); }); function rightClickHandlerWrapper (ev) { rightClickHandler.call(this, ev, term); } if (term.browser.isFirefox) { on(this.element, 'mousedown', function (ev) { if (ev.button == 2) { rightClickHandlerWrapper(ev); } }); } else { on(this.element, 'contextmenu', rightClickHandlerWrapper); } }; /** * Apply key handling to the terminal */ Terminal.bindKeys = function(term) { on(term.element, 'keydown', function(ev) { if (document.activeElement != this) { return; } term.keyDown(ev); }, true); on(term.element, 'keypress', function(ev) { if (document.activeElement != this) { return; } term.keyPress(ev); }, true); on(term.element, 'keyup', function(ev) { if (!wasMondifierKeyOnlyEvent(ev)) { term.focus(term); } }, true); on(term.textarea, 'keydown', function(ev) { term.keyDown(ev); }, true); on(term.textarea, 'keypress', function(ev) { term.keyPress(ev); // Truncate the textarea's value, since it is not needed this.value = ''; }, true); on(term.textarea, 'compositionstart', term.compositionHelper.compositionstart.bind(term.compositionHelper)); on(term.textarea, 'compositionupdate', term.compositionHelper.compositionupdate.bind(term.compositionHelper)); on(term.textarea, 'compositionend', term.compositionHelper.compositionend.bind(term.compositionHelper)); term.on('refresh', term.compositionHelper.updateCompositionElements.bind(term.compositionHelper)); term.on('refresh', function (data) { term.queueLinkification(data.start, data.end) }); }; /** * Insert the given row to the terminal or produce a new one * if no row argument is passed. Return the inserted row. * @param {HTMLElement} row (optional) The row to append to the terminal. */ Terminal.prototype.insertRow = function (row) { if (typeof row != 'object') { row = document.createElement('div'); } this.rowContainer.appendChild(row); this.children.push(row); return row; }; /** * Opens the terminal within an element. * * @param {HTMLElement} parent The element to create the terminal within. * @param {boolean} focus Focus the terminal, after it gets instantiated in the DOM */ Terminal.prototype.open = function(parent, focus) { var self=this, i=0, div; this.parent = parent || this.parent; if (!this.parent) { throw new Error('Terminal requires a parent element.'); } // Grab global elements this.context = this.parent.ownerDocument.defaultView; this.document = this.parent.ownerDocument; this.body = this.document.getElementsByTagName('body')[0]; //Create main element container this.element = this.document.createElement('div'); this.element.classList.add('terminal'); this.element.classList.add('xterm'); this.element.classList.add('xterm-theme-' + this.theme); this.setCursorBlinking(this.options.cursorBlink); this.element.style.height; this.element.setAttribute('tabindex', 0); this.viewportElement = document.createElement('div'); this.viewportElement.classList.add('xterm-viewport'); this.element.appendChild(this.viewportElement); this.viewportScrollArea = document.createElement('div'); this.viewportScrollArea.classList.add('xterm-scroll-area'); this.viewportElement.appendChild(this.viewportScrollArea); // Create the container that will hold the lines of the terminal and then // produce the lines the lines. this.rowContainer = document.createElement('div'); this.rowContainer.classList.add('xterm-rows'); this.element.appendChild(this.rowContainer); this.children = []; this.linkifier.attachToDom(document, this.children); // Create the container that will hold helpers like the textarea for // capturing DOM Events. Then produce the helpers. this.helperContainer = document.createElement('div'); this.helperContainer.classList.add('xterm-helpers'); // TODO: This should probably be inserted once it's filled to prevent an additional layout this.element.appendChild(this.helperContainer); this.textarea = document.createElement('textarea'); this.textarea.classList.add('xterm-helper-textarea'); this.textarea.setAttribute('autocorrect', 'off'); this.textarea.setAttribute('autocapitalize', 'off'); this.textarea.setAttribute('spellcheck', 'false'); this.textarea.tabIndex = 0; this.textarea.addEventListener('focus', function() { self.emit('focus', {terminal: self}); }); this.textarea.addEventListener('blur', function() { self.emit('blur', {terminal: self}); }); this.helperContainer.appendChild(this.textarea); this.compositionView = document.createElement('div'); this.compositionView.classList.add('composition-view'); this.compositionHelper = new CompositionHelper(this.textarea, this.compositionView, this); this.helperContainer.appendChild(this.compositionView); this.charSizeStyleElement = document.createElement('style'); this.helperContainer.appendChild(this.charSizeStyleElement); for (; i < this.rows; i++) { this.insertRow(); } this.parent.appendChild(this.element); this.charMeasure = new CharMeasure(document, this.helperContainer); this.charMeasure.on('charsizechanged', function () { self.updateCharSizeCSS(); }); this.charMeasure.measure(); this.viewport = new Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasure); this.renderer = new Renderer(this); // Setup loop that draws to screen this.refresh(0, this.rows - 1); // Initialize global actions that // need to be taken on the document. this.initGlobal(); /** * Automatic focus functionality. * TODO: Default to `false` starting with xterm.js 3.0. */ if (typeof focus == 'undefined') { let message = 'You did not pass the `focus` argument in `Terminal.prototype.open()`.\n'; message += 'The `focus` argument now defaults to `true` but starting with xterm.js 3.0 '; message += 'it will default to `false`.'; console.warn(message); focus = true; } if (focus) { this.focus(); } on(this.element, 'click', function() { var selection = document.getSelection(), collapsed = selection.isCollapsed, isRange = typeof collapsed == 'boolean' ? !collapsed : selection.type == 'Range'; if (!isRange) { self.focus(); } }); // Listen for mouse events and translate // them into terminal mouse protocols. this.bindMouse(); /** * This event is emitted when terminal has completed opening. * * @event open */ this.emit('open'); }; /** * Attempts to load an add-on using CommonJS or RequireJS (whichever is available). * @param {string} addon The name of the addon to load * @static */ Terminal.loadAddon = function(addon, callback) { if (typeof exports === 'object' && typeof module === 'object') { // CommonJS return require('./addons/' + addon + '/' + addon); } else if (typeof define == 'function') { // RequireJS return require(['./addons/' + addon + '/' + addon], callback); } else { console.error('Cannot load a module without a CommonJS or RequireJS environment.'); return false; } }; /** * Updates the helper CSS class with any changes necessary after the terminal's * character width has been changed. */ Terminal.prototype.updateCharSizeCSS = function() { this.charSizeStyleElement.textContent = `.xterm-wide-char{width:${this.charMeasure.width * 2}px;}` + `.xterm-normal-char{width:${this.charMeasure.width}px;}` } /** * XTerm mouse events * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking * To better understand these * the xterm code is very helpful: * Relevant files: * button.c, charproc.c, misc.c * Relevant functions in xterm/button.c: * BtnCode, EmitButtonCode, EditorButton, SendMousePosition */ Terminal.prototype.bindMouse = function() { var el = this.element, self = this, pressed = 32; // mouseup, mousedown, wheel // left click: ^[[M 3<^[[M#3< // wheel up: ^[[M`3> function sendButton(ev) { var button , pos; // get the xterm-style button button = getButton(ev); // get mouse coordinates pos = getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows); if (!pos) return; sendEvent(button, pos); switch (ev.overrideType || ev.type) { case 'mousedown': pressed = button; break; case 'mouseup': // keep it at the left // button, just in case. pressed = 32; break; case 'wheel': // nothing. don't // interfere with // `pressed`. break; } } // motion example of a left click: // ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7< function sendMove(ev) { var button = pressed , pos; pos = getRawByteCoords(ev, self.rowContainer, self.charMeasure, self.cols, self.rows); if (!pos) return; // buttons marked as motions // are incremented by 32 button += 32; sendEvent(button, pos); } // encode button and // position to characters function encode(data, ch) { if (!self.utfMouse) { if (ch === 255) return data.push(0); if (ch > 127) ch = 127; data.push(ch); } else { if (ch === 2047) return data.push(0); if (ch < 127) { data.push(ch); } else { if (ch > 2047) ch = 2047; data.push(0xC0 | (ch >> 6)); data.push(0x80 | (ch & 0x3F)); } } } // send a mouse event: // regular/utf8: ^[[M Cb Cx Cy // urxvt: ^[[ Cb ; Cx ; Cy M // sgr: ^[[ Cb ; Cx ; Cy M/m // vt300: ^[[ 24(1/3/5)~ [ Cx , Cy ] \r // locator: CSI P e ; P b ; P r ; P c ; P p & w function sendEvent(button, pos) { // self.emit('mouse', { // x: pos.x - 32, // y: pos.x - 32, // button: button // }); if (self.vt300Mouse) { // NOTE: Unstable. // http://www.vt100.net/docs/vt3xx-gp/chapter15.html button &= 3; pos.x -= 32; pos.y -= 32; var data = C0.ESC + '[24'; if (button === 0) data += '1'; else if (button === 1) data += '3'; else if (button === 2) data += '5'; else if (button === 3) return; else data += '0'; data += '~[' + pos.x + ',' + pos.y + ']\r'; self.send(data); return; } if (self.decLocator) { // NOTE: Unstable. button &= 3; pos.x -= 32; pos.y -= 32; if (button === 0) button = 2; else if (button === 1) button = 4; else if (button === 2) button = 6; else if (button === 3) button = 3; self.send(C0.ESC + '[' + button + ';' + (button === 3 ? 4 : 0) + ';' + pos.y + ';' + pos.x + ';' + (pos.page || 0) + '&w'); return; } if (self.urxvtMouse) { pos.x -= 32; pos.y -= 32; pos.x++; pos.y++; self.send(C0.ESC + '[' + button + ';' + pos.x + ';' + pos.y + 'M'); return; } if (self.sgrMouse) { pos.x -= 32; pos.y -= 32; self.send(C0.ESC + '[<' + (((button & 3) === 3 ? button & ~3 : button) - 32) + ';' + pos.x + ';' + pos.y + ((button & 3) === 3 ? 'm' : 'M')); return; } var data = []; encode(data, button); encode(data, pos.x); encode(data, pos.y); self.send(C0.ESC + '[M' + String.fromCharCode.apply(String, data)); } function getButton(ev) { var button , shift , meta , ctrl , mod; // two low bits: // 0 = left // 1 = middle // 2 = right // 3 = release // wheel up/down: // 1, and 2 - with 64 added switch (ev.overrideType || ev.type) { case 'mousedown': button = ev.button != null ? +ev.button : ev.which != null ? ev.which - 1 : null; if (self.browser.isMSIE) { button = button === 1 ? 0 : button === 4 ? 1 : button; } break; case 'mouseup': button = 3; break; case 'DOMMouseScroll': button = ev.detail < 0 ? 64 : 65; break; case 'wheel': button = ev.wheelDeltaY > 0 ? 64 : 65; break; } // next three bits are the modifiers: // 4 = shift, 8 = meta, 16 = control shift = ev.shiftKey ? 4 : 0; meta = ev.metaKey ? 8 : 0; ctrl = ev.ctrlKey ? 16 : 0; mod = shift | meta | ctrl; // no mods if (self.vt200Mouse) { // ctrl only mod &= ctrl; } else if (!self.normalMouse) { mod = 0; } // increment to SP button = (32 + (mod << 2)) + button; return button; } on(el, 'mousedown', function(ev) { if (!self.mouseEvents) return; // send the button sendButton(ev); // ensure focus self.focus(); // fix for odd bug //if (self.vt200Mouse && !self.normalMouse) { if (self.vt200Mouse) { ev.overrideType = 'mouseup'; sendButton(ev); return self.cancel(ev); } // bind events if (self.normalMouse) on(self.document, 'mousemove', sendMove); // x10 compatibility mode can't send button releases if (!self.x10Mouse) { on(self.document, 'mouseup', function up(ev) { sendButton(ev); if (self.normalMouse) off(self.document, 'mousemove', sendMove); off(self.document, 'mouseup', up); return self.cancel(ev); }); } return self.cancel(ev); }); //if (self.normalMouse) { // on(self.document, 'mousemove', sendMove); //} on(el, 'wheel', function(ev) { if (!self.mouseEvents) return; if (self.x10Mouse || self.vt300Mouse || self.decLocator) return; sendButton(ev); return self.cancel(ev); }); // allow wheel scrolling in // the shell for example on(el, 'wheel', function(ev) { if (self.mouseEvents) return; self.viewport.onWheel(ev); return self.cancel(ev); }); }; /** * Destroys the terminal. */ Terminal.prototype.destroy = function() { this.readable = false; this.writable = false; this._events = {}; this.handler = function() {}; this.write = function() {}; if (this.element && this.element.parentNode) { this.element.parentNode.removeChild(this.element); } //this.emit('close'); }; /** * Tells the renderer to refresh terminal content between two rows (inclusive) at the next * opportunity. * @param {number} start The row to start from (between 0 and this.rows - 1). * @param {number} end The row to end at (between start and this.rows - 1). */ Terminal.prototype.refresh = function(start, end) { if (this.renderer) { this.renderer.queueRefresh(start, end); } }; /** * Queues linkification for the specified rows. * @param {number} start The row to start from (between 0 and this.rows - 1). * @param {number} end The row to end at (between start and this.rows - 1). */ Terminal.prototype.queueLinkification = function(start, end) { if (this.linkifier) { for (let i = start; i <= end; i++) { this.linkifier.linkifyRow(i); } } } /** * Display the cursor element */ Terminal.prototype.showCursor = function() { if (!this.cursorState) { this.cursorState = 1; this.refresh(this.y, this.y); } }; /** * Scroll the terminal down 1 row, creating a blank line. */ Terminal.prototype.scroll = function() { 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--; } } this.ybase++; // TODO: Why is this done twice? if (!this.userScrolling) { this.ydisp = this.ybase; } // last line row = this.ybase + this.rows - 1; // subtract the bottom scroll region row -= this.rows - 1 - this.scrollBottom; if (row === this.lines.length) { // Optimization: pushing is faster than splicing when they amount to the same behavior this.lines.push(this.blankLine()); } else { // add our new line this.lines.splice(row, 0, this.blankLine()); } if (this.scrollTop !== 0) { if (this.ybase !== 0) { this.ybase--; if (!this.userScrolling) { this.ydisp = this.ybase; } } this.lines.splice(this.ybase + this.scrollTop, 1); } // this.maxRange(); this.updateRange(this.scrollTop); this.updateRange(this.scrollBottom); /** * This event is emitted whenever the terminal is scrolled. * The one parameter passed is the new y display position. * * @event scroll */ this.emit('scroll', this.ydisp); }; /** * Scroll the display of the terminal * @param {number} disp The number of lines to scroll down (negatives scroll up). * @param {boolean} suppressScrollEvent Don't emit the scroll event as scrollDisp. This is used * to avoid unwanted events being handled by the veiwport when the event was triggered from the * viewport originally. */ Terminal.prototype.scrollDisp = function(disp, suppressScrollEvent) { if (disp < 0) { this.userScrolling = true; } else if (disp + this.ydisp >= this.ybase) { this.userScrolling = false; } this.ydisp += disp; if (this.ydisp > this.ybase) { this.ydisp = this.ybase; } else if (this.ydisp < 0) { this.ydisp = 0; } if (!suppressScrollEvent) { this.emit('scroll', this.ydisp); } this.refresh(0, this.rows - 1); }; /** * Scroll the display of the terminal by a number of pages. * @param {number} pageCount The number of pages to scroll (negative scrolls up). */ Terminal.prototype.scrollPages = function(pageCount) { this.scrollDisp(pageCount * (this.rows - 1)); } /** * Scrolls the display of the terminal to the top. */ Terminal.prototype.scrollToTop = function() { this.scrollDisp(-this.ydisp); } /** * Scrolls the display of the terminal to the bottom. */ Terminal.prototype.scrollToBottom = function() { this.scrollDisp(this.ybase - this.ydisp); } /** * Writes text to the terminal. * @param {string} text The text to write to the terminal. */ Terminal.prototype.write = function(data) { this.writeBuffer.push(data); // Send XOFF to pause the pty process if the write buffer becomes too large so // xterm.js can catch up before more data is sent. This is necessary in order // to keep signals such as ^C responsive. if (this.options.useFlowControl && !this.xoffSentToCatchUp && this.writeBuffer.length >= WRITE_BUFFER_PAUSE_THRESHOLD) { // XOFF - stop pty pipe // XON will be triggered by emulator before processing data chunk this.send(C0.DC3); this.xoffSentToCatchUp = true; } if (!this.writeInProgress && this.writeBuffer.length > 0) { // Kick off a write which will write all data in sequence recursively this.writeInProgress = true; // Kick off an async innerWrite so more writes can come in while processing data var self = this; setTimeout(function () { self.innerWrite(); }); } } Terminal.prototype.innerWrite = function() { var writeBatch = this.writeBuffer.splice(0, WRITE_BATCH_SIZE); while (writeBatch.length > 0) { var data = writeBatch.shift(); var l = data.length, i = 0, j, cs, ch, code, low, ch_width, row; // If XOFF was sent in order to catch up with the pty process, resume it if // the writeBuffer is empty to allow more data to come in. if (this.xoffSentToCatchUp && writeBatch.length === 0 && this.writeBuffer.length === 0) { this.send(C0.DC1); this.xoffSentToCatchUp = false; } this.refreshStart = this.y; this.refreshEnd = this.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 // middle of parsing escape sequence in two chunks. For some reason the // state of the parser resets to 0 after exiting parser.parse. This change // just sets the state back based on the correct return statement. var state = this.parser.parse(data); this.parser.setState(state); this.updateRange(this.y); this.refresh(this.refreshStart, this.refreshEnd); } if (this.writeBuffer.length > 0) { // Allow renderer to catch up before processing the next batch var self = this; setTimeout(function () { self.innerWrite(); }, 0); } else { this.writeInProgress = false; } }; /** * Writes text to the terminal, followed by a break line character (\n). * @param {string} text The text to write to the terminal. */ Terminal.prototype.writeln = function(data) { this.write(data + '\r\n'); }; /** * Attaches a custom keydown handler which is run before keys are processed, giving consumers of * xterm.js ultimate control as to what keys should be processed by the terminal and what keys * should not. * @param {function} customKeydownHandler The custom KeyboardEvent handler to attach. This is a * function that takes a KeyboardEvent, allowing consumers to stop propogation and/or prevent * the default action. The function returns whether the event should be processed by xterm.js. */ Terminal.prototype.attachCustomKeydownHandler = function(customKeydownHandler) { this.customKeydownHandler = customKeydownHandler; } /** * Attaches a http(s) link handler, forcing web links to behave differently to * regular
tags. This will trigger a refresh as links potentially need to be * reconstructed. Calling this with null will remove the handler. * @param {LinkHandler} handler The handler callback function. */ Terminal.prototype.setHypertextLinkHandler = function(handler) { if (!this.linkifier) { throw new Error('Cannot attach a hypertext link handler before Terminal.open is called'); } this.linkifier.setHypertextLinkHandler(handler); // Refresh to force links to refresh this.refresh(0, this.rows - 1); } /** * Attaches a validation callback for hypertext links. This is useful to use * validation logic or to do something with the link's element and url. * @param {LinkMatcherValidationCallback} callback The callback to use, this can * be cleared with null. */ Terminal.prototype.setHypertextValidationCallback = function(handler) { if (!this.linkifier) { throw new Error('Cannot attach a hypertext validation callback before Terminal.open is called'); } this.linkifier.setHypertextValidationCallback(handler); // Refresh to force links to refresh this.refresh(0, this.rows - 1); } /** * Registers a link matcher, allowing custom link patterns to be matched and * handled. * @param {RegExp} regex The regular expression to search for, specifically * this searches the textContent of the rows. You will want to use \s to match * a space ' ' character for example. * @param {LinkHandler} handler The callback when the link is called. * @param {LinkMatcherOptions} [options] Options for the link matcher. * @return {number} The ID of the new matcher, this can be used to deregister. */ Terminal.prototype.registerLinkMatcher = function(regex, handler, options) { if (this.linkifier) { var matcherId = this.linkifier.registerLinkMatcher(regex, handler, options); this.refresh(0, this.rows - 1); return matcherId; } } /** * Deregisters a link matcher if it has been registered. * @param {number} matcherId The link matcher's ID (returned after register) */ Terminal.prototype.deregisterLinkMatcher = function(matcherId) { if (this.linkifier) { if (this.linkifier.deregisterLinkMatcher(matcherId)) { this.refresh(0, this.rows - 1); } } } /** * Handle a keydown event * Key Resources: * - https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent * @param {KeyboardEvent} ev The keydown event to be handled. */ Terminal.prototype.keyDown = function(ev) { if (this.customKeydownHandler && this.customKeydownHandler(ev) === false) { return false; } this.restartCursorBlinking(); if (!this.compositionHelper.keydown.bind(this.compositionHelper)(ev)) { if (this.ybase !== this.ydisp) { this.scrollToBottom(); } return false; } var self = this; var result = this.evaluateKeyEscapeSequence(ev); if (result.key === C0.DC3) { // XOFF this.writeStopped = true; } else if (result.key === C0.DC1) { // XON this.writeStopped = false; } if (result.scrollDisp) { this.scrollDisp(result.scrollDisp); return this.cancel(ev, true); } if (isThirdLevelShift(this, ev)) { return true; } if (result.cancel) { // The event is canceled at the end already, is this necessary? this.cancel(ev, true); } if (!result.key) { return true; } this.emit('keydown', ev); this.emit('key', result.key, ev); this.showCursor(); this.handler(result.key); return this.cancel(ev, true); }; /** * Returns an object that determines how a KeyboardEvent should be handled. The key of the * returned value is the new key code to pass to the PTY. * * Reference: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html * @param {KeyboardEvent} ev The keyboard event to be translated to key escape sequence. */ Terminal.prototype.evaluateKeyEscapeSequence = function(ev) { var result = { // Whether to cancel event propogation (NOTE: this may not be needed since the event is // canceled at the end of keyDown cancel: false, // The new key even to emit key: undefined, // The number of characters to scroll, if this is defined it will cancel the event scrollDisp: undefined }; var modifiers = ev.shiftKey << 0 | ev.altKey << 1 | ev.ctrlKey << 2 | ev.metaKey << 3; switch (ev.keyCode) { case 8: // backspace if (ev.shiftKey) { result.key = C0.BS; // ^H break; } result.key = C0.DEL; // ^? break; case 9: // tab if (ev.shiftKey) { result.key = C0.ESC + '[Z'; break; } result.key = C0.HT; result.cancel = true; break; case 13: // return/enter result.key = C0.CR; result.cancel = true; break; case 27: // escape result.key = C0.ESC; result.cancel = true; break; case 37: // left-arrow if (modifiers) { result.key = C0.ESC + '[1;' + (modifiers + 1) + 'D'; // HACK: Make Alt + left-arrow behave like Ctrl + left-arrow: move one word backwards // http://unix.stackexchange.com/a/108106 // macOS uses different escape sequences than linux if (result.key == C0.ESC + '[1;3D') { result.key = (this.browser.isMac) ? C0.ESC + 'b' : C0.ESC + '[1;5D'; } } else if (this.applicationCursor) { result.key = C0.ESC + 'OD'; } else { result.key = C0.ESC + '[D'; } break; case 39: // right-arrow if (modifiers) { result.key = C0.ESC + '[1;' + (modifiers + 1) + 'C'; // HACK: Make Alt + right-arrow behave like Ctrl + right-arrow: move one word forward // http://unix.stackexchange.com/a/108106 // macOS uses different escape sequences than linux if (result.key == C0.ESC + '[1;3C') { result.key = (this.browser.isMac) ? C0.ESC + 'f' : C0.ESC + '[1;5C'; } } else if (this.applicationCursor) { result.key = C0.ESC + 'OC'; } else { result.key = C0.ESC + '[C'; } break; case 38: // up-arrow if (modifiers) { result.key = C0.ESC + '[1;' + (modifiers + 1) + 'A'; // HACK: Make Alt + up-arrow behave like Ctrl + up-arrow // http://unix.stackexchange.com/a/108106 if (result.key == C0.ESC + '[1;3A') { result.key = C0.ESC + '[1;5A'; } } else if (this.applicationCursor) { result.key = C0.ESC + 'OA'; } else { result.key = C0.ESC + '[A'; } break; case 40: // down-arrow if (modifiers) { result.key = C0.ESC + '[1;' + (modifiers + 1) + 'B'; // HACK: Make Alt + down-arrow behave like Ctrl + down-arrow // http://unix.stackexchange.com/a/108106 if (result.key == C0.ESC + '[1;3B') { result.key = C0.ESC + '[1;5B'; } } else if (this.applicationCursor) { result.key = C0.ESC + 'OB'; } else { result.key = C0.ESC + '[B'; } break; case 45: // insert if (!ev.shiftKey && !ev.ctrlKey) { // or + are used to // copy-paste on some systems. result.key = C0.ESC + '[2~'; } break; case 46: // delete if (modifiers) { result.key = C0.ESC + '[3;' + (modifiers + 1) + '~'; } else { result.key = C0.ESC + '[3~'; } break; case 36: // home if (modifiers) result.key = C0.ESC + '[1;' + (modifiers + 1) + 'H'; else if (this.applicationCursor) result.key = C0.ESC + 'OH'; else result.key = C0.ESC + '[H'; break; case 35: // end if (modifiers) result.key = C0.ESC + '[1;' + (modifiers + 1) + 'F'; else if (this.applicationCursor) result.key = C0.ESC + 'OF'; else result.key = C0.ESC + '[F'; break; case 33: // page up if (ev.shiftKey) { result.scrollDisp = -(this.rows - 1); } else { result.key = C0.ESC + '[5~'; } break; case 34: // page down if (ev.shiftKey) { result.scrollDisp = this.rows - 1; } else { result.key = C0.ESC + '[6~'; } break; case 112: // F1-F12 if (modifiers) { result.key = C0.ESC + '[1;' + (modifiers + 1) + 'P'; } else { result.key = C0.ESC + 'OP'; } break; case 113: if (modifiers) { result.key = C0.ESC + '[1;' + (modifiers + 1) + 'Q'; } else { result.key = C0.ESC + 'OQ'; } break; case 114: if (modifiers) { result.key = C0.ESC + '[1;' + (modifiers + 1) + 'R'; } else { result.key = C0.ESC + 'OR'; } break; case 115: if (modifiers) { result.key = C0.ESC + '[1;' + (modifiers + 1) + 'S'; } else { result.key = C0.ESC + 'OS'; } break; case 116: if (modifiers) { result.key = C0.ESC + '[15;' + (modifiers + 1) + '~'; } else { result.key = C0.ESC + '[15~'; } break; case 117: if (modifiers) { result.key = C0.ESC + '[17;' + (modifiers + 1) + '~'; } else { result.key = C0.ESC + '[17~'; } break; case 118: if (modifiers) { result.key = C0.ESC + '[18;' + (modifiers + 1) + '~'; } else { result.key = C0.ESC + '[18~'; } break; case 119: if (modifiers) { result.key = C0.ESC + '[19;' + (modifiers + 1) + '~'; } else { result.key = C0.ESC + '[19~'; } break; case 120: if (modifiers) { result.key = C0.ESC + '[20;' + (modifiers + 1) + '~'; } else { result.key = C0.ESC + '[20~'; } break; case 121: if (modifiers) { result.key = C0.ESC + '[21;' + (modifiers + 1) + '~'; } else { result.key = C0.ESC + '[21~'; } break; case 122: if (modifiers) { result.key = C0.ESC + '[23;' + (modifiers + 1) + '~'; } else { result.key = C0.ESC + '[23~'; } break; case 123: if (modifiers) { result.key = C0.ESC + '[24;' + (modifiers + 1) + '~'; } else { result.key = C0.ESC + '[24~'; } break; default: // a-z and space if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) { if (ev.keyCode >= 65 && ev.keyCode <= 90) { result.key = String.fromCharCode(ev.keyCode - 64); } else if (ev.keyCode === 32) { // NUL result.key = String.fromCharCode(0); } else if (ev.keyCode >= 51 && ev.keyCode <= 55) { // escape, file sep, group sep, record sep, unit sep result.key = String.fromCharCode(ev.keyCode - 51 + 27); } else if (ev.keyCode === 56) { // delete result.key = String.fromCharCode(127); } else if (ev.keyCode === 219) { // ^[ - Control Sequence Introducer (CSI) result.key = String.fromCharCode(27); } else if (ev.keyCode === 220) { // ^\ - String Terminator (ST) result.key = String.fromCharCode(28); } else if (ev.keyCode === 221) { // ^] - Operating System Command (OSC) result.key = String.fromCharCode(29); } } else if (!this.browser.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) { // On Mac this is a third level shift. Use instead. if (ev.keyCode >= 65 && ev.keyCode <= 90) { result.key = C0.ESC + String.fromCharCode(ev.keyCode + 32); } else if (ev.keyCode === 192) { result.key = C0.ESC + '`'; } else if (ev.keyCode >= 48 && ev.keyCode <= 57) { result.key = C0.ESC + (ev.keyCode - 48); } } break; } return result; }; /** * Set the G level of the terminal * @param g */ Terminal.prototype.setgLevel = function(g) { this.glevel = g; this.charset = this.charsets[g]; }; /** * Set the charset for the given G level of the terminal * @param g * @param charset */ Terminal.prototype.setgCharset = function(g, charset) { this.charsets[g] = charset; if (this.glevel === g) { this.charset = charset; } }; /** * Handle a keypress event. * Key Resources: * - https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent * @param {KeyboardEvent} ev The keypress event to be handled. */ Terminal.prototype.keyPress = function(ev) { var key; this.cancel(ev); if (ev.charCode) { key = ev.charCode; } else if (ev.which == null) { key = ev.keyCode; } else if (ev.which !== 0 && ev.charCode !== 0) { key = ev.which; } else { return false; } if (!key || ( (ev.altKey || ev.ctrlKey || ev.metaKey) && !isThirdLevelShift(this, ev) )) { return false; } key = String.fromCharCode(key); this.emit('keypress', key, ev); this.emit('key', key, ev); this.showCursor(); this.handler(key); return false; }; /** * Send data for handling to the terminal * @param {string} data */ Terminal.prototype.send = function(data) { var self = this; if (!this.queue) { setTimeout(function() { self.handler(self.queue); self.queue = ''; }, 1); } this.queue += data; }; /** * Ring the bell. * Note: We could do sweet things with webaudio here */ Terminal.prototype.bell = function() { if (!this.visualBell) return; var self = this; this.element.style.borderColor = 'white'; setTimeout(function() { self.element.style.borderColor = ''; }, 10); if (this.popOnBell) this.focus(); }; /** * Log the current state to the console. */ Terminal.prototype.log = function() { if (!this.debug) return; if (!this.context.console || !this.context.console.log) return; var args = Array.prototype.slice.call(arguments); this.context.console.log.apply(this.context.console, args); }; /** * Log the current state as error to the console. */ Terminal.prototype.error = function() { if (!this.debug) return; if (!this.context.console || !this.context.console.error) return; var args = Array.prototype.slice.call(arguments); this.context.console.error.apply(this.context.console, args); }; /** * Resizes the terminal. * * @param {number} x The number of columns to resize to. * @param {number} y The number of rows to resize to. */ Terminal.prototype.resize = function(x, y) { if (isNaN(x) || isNaN(y)) { return; } var line , el , i , j , ch , addToY; if (x === this.cols && y === this.rows) { return; } if (x < 1) x = 1; if (y < 1) y = 1; // resize cols j = this.cols; if (j < x) { ch = [this.defAttr, ' ', 1]; // does xterm use the default attr? i = this.lines.length; while (i--) { while (this.lines.get(i).length < x) { this.lines.get(i).push(ch); } } } this.cols = x; this.setupStops(this.cols); // resize rows j = this.rows; addToY = 0; 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) { // There is room above the buffer and there are no empty elements below the line, // scroll up this.ybase--; addToY++ if (this.ydisp > 0) { // Viewport is at the top of the buffer, must increase downwards this.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()); } } if (this.children.length < y) { this.insertRow(); } } } else { // (j > y) while (j-- > y) { if (this.lines.length > y + this.ybase) { if (this.lines.length > this.ybase + this.y + 1) { // The line is a blank line below the cursor, remove it this.lines.pop(); } else { // The line is the cursor, scroll down this.ybase++; this.ydisp++; } } if (this.children.length > y) { el = this.children.shift(); if (!el) continue; el.parentNode.removeChild(el); } } } this.rows = y; // Make sure that the cursor stays on screen if (this.y >= y) { this.y = y - 1; } if (addToY) { this.y += addToY; } if (this.x >= x) { this.x = x - 1; } this.scrollTop = 0; this.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}); }; /** * Updates the range of rows to refresh * @param {number} y The number of rows to refresh next. */ Terminal.prototype.updateRange = function(y) { if (y < this.refreshStart) this.refreshStart = y; if (y > this.refreshEnd) this.refreshEnd = y; // if (y > this.refreshEnd) { // this.refreshEnd = y; // if (y > this.rows - 1) { // this.refreshEnd = this.rows - 1; // } // } }; /** * Set the range of refreshing to the maximum value */ Terminal.prototype.maxRange = function() { this.refreshStart = 0; this.refreshEnd = this.rows - 1; }; /** * Setup the tab stops. * @param {number} i */ Terminal.prototype.setupStops = function(i) { if (i != null) { if (!this.tabs[i]) { i = this.prevStop(i); } } else { this.tabs = {}; i = 0; } for (; i < this.cols; i += this.getOption('tabStopWidth')) { this.tabs[i] = true; } }; /** * Move the cursor to the previous tab stop from the given position (default is current). * @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); return x >= this.cols ? this.cols - 1 : x < 0 ? 0 : x; }; /** * Move the cursor one tab stop forward from the given position (default is current). * @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); return x >= this.cols ? this.cols - 1 : x < 0 ? 0 : x; }; /** * Erase in the identified line everything from "x" to the end of the line (right). * @param {number} x The column from which to start erasing to the end of the line. * @param {number} y The line in which to operate. */ Terminal.prototype.eraseRight = function(x, y) { var line = this.lines.get(this.ybase + y); if (!line) { return; } var ch = [this.eraseAttr(), ' ', 1]; // xterm for (; x < this.cols; x++) { line[x] = ch; } this.updateRange(y); }; /** * Erase in the identified line everything from "x" to the start of the line (left). * @param {number} x The column from which to start erasing to the start of the line. * @param {number} y The line in which to operate. */ Terminal.prototype.eraseLeft = function(x, y) { var line = this.lines.get(this.ybase + y); if (!line) { return; } var ch = [this.eraseAttr(), ' ', 1]; // xterm x++; while (x--) { line[x] = ch; } this.updateRange(y); }; /** * Clears the entire buffer, making the prompt line the new first line. */ Terminal.prototype.clear = function() { if (this.ybase === 0 && this.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; for (var i = 1; i < this.rows; i++) { this.lines.push(this.blankLine()); } this.refresh(0, this.rows - 1); this.emit('scroll', this.ydisp); }; /** * Erase all content in the given line * @param {number} y The line to erase all of its contents. */ Terminal.prototype.eraseLine = function(y) { this.eraseRight(0, y); }; /** * Return the data array of a blank line * @param {number} cur First bunch of data for each "blank" character. */ Terminal.prototype.blankLine = function(cur) { var attr = cur ? this.eraseAttr() : this.defAttr; var ch = [attr, ' ', 1] // width defaults to 1 halfwidth character , line = [] , i = 0; for (; i < this.cols; i++) { line[i] = ch; } return line; }; /** * If cur return the back color xterm feature attribute. Else return defAttr. * @param {object} cur */ Terminal.prototype.ch = function(cur) { return cur ? [this.eraseAttr(), ' ', 1] : [this.defAttr, ' ', 1]; }; /** * Evaluate if the current erminal is the given argument. * @param {object} term The terminal to evaluate */ Terminal.prototype.is = function(term) { var name = this.termName; return (name + '').indexOf(term) === 0; }; /** * Emit the 'data' event and populate the given data. * @param {string} data The data to populate in the event. */ Terminal.prototype.handler = function(data) { // Prevents all events to pty process if stdin is disabled if (this.options.disableStdin) { return; } // Input is being sent to the terminal, the terminal should focus the prompt. if (this.ybase !== this.ydisp) { this.scrollToBottom(); } this.emit('data', data); }; /** * Emit the 'title' event and populate the given title. * @param {string} title The title to populate in the event. */ Terminal.prototype.handleTitle = function(title) { /** * This event is emitted when the title of the terminal is changed * from inside the terminal. The parameter is the new title. * * @event title */ this.emit('title', title); }; /** * ESC */ /** * ESC D Index (IND is 0x84). */ Terminal.prototype.index = function() { this.y++; if (this.y > this.scrollBottom) { this.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--; } }; /** * ESC M Reverse Index (RI is 0x8d). * * Move the cursor up one row, inserting a new blank line if necessary. */ Terminal.prototype.reverseIndex = function() { var j; if (this.y === this.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); } else { this.y--; } }; /** * ESC c Full Reset (RIS). */ Terminal.prototype.reset = function() { this.options.rows = this.rows; this.options.cols = this.cols; var customKeydownHandler = this.customKeydownHandler; var cursorBlinkInterval = this.cursorBlinkInterval; Terminal.call(this, this.options); this.customKeydownHandler = customKeydownHandler; this.cursorBlinkInterval = cursorBlinkInterval; 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; }; /** * Helpers */ function on(el, type, handler, capture) { if (!Array.isArray(el)) { el = [el]; } el.forEach(function (element) { element.addEventListener(type, handler, capture || false); }); } function off(el, type, handler, capture) { el.removeEventListener(type, handler, capture || false); } function cancel(ev, force) { if (!this.cancelEvents && !force) { return; } ev.preventDefault(); ev.stopPropagation(); return false; } function inherits(child, parent) { function f() { this.constructor = child; } f.prototype = parent.prototype; child.prototype = new f; } function indexOf(obj, el) { var i = obj.length; while (i--) { if (obj[i] === el) return i; } return -1; } function isThirdLevelShift(term, ev) { var thirdLevelKey = (term.browser.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) || (term.browser.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey); if (ev.type == 'keypress') { return thirdLevelKey; } // Don't invoke for arrows, pageDown, home, backspace, etc. (on non-keypress events) return thirdLevelKey && (!ev.keyCode || ev.keyCode > 47); } // Expose to InputHandler (temporary) Terminal.prototype.matchColor = matchColor; function matchColor(r1, g1, b1) { var hash = (r1 << 16) | (g1 << 8) | b1; if (matchColor._cache[hash] != null) { return matchColor._cache[hash]; } var ldiff = Infinity , li = -1 , i = 0 , c , r2 , g2 , b2 , diff; for (; i < Terminal.vcolors.length; i++) { c = Terminal.vcolors[i]; r2 = c[0]; g2 = c[1]; b2 = c[2]; diff = matchColor.distance(r1, g1, b1, r2, g2, b2); if (diff === 0) { li = i; break; } if (diff < ldiff) { ldiff = diff; li = i; } } return matchColor._cache[hash] = li; } matchColor._cache = {}; // http://stackoverflow.com/questions/1633828 matchColor.distance = function(r1, g1, b1, r2, g2, b2) { return Math.pow(30 * (r1 - r2), 2) + Math.pow(59 * (g1 - g2), 2) + Math.pow(11 * (b1 - b2), 2); }; function each(obj, iter, con) { if (obj.forEach) return obj.forEach(iter, con); for (var i = 0; i < obj.length; i++) { iter.call(con, obj[i], i, obj); } } function wasMondifierKeyOnlyEvent(ev) { return ev.keyCode === 16 || // Shift ev.keyCode === 17 || // Ctrl ev.keyCode === 18; // Alt } function keys(obj) { if (Object.keys) return Object.keys(obj); var key, keys = []; for (key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { keys.push(key); } } return keys; } /** * Expose */ Terminal.EventEmitter = EventEmitter; Terminal.inherits = inherits; /** * Adds an event listener to the terminal. * * @param {string} event The name of the event. TODO: Document all event types * @param {function} callback The function to call when the event is triggered. */ Terminal.on = on; Terminal.off = off; Terminal.cancel = cancel; module.exports = Terminal; xterm.js-2.7.0/tsconfig.json000066400000000000000000000004151311554223300160000ustar00rootroot00000000000000{ "compilerOptions": { "module": "commonjs", "target": "es5", "rootDir": "src", "allowJs": true, "outDir": "lib", "sourceMap": true, "removeComments": true }, "include": [ "src/**/*" ], "exclude": [ "src/addons/**/*" ] } xterm.js-2.7.0/tslint.json000066400000000000000000000017061311554223300155050ustar00rootroot00000000000000{ "rules": { "class-name": true, "comment-format": [ true, "check-space" ], "indent": [ true, "spaces" ], "eofline": true, "no-eval": true, "no-internal-module": true, "no-trailing-whitespace": true, "no-unsafe-finally": true, "no-var-keyword": true, "quotemark": [ true, "single" ], "semicolon": [ true, "always" ], "triple-equals": [ true, "allow-null-check" ], "typedef-whitespace": [ true, { "call-signature": "nospace", "index-signature": "nospace", "parameter": "nospace", "property-declaration": "nospace", "variable-declaration": "nospace" } ], "variable-name": [ true, "ban-keywords" ], "whitespace": [ true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type" ] } } xterm.js-2.7.0/typings.json000066400000000000000000000001521311554223300156570ustar00rootroot00000000000000{ "name": "xterm", "globalDependencies": { "node": "registry:env/node#6.0.0+20160918225031" } }