diff --git a/lib/readline.js b/lib/readline.js index 7629d23244..3ba30f355b 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -25,13 +25,13 @@ function Interface (output, completer) { this.setPrompt("node> "); - this._tty = output.fd < 3; + this.enabled = output.fd < 3; // Looks like a TTY. if (parseInt(process.env['NODE_NO_READLINE'])) { - this._tty = false; + this.enabled = false; } - if (this._tty) { + if (this.enabled) { // input refers to stdin // Current line @@ -39,7 +39,7 @@ function Interface (output, completer) { // Check process.env.TERM ? stdio.setRawMode(true); - this._tty = true; + this.enabled = true; // Cursor position on the line. this.cursor = 0; @@ -52,7 +52,7 @@ function Interface (output, completer) { inherits(Interface, EventEmitter); Interface.prototype.__defineGetter__("columns", function () { - if (this._tty) { + if (this.enabled) { return stdio.getColumns(); } }); @@ -64,7 +64,7 @@ Interface.prototype.setPrompt = function (prompt, length) { Interface.prototype.prompt = function () { - if (this._tty) { + if (this.enabled) { this.cursor = 0; this._refreshLine(); } else { @@ -110,7 +110,7 @@ Interface.prototype._refreshLine = function () { Interface.prototype.close = function (d) { - if (this._tty) { + if (this.enabled) { stdio.setRawMode(false); } this.emit('close'); @@ -120,7 +120,7 @@ Interface.prototype.close = function (d) { Interface.prototype.write = function (d) { if (this._closed) return; - return this._tty ? this._ttyWrite(d) : this._normalWrite(d); + return this.enabled ? this._ttyWrite(d) : this._normalWrite(d); }; diff --git a/lib/repl.js b/lib/repl.js index 4150f567de..e8e6c06e09 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -53,6 +53,12 @@ function REPLServer(prompt, stream) { var rli = self.rli = rl.createInterface(self.stream, function (text) { return self.complete(text); }); + if (rli.enabled) { + // Turn on ANSI coloring. + exports.writer = function(obj, showHidden, depth) { + return sys.inspect(obj, showHidden, depth, true); + } + } rli.setPrompt(self.prompt); self.stream.addListener("data", function (chunk) { diff --git a/lib/sys.js b/lib/sys.js index 8480facb7e..1d34713f3a 100644 --- a/lib/sys.js +++ b/lib/sys.js @@ -33,10 +33,51 @@ var error = exports.error = function (x) { * * @param {Object} value The object to print out * @param {Boolean} showHidden Flag that shows hidden (not enumerable) - * properties of objects. + * properties of objects. + * @param {Number} depth Depth in which to descend in object. Default is 2. + * @param {Boolean} colors Flag to turn on ANSI escape codes to color the + * output. Default is false (no coloring). */ -exports.inspect = function (obj, showHidden, depth) { +exports.inspect = function (obj, showHidden, depth, colors) { var seen = []; + + var stylize = function (str, styleType) { + // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics + var styles = { 'bold' : [1, 22] + , 'italic' : [3, 23] + , 'underline' : [4, 24] + , 'inverse' : [7, 27] + , 'white' : [37, 39] + , 'grey' : [90, 39] + , 'black' : [30, 39] + , 'blue' : [34, 39] + , 'cyan' : [36, 39] + , 'green' : [32, 39] + , 'magenta' : [35, 39] + , 'red' : [31, 39] + , 'yellow' : [33, 39] + }; + var style = { "special": "grey" + , "number": "blue" + , "boolean": "blue" + , "undefined": "red" + , "null": "red" + , "string": "green" + , "date": "magenta" + //, "name": intentionally not styling + , "regexp": "cyan" + }[styleType]; + if (style) { + return '\033[' + styles[style][0] + 'm' + str + + '\033[' + styles[style][1] + 'm'; + } else { + return str; + } + }; + if (! colors) { + stylize = function(str, styleType) { return str; }; + } + function format(value, recurseTimes) { // Provide a hook for user-specified inspect functions. // Check that value is an object with an inspect function on it @@ -50,16 +91,18 @@ exports.inspect = function (obj, showHidden, depth) { // Primitive types cannot have properties switch (typeof value) { - case 'undefined': return 'undefined'; - case 'string': return JSON.stringify(value).replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - case 'number': return '' + value; - case 'boolean': return '' + value; + case 'undefined': return stylize('undefined', 'undefined'); + case 'string': return stylize( + JSON.stringify(value).replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"), + 'string'); + case 'number': return stylize('' + value, 'number'); + case 'boolean': return stylize('' + value, 'boolean'); } // For some reason typeof null is "object", so special case here. if (value === null) { - return 'null'; + return stylize('null', 'null'); } // Look up the keys of the object. @@ -74,15 +117,15 @@ exports.inspect = function (obj, showHidden, depth) { // Functions without properties can be shortcutted. if (typeof value === 'function' && keys.length === 0) { if (isRegExp(value)) { - return '' + value; + return stylize('' + value, 'regexp'); } else { - return '[Function]'; + return stylize('[Function]', 'special'); } } // Dates without properties can be shortcutted if (isDate(value) && keys.length === 0) { - return value.toUTCString(); + return stylize(value.toUTCString(), 'date'); } var base, type, braces; @@ -115,9 +158,9 @@ exports.inspect = function (obj, showHidden, depth) { if (recurseTimes < 0) { if (isRegExp(value)) { - return '' + value; + return stylize('' + value, "regexp"); } else { - return "[Object]"; + return stylize("[Object]", "special"); } } @@ -126,13 +169,13 @@ exports.inspect = function (obj, showHidden, depth) { if (value.__lookupGetter__) { if (value.__lookupGetter__(key)) { if (value.__lookupSetter__(key)) { - str = "[Getter/Setter]"; + str = stylize("[Getter/Setter]", "special"); } else { - str = "[Getter]"; + str = stylize("[Getter]", "special"); } } else { if (value.__lookupSetter__(key)) { - str = "[Setter]"; + str = stylize("[Setter]", "special"); } } } @@ -160,7 +203,7 @@ exports.inspect = function (obj, showHidden, depth) { } } } else { - str = '[Circular]'; + str = stylize('[Circular]', 'special'); } } if (typeof name === 'undefined') { @@ -170,11 +213,13 @@ exports.inspect = function (obj, showHidden, depth) { name = JSON.stringify('' + key); if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { name = name.substr(1, name.length-2); + name = stylize(name, "name"); } else { name = name.replace(/'/g, "\\'") .replace(/\\"/g, '"') .replace(/(^"|"$)/g, "'"); + name = stylize(name, "string"); } }