You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
6.8 KiB
233 lines
6.8 KiB
'use strict' |
|
var Plumbing = require('./plumbing.js') |
|
var hasUnicode = require('has-unicode') |
|
var hasColor = require('./has-color.js') |
|
var onExit = require('signal-exit') |
|
var defaultThemes = require('./themes') |
|
var setInterval = require('./set-interval.js') |
|
var process = require('./process.js') |
|
var setImmediate = require('./set-immediate') |
|
|
|
module.exports = Gauge |
|
|
|
function callWith (obj, method) { |
|
return function () { |
|
return method.call(obj) |
|
} |
|
} |
|
|
|
function Gauge (arg1, arg2) { |
|
var options, writeTo |
|
if (arg1 && arg1.write) { |
|
writeTo = arg1 |
|
options = arg2 || {} |
|
} else if (arg2 && arg2.write) { |
|
writeTo = arg2 |
|
options = arg1 || {} |
|
} else { |
|
writeTo = process.stderr |
|
options = arg1 || arg2 || {} |
|
} |
|
|
|
this._status = { |
|
spun: 0, |
|
section: '', |
|
subsection: '' |
|
} |
|
this._paused = false // are we paused for back pressure? |
|
this._disabled = true // are all progress bar updates disabled? |
|
this._showing = false // do we WANT the progress bar on screen |
|
this._onScreen = false // IS the progress bar on screen |
|
this._needsRedraw = false // should we print something at next tick? |
|
this._hideCursor = options.hideCursor == null ? true : options.hideCursor |
|
this._fixedFramerate = options.fixedFramerate == null |
|
? !(/^v0\.8\./.test(process.version)) |
|
: options.fixedFramerate |
|
this._lastUpdateAt = null |
|
this._updateInterval = options.updateInterval == null ? 50 : options.updateInterval |
|
|
|
this._themes = options.themes || defaultThemes |
|
this._theme = options.theme |
|
var theme = this._computeTheme(options.theme) |
|
var template = options.template || [ |
|
{type: 'progressbar', length: 20}, |
|
{type: 'activityIndicator', kerning: 1, length: 1}, |
|
{type: 'section', kerning: 1, default: ''}, |
|
{type: 'subsection', kerning: 1, default: ''} |
|
] |
|
this.setWriteTo(writeTo, options.tty) |
|
var PlumbingClass = options.Plumbing || Plumbing |
|
this._gauge = new PlumbingClass(theme, template, this.getWidth()) |
|
|
|
this._$$doRedraw = callWith(this, this._doRedraw) |
|
this._$$handleSizeChange = callWith(this, this._handleSizeChange) |
|
|
|
this._cleanupOnExit = options.cleanupOnExit == null || options.cleanupOnExit |
|
this._removeOnExit = null |
|
|
|
if (options.enabled || (options.enabled == null && this._tty && this._tty.isTTY)) { |
|
this.enable() |
|
} else { |
|
this.disable() |
|
} |
|
} |
|
Gauge.prototype = {} |
|
|
|
Gauge.prototype.isEnabled = function () { |
|
return !this._disabled |
|
} |
|
|
|
Gauge.prototype.setTemplate = function (template) { |
|
this._gauge.setTemplate(template) |
|
if (this._showing) this._requestRedraw() |
|
} |
|
|
|
Gauge.prototype._computeTheme = function (theme) { |
|
if (!theme) theme = {} |
|
if (typeof theme === 'string') { |
|
theme = this._themes.getTheme(theme) |
|
} else if (theme && (Object.keys(theme).length === 0 || theme.hasUnicode != null || theme.hasColor != null)) { |
|
var useUnicode = theme.hasUnicode == null ? hasUnicode() : theme.hasUnicode |
|
var useColor = theme.hasColor == null ? hasColor : theme.hasColor |
|
theme = this._themes.getDefault({hasUnicode: useUnicode, hasColor: useColor, platform: theme.platform}) |
|
} |
|
return theme |
|
} |
|
|
|
Gauge.prototype.setThemeset = function (themes) { |
|
this._themes = themes |
|
this.setTheme(this._theme) |
|
} |
|
|
|
Gauge.prototype.setTheme = function (theme) { |
|
this._gauge.setTheme(this._computeTheme(theme)) |
|
if (this._showing) this._requestRedraw() |
|
this._theme = theme |
|
} |
|
|
|
Gauge.prototype._requestRedraw = function () { |
|
this._needsRedraw = true |
|
if (!this._fixedFramerate) this._doRedraw() |
|
} |
|
|
|
Gauge.prototype.getWidth = function () { |
|
return ((this._tty && this._tty.columns) || 80) - 1 |
|
} |
|
|
|
Gauge.prototype.setWriteTo = function (writeTo, tty) { |
|
var enabled = !this._disabled |
|
if (enabled) this.disable() |
|
this._writeTo = writeTo |
|
this._tty = tty || |
|
(writeTo === process.stderr && process.stdout.isTTY && process.stdout) || |
|
(writeTo.isTTY && writeTo) || |
|
this._tty |
|
if (this._gauge) this._gauge.setWidth(this.getWidth()) |
|
if (enabled) this.enable() |
|
} |
|
|
|
Gauge.prototype.enable = function () { |
|
if (!this._disabled) return |
|
this._disabled = false |
|
if (this._tty) this._enableEvents() |
|
if (this._showing) this.show() |
|
} |
|
|
|
Gauge.prototype.disable = function () { |
|
if (this._disabled) return |
|
if (this._showing) { |
|
this._lastUpdateAt = null |
|
this._showing = false |
|
this._doRedraw() |
|
this._showing = true |
|
} |
|
this._disabled = true |
|
if (this._tty) this._disableEvents() |
|
} |
|
|
|
Gauge.prototype._enableEvents = function () { |
|
if (this._cleanupOnExit) { |
|
this._removeOnExit = onExit(callWith(this, this.disable)) |
|
} |
|
this._tty.on('resize', this._$$handleSizeChange) |
|
if (this._fixedFramerate) { |
|
this.redrawTracker = setInterval(this._$$doRedraw, this._updateInterval) |
|
if (this.redrawTracker.unref) this.redrawTracker.unref() |
|
} |
|
} |
|
|
|
Gauge.prototype._disableEvents = function () { |
|
this._tty.removeListener('resize', this._$$handleSizeChange) |
|
if (this._fixedFramerate) clearInterval(this.redrawTracker) |
|
if (this._removeOnExit) this._removeOnExit() |
|
} |
|
|
|
Gauge.prototype.hide = function (cb) { |
|
if (this._disabled) return cb && process.nextTick(cb) |
|
if (!this._showing) return cb && process.nextTick(cb) |
|
this._showing = false |
|
this._doRedraw() |
|
cb && setImmediate(cb) |
|
} |
|
|
|
Gauge.prototype.show = function (section, completed) { |
|
this._showing = true |
|
if (typeof section === 'string') { |
|
this._status.section = section |
|
} else if (typeof section === 'object') { |
|
var sectionKeys = Object.keys(section) |
|
for (var ii = 0; ii < sectionKeys.length; ++ii) { |
|
var key = sectionKeys[ii] |
|
this._status[key] = section[key] |
|
} |
|
} |
|
if (completed != null) this._status.completed = completed |
|
if (this._disabled) return |
|
this._requestRedraw() |
|
} |
|
|
|
Gauge.prototype.pulse = function (subsection) { |
|
this._status.subsection = subsection || '' |
|
this._status.spun++ |
|
if (this._disabled) return |
|
if (!this._showing) return |
|
this._requestRedraw() |
|
} |
|
|
|
Gauge.prototype._handleSizeChange = function () { |
|
this._gauge.setWidth(this._tty.columns - 1) |
|
this._requestRedraw() |
|
} |
|
|
|
Gauge.prototype._doRedraw = function () { |
|
if (this._disabled || this._paused) return |
|
if (!this._fixedFramerate) { |
|
var now = Date.now() |
|
if (this._lastUpdateAt && now - this._lastUpdateAt < this._updateInterval) return |
|
this._lastUpdateAt = now |
|
} |
|
if (!this._showing && this._onScreen) { |
|
this._onScreen = false |
|
var result = this._gauge.hide() |
|
if (this._hideCursor) { |
|
result += this._gauge.showCursor() |
|
} |
|
return this._writeTo.write(result) |
|
} |
|
if (!this._showing && !this._onScreen) return |
|
if (this._showing && !this._onScreen) { |
|
this._onScreen = true |
|
this._needsRedraw = true |
|
if (this._hideCursor) { |
|
this._writeTo.write(this._gauge.hideCursor()) |
|
} |
|
} |
|
if (!this._needsRedraw) return |
|
if (!this._writeTo.write(this._gauge.show(this._status))) { |
|
this._paused = true |
|
this._writeTo.on('drain', callWith(this, function () { |
|
this._paused = false |
|
this._doRedraw() |
|
})) |
|
} |
|
}
|
|
|