mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge remote-tracking branch 'upstream/master' into linkify_ip_addr
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 4
|
||||
env:
|
||||
- CXX=g++-4.8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
notifications:
|
||||
email: false
|
||||
@@ -1,5 +1,7 @@
|
||||
# xterm.js
|
||||
|
||||

|
||||
|
||||
Xterm.js is a full xterm clone, written in JavaScript.
|
||||
|
||||
It is used at [SourceLair](https://www.sourcelair.com/home) to help people develop their applications in their browsers.
|
||||
@@ -8,7 +10,35 @@ Xterm.js supplies a modular, event-based interface that lets developers build ad
|
||||
|
||||

|
||||
|
||||
### Contribution and License Agreement
|
||||
## Demo
|
||||
|
||||
To launch the demo simply run:
|
||||
|
||||
```
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
Then open http://0.0.0.0:3000 in a web browser.
|
||||
|
||||
## 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 `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
|
||||
<script src="node_modules/src/xterm.js"></script>
|
||||
<script src="node_modules/addons/linkify/linkify.js"></script>
|
||||
```
|
||||
|
||||
```js
|
||||
var xterm = new Terminal();
|
||||
// init code...
|
||||
xterm.linkify();
|
||||
```
|
||||
|
||||
## Contribution and 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.
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
# Testing script for xterm.js
|
||||
|
||||
node_modules/.bin/mocha $@
|
||||
+6
-3
@@ -29,9 +29,12 @@ app.ws('/bash', function(ws, req) {
|
||||
cwd: process.env.PWD,
|
||||
env: process.env
|
||||
});
|
||||
|
||||
term.on('data', function(data) {
|
||||
ws.send(data);
|
||||
try {
|
||||
ws.send(data);
|
||||
} catch (ex) {
|
||||
// The WebSocket is not open, ignore
|
||||
}
|
||||
});
|
||||
ws.on('message', function(msg) {
|
||||
term.write(msg);
|
||||
@@ -45,5 +48,5 @@ app.ws('/bash', function(ws, req) {
|
||||
var port = process.env.PORT || 3000,
|
||||
host = '0.0.0.0';
|
||||
|
||||
console.log('App listening to ' + host + ':' + port);
|
||||
console.log('App listening to http://' + host + ':' + port);
|
||||
app.listen(port, host);
|
||||
|
||||
+1
-1
@@ -21,6 +21,6 @@ h1 {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#terminal-container .terminal .terminal-cursor {
|
||||
#terminal-container .terminal:focus .terminal-cursor {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
+5
-2
@@ -8,9 +8,12 @@
|
||||
"devDependencies": {
|
||||
"express": "4.13.4",
|
||||
"express-ws": "2.0.0-rc.1",
|
||||
"pty.js": "0.3.0"
|
||||
"pty.js": "0.3.0",
|
||||
"mocha": "2.5.3",
|
||||
"chai": "3.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "bash bin/server"
|
||||
"start": "bash bin/server",
|
||||
"test": "bash bin/test"
|
||||
}
|
||||
}
|
||||
|
||||
+7
-9
@@ -51,6 +51,12 @@
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.terminal:not(:focus) .terminal-cursor {
|
||||
outline: 1px solid #fff;
|
||||
outline-offset: -1px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine default colors for xterm.js
|
||||
*/
|
||||
@@ -2123,13 +2129,5 @@
|
||||
* in order to allow child elements to adjust.
|
||||
*/
|
||||
.terminal .xterm-rows > div {
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
/**
|
||||
* All styled spans inside terminal lines should be inline-blocks,
|
||||
* in orde to achieve better height adjustment.
|
||||
*/
|
||||
.terminal .xterm-rows span {
|
||||
display: inline-block;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
+259
-138
File diff suppressed because it is too large
Load Diff
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* term.js
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
*/
|
||||
|
||||
var element = {
|
||||
createElement: function() { return element; },
|
||||
appendChild: function() {},
|
||||
removeChild: function() {},
|
||||
addEventListener: function() {},
|
||||
removeEventListener: function() {},
|
||||
setAttribute: function() {},
|
||||
style: {}
|
||||
};
|
||||
|
||||
global.window = global;
|
||||
window.navigator = { userAgent: '' };
|
||||
window.document = element;
|
||||
window.document.body = element;
|
||||
|
||||
element.ownerDocument = window.document;
|
||||
window.document.defaultView = window;
|
||||
|
||||
var Terminal = require('../src/term');
|
||||
Terminal.cursorBlink = false;
|
||||
|
||||
var data = require('./data').data;
|
||||
|
||||
var term = new Terminal({
|
||||
cols: 250,
|
||||
rows: 100
|
||||
});
|
||||
|
||||
term.open(element);
|
||||
|
||||
var time = new Date;
|
||||
var t = 10;
|
||||
|
||||
while (t--) {
|
||||
var l = data.length
|
||||
, i = 0;
|
||||
|
||||
for (; i < l; i++) {
|
||||
term.write(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Completed: %d.', new Date - time);
|
||||
console.log('Average (?): 13.5k (for ~2.7k writes).');
|
||||
@@ -1,10 +0,0 @@
|
||||
167a168,170
|
||||
> var stream = fs.createWriteStream(__dirname + '/../test/data.js');
|
||||
> stream.write('this.data = [\n');
|
||||
>
|
||||
169a173
|
||||
> stream.write(' ' + JSON.stringify(data) + ',\n');
|
||||
182a187,189
|
||||
>
|
||||
> stream.write('];\n');
|
||||
> stream.end();
|
||||
@@ -1,49 +0,0 @@
|
||||
<!doctype html>
|
||||
<title>term.js test</title>
|
||||
<style>
|
||||
h1 {
|
||||
margin-bottom: 20px;
|
||||
font: 20px/1.5 sans-serif;
|
||||
}
|
||||
</style>
|
||||
<h1>term.js test</h1>
|
||||
<script src="term.js"></script>
|
||||
<script src="data.js"></script>
|
||||
<script>
|
||||
;(function() {
|
||||
var time = new Date
|
||||
, l = data.length * 0.9 | 0
|
||||
, i = 0;
|
||||
|
||||
Terminal.cursorBlink = false;
|
||||
|
||||
var term = new Terminal({
|
||||
cols: 80,
|
||||
rows: 30,
|
||||
useStyle: true
|
||||
});
|
||||
|
||||
window.onload = function() {
|
||||
// Add terminal.
|
||||
term.open(document.body);
|
||||
|
||||
// Run benchmark.
|
||||
(function write() {
|
||||
if (i >= l) return next();
|
||||
term.write(data[i]);
|
||||
i++;
|
||||
setTimeout(write, 1);
|
||||
})();
|
||||
|
||||
// Results.
|
||||
function next() {
|
||||
term.write('\x1b[2J');
|
||||
term.reset();
|
||||
term.refresh(0, term.rows - 1);
|
||||
term.writeln('Completed in ' + (new Date - time) + '.');
|
||||
term.writeln('Writes: ' + l + '.');
|
||||
term.writeln('Average (?): 28.5k (for ~2.5k writes).');
|
||||
}
|
||||
};
|
||||
}).call(this);
|
||||
</script>
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* term.js
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
*/
|
||||
|
||||
var http = require('http')
|
||||
, path = require('path')
|
||||
, fs = require('fs');
|
||||
|
||||
var express = require('express')
|
||||
, term = require('../');
|
||||
|
||||
var app = express()
|
||||
, server = http.createServer(app);
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
var setHeader = res.setHeader;
|
||||
res.setHeader = function(name) {
|
||||
switch (name) {
|
||||
case 'Cache-Control':
|
||||
case 'Last-Modified':
|
||||
case 'ETag':
|
||||
return;
|
||||
}
|
||||
return setHeader.apply(res, arguments);
|
||||
};
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(express.static(__dirname));
|
||||
app.use(term.middleware());
|
||||
|
||||
server.listen(8080);
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
var assert = require('chai').assert;
|
||||
var Terminal = require('../src/xterm');
|
||||
|
||||
describe('xterm.js', function() {
|
||||
var xterm;
|
||||
|
||||
beforeEach(function () {
|
||||
xterm = new Terminal();
|
||||
});
|
||||
|
||||
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, '\x1bOF'); // SS3 F
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 36 }).key, '\x1bOH'); // 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[5D for ctrl+left', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 37 }).key, '\x1b[5D'); // CSI 5 D
|
||||
});
|
||||
it('should return \\x1b[5C for ctrl+right', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 39 }).key, '\x1b[5C'); // CSI 5 C
|
||||
});
|
||||
});
|
||||
|
||||
describe('evaluateCopiedTextProcessing', function () {
|
||||
it('should strip trailing whitespaces and replace nbsps with spaces', function () {
|
||||
var nonBreakingSpace = String.fromCharCode(160),
|
||||
copiedText = 'echo' + nonBreakingSpace + 'hello' + nonBreakingSpace,
|
||||
processedText = Terminal.prepareCopiedTextForClipboard(copiedText);
|
||||
|
||||
// No trailing spaces
|
||||
assert.equal(processedText.match(/\s+$/), null);
|
||||
|
||||
// No non-breaking space
|
||||
assert.equal(processedText.indexOf(nonBreakingSpace), -1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Third level shift', function() {
|
||||
var ev = {
|
||||
preventDefault: function() {},
|
||||
stopPropagation: function() {}
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
xterm.handler = function() {};
|
||||
xterm.showCursor = function() {};
|
||||
xterm.clearSelection = function() {};
|
||||
})
|
||||
|
||||
describe('On Mac OS', function() {
|
||||
beforeEach(function() {
|
||||
xterm.isMac = true;
|
||||
});
|
||||
|
||||
it('should not interfere with the alt key on keyDown', function() {
|
||||
assert.equal(
|
||||
xterm.keyDown(Object.assign({}, ev, { altKey: true, keyCode: 81 })),
|
||||
true
|
||||
);
|
||||
assert.equal(
|
||||
xterm.keyDown(Object.assign({}, ev, { altKey: true, keyCode: 192 })),
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should interefere with the alt + arrow keys', function() {
|
||||
assert.equal(
|
||||
xterm.keyDown(Object.assign({}, ev, { altKey: true, keyCode: 37 })),
|
||||
false
|
||||
);
|
||||
assert.equal(
|
||||
xterm.keyDown(Object.assign({}, ev, { 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({}, ev, { altKey: true, keyCode: 64 })); // @
|
||||
// Firefox
|
||||
xterm.keyPress(Object.assign({}, ev, { altKey: true, charCode: 64, keyCode: 0 }));
|
||||
xterm.keyPress(Object.assign({}, ev, { altKey: true, keyCode: 92 })); // \
|
||||
xterm.keyPress(Object.assign({}, ev, { altKey: true, charCode: 92, keyCode: 0 }));
|
||||
xterm.keyPress(Object.assign({}, ev, { altKey: true, keyCode: 124 })); // |
|
||||
xterm.keyPress(Object.assign({}, ev, { altKey: true, charCode: 124, keyCode: 0 }));
|
||||
});
|
||||
});
|
||||
|
||||
describe('On MS Windows', function() {
|
||||
beforeEach(function() {
|
||||
xterm.isMSWindows = true;
|
||||
});
|
||||
|
||||
it('should not interfere with the alt + ctrl key on keyDown', function() {
|
||||
assert.equal(
|
||||
xterm.keyDown(Object.assign({}, ev, { altKey: true, ctrlKey: true, keyCode: 81 })),
|
||||
true
|
||||
);
|
||||
assert.equal(
|
||||
xterm.keyDown(Object.assign({}, ev, { altKey: true, ctrlKey: true, keyCode: 192 })),
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should interefere with the alt + ctrl + arrow keys', function() {
|
||||
assert.equal(
|
||||
xterm.keyDown(Object.assign({}, ev, { altKey: true, ctrlKey: true, keyCode: 37 })),
|
||||
false
|
||||
);
|
||||
assert.equal(
|
||||
xterm.keyDown(Object.assign({}, ev, { 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({}, ev, { altKey: true, ctrlKey: true, keyCode: 64 })
|
||||
); // @
|
||||
xterm.keyPress(
|
||||
Object.assign({}, ev, { altKey: true, ctrlKey: true, charCode: 64, keyCode: 0 })
|
||||
);
|
||||
xterm.keyPress(
|
||||
Object.assign({}, ev, { altKey: true, ctrlKey: true, keyCode: 92 })
|
||||
); // \
|
||||
xterm.keyPress(
|
||||
Object.assign({}, ev, { altKey: true, ctrlKey: true, charCode: 92, keyCode: 0 })
|
||||
);
|
||||
xterm.keyPress(
|
||||
Object.assign({}, ev, { altKey: true, ctrlKey: true, keyCode: 124 })
|
||||
); // |
|
||||
xterm.keyPress(
|
||||
Object.assign({}, ev, { altKey: true, ctrlKey: true, charCode: 124, keyCode: 0 })
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user