Merge branch 'master' into more_naming_conventions

This commit is contained in:
Daniel Imms
2018-05-16 09:45:42 -07:00
committed by GitHub
15 changed files with 187 additions and 126 deletions
+44 -12
View File
@@ -1,16 +1,48 @@
node_modules/
*.swp
.lock-wscript
lib/*.test.js
lib/*.test.js.map
# Blacklist - exclude everything except npm defaults such as LICENSE, etc
*
!*/
# Whitelist - entries to be included must be negated with "!"
!*.js
!*.json
# Whitelist - dist/
!dist/**/*.js
!dist/**/*.js.map
!dist/**/*.css
# Whitelist - lib/
!lib/**/*.d.ts
!lib/**/*.js
!lib/**/*.js.map
!lib/**/*.css
# Whitelist - src/
!src/**/*.ts
!src/**/*.d.ts
!src/**/*.js
!src/**/*.js.map
!src/**/*.css
# Whitelist - typings/
!typings/*.d.ts
# Blacklist - (normal behavior) these will override any whitelist
*.test.ts
*.test.d.ts
*.test.js
*.test.js.map
lib/test/
Makefile.gyp
*.Makefile
*.target.gyp.mk
*.node
example/*.log
docs/
npm-debug.log
/.idea/
.env
.vscode/
build/
fixtures/
coverage/
demo/
-1
View File
@@ -17,4 +17,3 @@ env:
notifications:
email: false
script: npm run $NPM_COMMAND
after_success: npm run coveralls
+18 -4
View File
@@ -1,6 +1,6 @@
# [![xterm.js logo](logo-full.png)](https://xtermjs.org)
[![xterm.js build status](https://api.travis-ci.org/xtermjs/xterm.js.svg)](https://travis-ci.org/xtermjs/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) [![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/xterm/badge?style=rounded)](https://www.jsdelivr.com/package/npm/xterm)
[![xterm.js build status](https://api.travis-ci.org/xtermjs/xterm.js.svg)](https://travis-ci.org/xtermjs/xterm.js) [![Coverage Status](https://coveralls.io/repos/github/xtermjs/xterm.js/badge.svg?branch=master)](https://coveralls.io/github/xtermjs/xterm.js?branch=master) [![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) [![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/xterm/badge?style=rounded)](https://www.jsdelivr.com/package/npm/xterm)
Xterm.js is a terminal front-end component written in JavaScript that works in the browser.
@@ -41,7 +41,7 @@ To start using xterm.js on your browser, add the `xterm.js` and `xterm.css` to t
<script>
var term = new Terminal();
term.open(document.getElementById('terminal'));
term.write('Hello from \033[1;3;31mxterm.js\033[0m $ ')
      term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ')
</script>
</body>
</html>
@@ -57,8 +57,6 @@ The proposed way to load xterm.js is via the ES6 module syntax.
import { Terminal } from 'xterm';
```
*Note: There are currently no typings for addons so you will need to upcast if using TypeScript, eg. `(<any>xterm).fit()`.*
### Addons
Addons are JavaScript modules that extend the `Terminal` prototype with new methods and attributes to provide additional functionality. There are a handful available in the main repository in the `src/addons` directory and you can even write your own, by using xterm.js' public API.
@@ -76,6 +74,21 @@ var xterm = new Terminal(); // Instantiate the terminal
xterm.fit(); // Use the `fit` method, provided by the `fit` addon
```
#### Importing Addons in TypeScript
There are currently no typings for addons if they are accessed via extending Terminal prototype, so you will need to upcast if using TypeScript, eg. `(<any>xterm).fit()`.
Alternatively, you can import addon function and enhance the terminal on demand. This would have better typing support and is friendly to treeshaking. E.g.:
```typescript
import { Terminal } from 'xterm';
import { fit } from 'xterm/lib/addons/fit/fit';
const xterm = new Terminal();
// Fit the terminal when necessary:
fit(xterm);
```
#### Third party addons
There are also the following third party addons available:
@@ -135,6 +148,7 @@ computational environment for Jupyter, supporting interactive data science and s
- [**FreeMAN**](https://github.com/matthew-matvei/freeman): A free, cross-platform file manager for power users
- [**Fluent Terminal**](https://github.com/felixse/FluentTerminal): A terminal emulator based on UWP and web technologies.
- [**Hyper**](https://hyper.is): A terminal built on web technologies
- [**Diag**](https://diag.ai): A better way to troubleshoot problems faster. Capture, share and reapply troubleshooting knowledge so you can focus on solving problems that matter.
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.
+1 -1
View File
@@ -9,7 +9,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js"></script>
</head>
<body>
<h1>xterm.js: xterm, in the browser</h1>
<h1 style="color: #2D2E2C">xterm.js: A terminal for the <em style="color: #5DA5D5">web</em></h1>
<div id="terminal-container"></div>
<div>
<h2>Actions</h2>
+3 -36
View File
@@ -2,47 +2,15 @@
"name": "xterm",
"description": "Full xterm terminal, in your browser",
"version": "3.3.0",
"ignore": [
"demo",
"test",
".gitignore"
],
"main": "lib/Terminal.js",
"types": "typings/xterm.d.ts",
"repository": "https://github.com/xtermjs/xterm.js",
"license": "MIT",
"files": [
"*.js",
"*.json",
"dist/*.css",
"dist/**/*.css",
"dist/*.js",
"dist/*.js.map",
"dist/**/*.js",
"dist/**/*.js.map",
"lib/*.css",
"lib/**/*.css",
"lib/*.d.ts",
"lib/*.js",
"lib/*.js.map",
"lib/**/*.d.ts",
"lib/**/*.js",
"lib/**/*.js.map",
"src/*.css",
"src/**/*.css",
"src/*.js",
"src/*.js.map",
"src/*.ts",
"src/**/*.js",
"src/**/*.js.map",
"src/**/*.ts",
"typings/*.d.ts"
],
"devDependencies": {
"@types/chai": "^3.4.34",
"@types/jsdom": "^11.0.1",
"@types/mocha": "^2.2.33",
"@types/node": "^6.0.41",
"@types/node": "6.0.108",
"@types/text-encoding": "0.0.32",
"browserify": "^13.3.0",
"chai": "3.5.0",
@@ -78,7 +46,7 @@
"scripts": {
"start": "node demo/app",
"start-zmodem": "node demo/zmodem/app",
"lint": "tslint src/*.ts src/**/*.ts src/addons/**/*.ts",
"lint": "tslint 'src/**/*.ts'",
"test": "npm-run-all mocha lint",
"mocha": "gulp test",
"build:docs": "jsdoc -c jsdoc.json",
@@ -88,6 +56,5 @@
"coveralls": "gulp coveralls",
"webpack": "gulp webpack",
"watch": "gulp watch"
},
"dependencies": {}
}
}
+3
View File
@@ -1263,6 +1263,9 @@ export class InputHandler implements IInputHandler {
} else if (p === 1) {
// bold text
flags |= FLAGS.BOLD;
} else if (p === 3) {
// italic text
flags |= FLAGS.ITALIC;
} else if (p === 4) {
// underlined text
flags |= FLAGS.UNDERLINE;
+1
View File
@@ -103,6 +103,7 @@ const DEFAULT_OPTIONS: ITerminalOptions = {
cursorStyle: 'block',
bellSound: DEFAULT_BELL_SOUND,
bellStyle: 'none',
drawBoldTextInBrightColors: true,
enableBold: true,
fontFamily: 'courier-new, courier, monospace',
fontSize: 15,
+9 -5
View File
@@ -28,7 +28,7 @@ export class AltClickHandler {
this._startCol = this._terminal.buffer.x;
this._startRow = this._terminal.buffer.y;
[this._endCol, this._endRow] = this._terminal.mouseHelper.getCoords(
let coordinates = this._terminal.mouseHelper.getCoords(
this._mouseEvent,
this._terminal.element,
this._terminal.charMeasure,
@@ -36,16 +36,20 @@ export class AltClickHandler {
this._terminal.cols,
this._terminal.rows,
false
).map((coordinate: number) => {
return coordinate - 1;
});
);
if (coordinates) {
[this._endCol, this._endRow] = coordinates.map((coordinate: number) => {
return coordinate - 1;
});
}
}
/**
* Writes the escape sequences of arrows to the terminal
*/
public move(): void {
if (this._mouseEvent.altKey) {
if (this._mouseEvent.altKey && this._endCol !== undefined && this._endRow !== undefined) {
this._terminal.send(this._arrowSequences());
}
}
+21 -29
View File
@@ -219,7 +219,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
* @param color The color of the character.
*/
protected fillCharTrueColor(terminal: ITerminal, charData: CharData, x: number, y: number): void {
this._ctx.font = this._getFont(terminal, false);
this._ctx.font = this._getFont(terminal, false, false);
this._ctx.textBaseline = 'top';
this._clipRow(terminal, y);
this._ctx.fillText(
@@ -242,24 +242,22 @@ export abstract class BaseRenderLayer implements IRenderLayer {
* This is used to validate whether a cached image can be used.
* @param bold Whether the text is bold.
*/
protected drawChar(terminal: ITerminal, char: string, code: number, width: number, x: number, y: number, fg: number, bg: number, bold: boolean, dim: boolean): void {
let colorIndex = 0;
if (fg < 256) {
colorIndex = fg + 2;
} else {
// If default color and bold
if (bold && terminal.options.enableBold) {
colorIndex = 1;
}
}
protected drawChar(terminal: ITerminal, char: string, code: number, width: number, x: number, y: number, fg: number, bg: number, bold: boolean, dim: boolean, italic: boolean): void {
const isAscii = code < 256;
// A color is basic if it is one of the standard normal or bold weight
// colors of the characters held in the char atlas. Note that this excludes
// the normal weight _light_ color characters.
const isBasicColor = (colorIndex > 1 && fg < 16) && (fg < 8 || bold);
// A color is basic if it is one of the 4 bit ANSI colors.
const isBasicColor = fg < 16;
const isDefaultColor = fg >= 256;
const isDefaultBackground = bg >= 256;
if (this._charAtlas && isAscii && (isBasicColor || isDefaultColor) && isDefaultBackground) {
const drawInBrightColor = (terminal.options.drawBoldTextInBrightColors && bold && fg < 8);
if (this._charAtlas && isAscii && (isBasicColor || isDefaultColor) && isDefaultBackground && !italic) {
this._ctx.save(); // we may set globalAlpha, so we need to be able to restore
let colorIndex: number;
if (isDefaultColor) {
colorIndex = (bold && terminal.options.enableBold ? 1 : 0);
} else {
colorIndex = 2 + fg + (bold && terminal.options.enableBold ? 16 : 0) + (drawInBrightColor ? 8 : 0);
}
// ImageBitmap's draw about twice as fast as from a canvas
const charAtlasCellWidth = this._scaledCharWidth + CHAR_ATLAS_CELL_SPACING;
const charAtlasCellHeight = this._scaledCharHeight + CHAR_ATLAS_CELL_SPACING;
@@ -269,14 +267,6 @@ export abstract class BaseRenderLayer implements IRenderLayer {
this._ctx.globalAlpha = DIM_OPACITY;
}
// Draw the non-bold version of the same color if bold is not enabled
if (bold && !terminal.options.enableBold) {
// Ignore default color as it's not touched above
if (colorIndex > 1) {
colorIndex -= 8;
}
}
this._ctx.drawImage(this._charAtlas,
code * charAtlasCellWidth,
colorIndex * charAtlasCellHeight,
@@ -286,8 +276,9 @@ export abstract class BaseRenderLayer implements IRenderLayer {
y * this._scaledCellHeight + this._scaledCharTop,
charAtlasCellWidth,
this._scaledCharHeight);
this._ctx.restore();
} else {
this._drawUncachedChar(terminal, char, width, fg, x, y, bold && terminal.options.enableBold, dim);
this._drawUncachedChar(terminal, char, width, fg + (drawInBrightColor ? 8 : 0), x, y, bold && terminal.options.enableBold, dim, italic);
}
// This draws the atlas (for debugging purposes)
// this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);
@@ -305,9 +296,9 @@ export abstract class BaseRenderLayer implements IRenderLayer {
* @param x The column to draw at.
* @param y The row to draw at.
*/
private _drawUncachedChar(terminal: ITerminal, char: string, width: number, fg: number, x: number, y: number, bold: boolean, dim: boolean): void {
private _drawUncachedChar(terminal: ITerminal, char: string, width: number, fg: number, x: number, y: number, bold: boolean, dim: boolean, italic: boolean): void {
this._ctx.save();
this._ctx.font = this._getFont(terminal, bold);
this._ctx.font = this._getFont(terminal, bold, italic);
this._ctx.textBaseline = 'top';
if (fg === INVERTED_DEFAULT_COLOR) {
@@ -353,10 +344,11 @@ export abstract class BaseRenderLayer implements IRenderLayer {
* @param terminal The terminal.
* @param isBold If we should use the bold fontWeight.
*/
protected _getFont(terminal: ITerminal, isBold: boolean): string {
protected _getFont(terminal: ITerminal, isBold: boolean, isItalic: boolean): string {
const fontWeight = isBold ? terminal.options.fontWeightBold : terminal.options.fontWeight;
const fontStyle = isItalic ? 'italic' : '';
return `${fontWeight} ${terminal.options.fontSize * window.devicePixelRatio}px ${terminal.options.fontFamily}`;
return `${fontStyle} ${fontWeight} ${terminal.options.fontSize * window.devicePixelRatio}px ${terminal.options.fontFamily}`;
}
}
+48 -15
View File
@@ -32,7 +32,7 @@ export class TextRenderLayer extends BaseRenderLayer {
super.resize(terminal, dim);
// Clear the character width cache if the font or width has changed
const terminalFont = this._getFont(terminal, false);
const terminalFont = this._getFont(terminal, false, false);
if (this._characterWidth !== dim.scaledCharWidth || this._characterFont !== terminalFont) {
this._characterWidth = dim.scaledCharWidth;
this._characterFont = terminalFont;
@@ -116,30 +116,63 @@ export class TextRenderLayer extends BaseRenderLayer {
}
}
if (flags & FLAGS.BOLD) {
// Convert the FG color to the bold variant
if (fg < 8) {
fg += 8;
}
}
callback(code, char, width, x, y, fg, bg, flags);
}
}
}
/**
* Draws the background for a specified range of columns. Tries to batch adjacent cells of the
* same color together to reduce draw calls.
*/
private _drawBackground(terminal: ITerminal, firstRow: number, lastRow: number): void {
const ctx = this._ctx;
const cols = terminal.cols;
let startX: number = 0;
let startY: number = 0;
let prevFillStyle: string | null = null;
ctx.save();
this._forEachCell(terminal, firstRow, lastRow, (code, char, width, x, y, fg, bg, flags) => {
// libvte and xterm both draw the background (but not foreground) of invisible characters,
// so we should too.
const isDefaultBackground = bg >= 256;
if (!isDefaultBackground) {
this._ctx.save();
this._ctx.fillStyle = (bg === INVERTED_DEFAULT_COLOR ? this._colors.foreground.css : this._colors.ansi[bg].css);
this.fillCells(x, y, width, 1);
this._ctx.restore();
let nextFillStyle = null; // null represents default background color
if (bg === INVERTED_DEFAULT_COLOR) {
nextFillStyle = this._colors.foreground.css;
} else if (bg < 256) {
nextFillStyle = this._colors.ansi[bg].css;
}
if (prevFillStyle === null) {
// This is either the first iteration, or the default background was set. Either way, we
// don't need to draw anything.
startX = x;
startY = y;
} if (y !== startY) {
// our row changed, draw the previous row
ctx.fillStyle = prevFillStyle;
this.fillCells(startX, startY, cols - startX, 1);
startX = x;
startY = y;
} else if (prevFillStyle !== nextFillStyle) {
// our color changed, draw the previous characters in this row
ctx.fillStyle = prevFillStyle;
this.fillCells(startX, startY, x - startX, 1);
startX = x;
startY = y;
}
prevFillStyle = nextFillStyle;
});
// flush the last color we encountered
if (prevFillStyle !== null) {
ctx.fillStyle = prevFillStyle;
this.fillCells(startX, startY, cols - startX, 1);
}
ctx.restore();
}
private _drawForeground(terminal: ITerminal, firstRow: number, lastRow: number): void {
@@ -164,7 +197,7 @@ export class TextRenderLayer extends BaseRenderLayer {
terminal, char, code,
width, x, y,
fg, bg,
!!(flags & FLAGS.BOLD), !!(flags & FLAGS.DIM)
!!(flags & FLAGS.BOLD), !!(flags & FLAGS.DIM), !!(flags & FLAGS.ITALIC)
);
});
}
+2 -1
View File
@@ -16,7 +16,8 @@ export const enum FLAGS {
BLINK = 4,
INVERSE = 8,
INVISIBLE = 16,
DIM = 32
DIM = 32,
ITALIC = 64
}
export interface IRenderer extends IEventEmitter {
+7 -8
View File
@@ -35,15 +35,14 @@ export function acquireCharAtlas(terminal: ITerminal, colors: IColorSet, scaledC
if (ownedByIndex >= 0) {
if (configEquals(entry.config, newConfig)) {
return entry.bitmap;
} else {
// The configs differ, release the terminal from the entry
if (entry.ownedBy.length === 1) {
charAtlasCache.splice(i, 1);
} else {
entry.ownedBy.splice(ownedByIndex, 1);
}
break;
}
// The configs differ, release the terminal from the entry
if (entry.ownedBy.length === 1) {
charAtlasCache.splice(i, 1);
} else {
entry.ownedBy.splice(ownedByIndex, 1);
}
break;
}
}
+19 -8
View File
@@ -27,7 +27,7 @@ export function generateCharAtlas(context: Window, canvasFactory: (width: number
const cellHeight = config.scaledCharHeight + CHAR_ATLAS_CELL_SPACING;
const canvas = canvasFactory(
/*255 ascii chars*/255 * cellWidth,
(/*default+default bold*/2 + /*0-15*/16) * cellHeight
(/*default+default bold*/2 + /*0-15*/16 + /*0-15 bold*/16) * cellHeight
);
const ctx = canvas.getContext('2d', {alpha: config.allowTransparency});
@@ -64,10 +64,6 @@ export function generateCharAtlas(context: Window, canvasFactory: (width: number
// Colors 0-15
ctx.font = getFont(config.fontWeight, config);
for (let colorIndex = 0; colorIndex < 16; colorIndex++) {
// colors 8-15 are bold
if (colorIndex === 8) {
ctx.font = getFont(config.fontWeightBold, config);
}
const y = (colorIndex + 2) * cellHeight;
// Draw ascii characters
for (let i = 0; i < 256; i++) {
@@ -80,6 +76,22 @@ export function generateCharAtlas(context: Window, canvasFactory: (width: number
ctx.restore();
}
}
// Colors 0-15 bold
ctx.font = getFont(config.fontWeightBold, config);
for (let colorIndex = 0; colorIndex < 16; colorIndex++) {
const y = (colorIndex + 2 + 16) * cellHeight;
// Draw ascii characters
for (let i = 0; i < 256; i++) {
ctx.save();
ctx.beginPath();
ctx.rect(i * cellWidth, y, cellWidth, cellHeight);
ctx.clip();
ctx.fillStyle = config.colors.ansi[colorIndex].css;
ctx.fillText(String.fromCharCode(i), i * cellWidth, y);
ctx.restore();
}
}
ctx.restore();
// Support is patchy for createImageBitmap at the moment, pass a canvas back
@@ -91,10 +103,9 @@ export function generateCharAtlas(context: Window, canvasFactory: (width: number
if (canvas instanceof HTMLCanvasElement) {
// Just return the HTMLCanvas if it's a HTMLCanvasElement
return canvas;
} else {
// Transfer to an ImageBitmap is this is an OffscreenCanvas
return new Promise(r => r(canvas.transferToImageBitmap()));
}
// Transfer to an ImageBitmap is this is an OffscreenCanvas
return new Promise(r => r(canvas.transferToImageBitmap()));
}
const charAtlasImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
+6 -6
View File
@@ -126,13 +126,17 @@
line-height: normal;
}
.xterm {
cursor: text;
}
.xterm.enable-mouse-events {
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
cursor: default;
}
.xterm:not(.enable-mouse-events) {
cursor: text;
.xterm.xterm-cursor-pointer {
cursor: pointer;
}
.xterm .xterm-accessibility,
@@ -153,7 +157,3 @@
height: 1px;
overflow: hidden;
}
.xterm-cursor-pointer {
cursor: pointer;
}
+5
View File
@@ -54,6 +54,11 @@ declare module 'xterm' {
*/
disableStdin?: boolean;
/**
* Whether to draw bold text in bright colors. The default is true.
*/
drawBoldTextInBrightColors?: boolean;
/**
* Whether to enable the rendering of bold text.
*