0
0
mirror of https://github.com/nodejs/node.git synced 2024-12-01 16:10:02 +01:00
nodejs/lib/tty.js
Ruben Bridgewater 373e893ee0
tty: refactor to es6
PR-URL: https://github.com/nodejs/node/pull/17615
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2018-01-24 13:07:35 +01:00

210 lines
5.8 KiB
JavaScript

// Copyright Joyent, Inc. and other Node contributors.
//
// 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.
'use strict';
const { inherits, _errnoException, _extend } = require('util');
const net = require('net');
const { TTY, isTTY } = process.binding('tty_wrap');
const errors = require('internal/errors');
const readline = require('readline');
const { release } = require('os');
const OSRelease = release().split('.');
const COLORS_2 = 1;
const COLORS_16 = 4;
const COLORS_256 = 8;
const COLORS_16m = 24;
function isatty(fd) {
return Number.isInteger(fd) && fd >= 0 && isTTY(fd);
}
function ReadStream(fd, options) {
if (!(this instanceof ReadStream))
return new ReadStream(fd, options);
if (fd >> 0 !== fd || fd < 0)
throw new errors.RangeError('ERR_INVALID_FD', fd);
const ctx = {};
const tty = new TTY(fd, true, ctx);
if (ctx.code !== undefined) {
throw new errors.SystemError(ctx);
}
options = _extend({
highWaterMark: 0,
readable: true,
writable: false,
handle: tty
}, options);
net.Socket.call(this, options);
this.isRaw = false;
this.isTTY = true;
}
inherits(ReadStream, net.Socket);
ReadStream.prototype.setRawMode = function(flag) {
flag = !!flag;
this._handle.setRawMode(flag);
this.isRaw = flag;
};
function WriteStream(fd) {
if (!(this instanceof WriteStream))
return new WriteStream(fd);
if (fd >> 0 !== fd || fd < 0)
throw new errors.RangeError('ERR_INVALID_FD', fd);
const ctx = {};
const tty = new TTY(fd, false, ctx);
if (ctx.code !== undefined) {
throw new errors.SystemError(ctx);
}
net.Socket.call(this, {
handle: tty,
readable: false,
writable: true
});
// Prevents interleaved or dropped stdout/stderr output for terminals.
// As noted in the following reference, local TTYs tend to be quite fast and
// this behavior has become expected due historical functionality on OS X,
// even though it was originally intended to change in v1.0.2 (Libuv 1.2.1).
// Ref: https://github.com/nodejs/node/pull/1771#issuecomment-119351671
this._handle.setBlocking(true);
const winSize = new Array(2);
const err = this._handle.getWindowSize(winSize);
if (!err) {
this.columns = winSize[0];
this.rows = winSize[1];
}
}
inherits(WriteStream, net.Socket);
WriteStream.prototype.isTTY = true;
WriteStream.prototype.getColorDepth = function(env = process.env) {
if (env.NODE_DISABLE_COLORS || env.TERM === 'dumb' && !env.COLORTERM) {
return COLORS_2;
}
if (process.platform === 'win32') {
// Windows 10 build 10586 is the first Windows release that supports 256
// colors. Windows 10 build 14931 is the first release that supports
// 16m/TrueColor.
if (+OSRelease[0] >= 10) {
const build = +OSRelease[2];
if (build >= 14931)
return COLORS_16m;
if (build >= 10586)
return COLORS_256;
}
return COLORS_16;
}
if (env.TMUX) {
return COLORS_256;
}
if (env.CI) {
if ('TRAVIS' in env || 'CIRCLECI' in env || 'APPVEYOR' in env ||
'GITLAB_CI' in env || env.CI_NAME === 'codeship') {
return COLORS_256;
}
return COLORS_2;
}
if ('TEAMCITY_VERSION' in env) {
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ?
COLORS_16 : COLORS_2;
}
switch (env.TERM_PROGRAM) {
case 'iTerm.app':
if (!env.TERM_PROGRAM_VERSION ||
/^[0-2]\./.test(env.TERM_PROGRAM_VERSION)) {
return COLORS_256;
}
return COLORS_16m;
case 'HyperTerm':
case 'Hyper':
case 'MacTerm':
return COLORS_16m;
case 'Apple_Terminal':
return COLORS_256;
}
if (env.TERM) {
if (/^xterm-256/.test(env.TERM))
return COLORS_256;
if (/^screen|^xterm|^vt100|color|ansi|cygwin|linux/i.test(env.TERM))
return COLORS_16;
}
if (env.COLORTERM)
return COLORS_16;
return COLORS_2;
};
WriteStream.prototype._refreshSize = function() {
const oldCols = this.columns;
const oldRows = this.rows;
const winSize = new Array(2);
const err = this._handle.getWindowSize(winSize);
if (err) {
this.emit('error', _errnoException(err, 'getWindowSize'));
return;
}
const [newCols, newRows] = winSize;
if (oldCols !== newCols || oldRows !== newRows) {
this.columns = newCols;
this.rows = newRows;
this.emit('resize');
}
};
// Backwards-compat
WriteStream.prototype.cursorTo = function(x, y) {
readline.cursorTo(this, x, y);
};
WriteStream.prototype.moveCursor = function(dx, dy) {
readline.moveCursor(this, dx, dy);
};
WriteStream.prototype.clearLine = function(dir) {
readline.clearLine(this, dir);
};
WriteStream.prototype.clearScreenDown = function() {
readline.clearScreenDown(this);
};
WriteStream.prototype.getWindowSize = function() {
return [this.columns, this.rows];
};
module.exports = { isatty, ReadStream, WriteStream };