From d624a683c160422ca03e7fd78a16686a5154756f Mon Sep 17 00:00:00 2001 From: seebees Date: Fri, 9 Aug 2013 21:39:54 -0700 Subject: [PATCH] REPL: tab complete for Arrays The tab complete for Arrays will include any integer indexes. This is suboptimal because obj.21 is not valid syntax and a large array will contain a very cluttered list. --- lib/repl.js | 15 ++- ...-complete-array-remove-integer-elements.js | 107 ++++++++++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 test/simple/test-repl-tab-complete-array-remove-integer-elements.js diff --git a/lib/repl.js b/lib/repl.js index 7b501412f557..f6e2e7d51c6d 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -580,7 +580,20 @@ REPLServer.prototype.complete = function(line, callback) { // if (e) console.log(e); if (obj != null) { - if (util.isObject(obj) || util.isFunction(obj)) { + if (util.isArray(obj)) { + // Array elements will contain many integer values + // if we return them in memberGroups they will appear + // as obj.0 obj.100 etc. which is not valid syntax. + // Additionally for large arrays this can make for a + // very cluttered list. So I filter them out. + memberGroups + .push(Object + .getOwnPropertyNames(obj) + .filter(function(element) { + // parseInt('0', 10) == 0 + return element == 0 ? false : !parseInt(element, 10); + })); + } else if (util.isObject(obj) || util.isFunction(obj)) { memberGroups.push(Object.getOwnPropertyNames(obj)); } // works for non-objects diff --git a/test/simple/test-repl-tab-complete-array-remove-integer-elements.js b/test/simple/test-repl-tab-complete-array-remove-integer-elements.js new file mode 100644 index 000000000000..620d36eefc60 --- /dev/null +++ b/test/simple/test-repl-tab-complete-array-remove-integer-elements.js @@ -0,0 +1,107 @@ +// 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. + +var common = require('../common'); +var assert = require('assert'); +var util = require('util'); + +var repl = require('repl'); + +// A stream to push an array into a REPL +function ArrayStream() { + this.run = function(data) { + var self = this; + data.forEach(function(line) { + self.emit('data', line + '\n'); + }); + } +} +util.inherits(ArrayStream, require('stream').Stream); +ArrayStream.prototype.readable = true; +ArrayStream.prototype.writable = true; +ArrayStream.prototype.resume = function() {}; +ArrayStream.prototype.write = function() {}; + +var array_elements = [ + [ 'asdf.__defineGetter__', 'asdf.__defineSetter__', + 'asdf.__lookupGetter__', 'asdf.__lookupSetter__', + 'asdf.__proto__', 'asdf.constructor', + 'asdf.hasOwnProperty', 'asdf.isPrototypeOf', + 'asdf.propertyIsEnumerable', + 'asdf.toLocaleString', 'asdf.toString', + 'asdf.valueOf', '', 'asdf.concat', 'asdf.constructor', + 'asdf.every', 'asdf.filter', + 'asdf.forEach', 'asdf.indexOf', + 'asdf.join', 'asdf.lastIndexOf', + 'asdf.length', 'asdf.map', + 'asdf.pop', 'asdf.push', 'asdf.reduce', + 'asdf.reduceRight', 'asdf.reverse', 'asdf.shift', + 'asdf.slice', 'asdf.some', 'asdf.sort', 'asdf.splice', + 'asdf.toLocaleString', 'asdf.toString', 'asdf.unshift', + '', 'asdf.length' ], + 'asdf.' ]; + +var object_elements = [ + [ 'asdf.__defineGetter__', 'asdf.__defineSetter__', + 'asdf.__lookupGetter__', 'asdf.__lookupSetter__', + 'asdf.__proto__', 'asdf.constructor', + 'asdf.hasOwnProperty', 'asdf.isPrototypeOf', + 'asdf.propertyIsEnumerable', + 'asdf.toLocaleString', 'asdf.toString', + 'asdf.valueOf', '', 'asdf.1'], + 'asdf.' ]; + +var putIn = new ArrayStream(); +var testMe = repl.start('', putIn); + +// Tab Complete will not return integer indexes +putIn.run(['.clear']); +putIn.run([ + 'asdf = [\'one\', 2, 3]', +]); +testMe.complete('asdf.', function(error, data) { + assert.deepEqual(data, array_elements); +}); + +// Tab Complete will return additional non-integer indexes +putIn.run(['.clear']); +putIn.run([ + 'asdf = [\'one\', 2, 3]', + 'asdf.qwer = 1' +]); + +var array_with_extra = array_elements; +array_with_extra[0].push('qwer'); + +testMe.complete('asdf.', function(error, data) { + assert.deepEqual(data, array_with_extra); +}); + +// Tab Complete will return integer indexes on an object +putIn.run(['.clear']); +putIn.run([ + 'asdf = {}', + 'asdf[1] = 1' +]); +testMe.complete('asdf.', function(error, data) { + assert.deepEqual(data, object_elements); +}); +