diff --git a/.npmignore b/.npmignore index 63069bda..517ba0bd 100644 --- a/.npmignore +++ b/.npmignore @@ -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/ diff --git a/.travis.yml b/.travis.yml index c41ebf79..1f3c9079 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,3 @@ env: notifications: email: false script: npm run $NPM_COMMAND -after_success: npm run coveralls diff --git a/README.md b/README.md index 07baec5a..6ba671a2 100644 --- a/README.md +++ b/README.md @@ -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. @@ -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. `(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. `(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. diff --git a/demo/index.html b/demo/index.html index 760d5990..9c19ea83 100644 --- a/demo/index.html +++ b/demo/index.html @@ -9,7 +9,7 @@ -

xterm.js: xterm, in the browser

+

xterm.js: A terminal for the web

Actions

diff --git a/package.json b/package.json index d4a06f82..5f3d835e 100644 --- a/package.json +++ b/package.json @@ -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": {} + } } diff --git a/src/Terminal.ts b/src/Terminal.ts index c466396e..5ec79a7c 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -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, diff --git a/src/handlers/AltClickHandler.ts b/src/handlers/AltClickHandler.ts index 85465272..7f2e4f05 100644 --- a/src/handlers/AltClickHandler.ts +++ b/src/handlers/AltClickHandler.ts @@ -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()); } } diff --git a/src/renderer/BaseRenderLayer.ts b/src/renderer/BaseRenderLayer.ts index 7a655163..c2b65e16 100644 --- a/src/renderer/BaseRenderLayer.ts +++ b/src/renderer/BaseRenderLayer.ts @@ -243,23 +243,21 @@ export abstract class BaseRenderLayer implements IRenderLayer { * @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, italic: boolean): void { - let colorIndex = 0; - if (fg < 256) { - colorIndex = fg + 2; - } else { - // If default color and bold - if (bold && terminal.options.enableBold) { - colorIndex = 1; - } - } 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; + 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, italic); + 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); diff --git a/src/renderer/TextRenderLayer.ts b/src/renderer/TextRenderLayer.ts index 8d8d6d4d..0dca11b2 100644 --- a/src/renderer/TextRenderLayer.ts +++ b/src/renderer/TextRenderLayer.ts @@ -116,13 +116,6 @@ 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); } } diff --git a/src/renderer/atlas/CharAtlas.ts b/src/renderer/atlas/CharAtlas.ts index f516919f..db5c92f6 100644 --- a/src/renderer/atlas/CharAtlas.ts +++ b/src/renderer/atlas/CharAtlas.ts @@ -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; } } diff --git a/src/shared/atlas/CharAtlasGenerator.ts b/src/shared/atlas/CharAtlasGenerator.ts index fc83c7ce..ffb736dd 100644 --- a/src/shared/atlas/CharAtlasGenerator.ts +++ b/src/shared/atlas/CharAtlasGenerator.ts @@ -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); diff --git a/src/xterm.css b/src/xterm.css index eec41a05..6e7d2f96 100644 --- a/src/xterm.css +++ b/src/xterm.css @@ -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; -} diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 65d533de..3107589e 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -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. *