|
|
@ -16,6 +16,7 @@ var sys = require('sys'); |
|
|
|
var Script = process.binding('evals').Script; |
|
|
|
var evalcx = Script.runInContext; |
|
|
|
var path = require("path"); |
|
|
|
var fs = require("fs"); |
|
|
|
var rl = require('readline'); |
|
|
|
var context; |
|
|
|
|
|
|
@ -162,7 +163,7 @@ REPLServer.prototype.complete = function (line) { |
|
|
|
completeOn, |
|
|
|
match, filter, i, j, group, c; |
|
|
|
|
|
|
|
// REPL comments (e.g. ".break").
|
|
|
|
// REPL commands (e.g. ".break").
|
|
|
|
var match = null; |
|
|
|
match = line.match(/^\s*(\.\w*)$/); |
|
|
|
if (match) { |
|
|
@ -173,6 +174,72 @@ REPLServer.prototype.complete = function (line) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// require('...<Tab>')
|
|
|
|
else if (match = line.match(/\brequire\s*\(['"](([\w\.\/-]+\/)?([\w\.\/-]*))/)) { |
|
|
|
//TODO: suggest require.exts be exposed to be introspec registered extensions?
|
|
|
|
//TODO: suggest include the '.' in exts in internal repr: parity with `path.extname`.
|
|
|
|
var exts = [".js", ".node"]; |
|
|
|
var indexRe = new RegExp('^index(' + exts.map(regexpEscape).join('|') + ')$'); |
|
|
|
|
|
|
|
completeOn = match[1]; |
|
|
|
var subdir = match[2] || ""; |
|
|
|
var filter = match[1]; |
|
|
|
var dir, files, f, name, base, ext, abs, subfiles, s; |
|
|
|
group = []; |
|
|
|
for (i = 0; i < require.paths.length; i++) { |
|
|
|
dir = require.paths[i]; |
|
|
|
if (subdir && subdir[0] === '/') { |
|
|
|
dir = subdir; |
|
|
|
} else if (subdir) { |
|
|
|
dir = path.join(dir, subdir); |
|
|
|
} |
|
|
|
try { |
|
|
|
files = fs.readdirSync(dir); |
|
|
|
} catch (e) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
for (f = 0; f < files.length; f++) { |
|
|
|
name = files[f]; |
|
|
|
ext = path.extname(name); |
|
|
|
base = name.slice(0, -ext.length); |
|
|
|
if (base.match(/-\d+\.\d+(\.\d+)?/) || name === ".npm") { |
|
|
|
// Exclude versioned names that 'npm' installs.
|
|
|
|
continue; |
|
|
|
} |
|
|
|
if (exts.indexOf(ext) !== -1) { |
|
|
|
if (!subdir || base !== "index") { |
|
|
|
group.push(subdir + base); |
|
|
|
} |
|
|
|
} else { |
|
|
|
abs = path.join(dir, name); |
|
|
|
try { |
|
|
|
if (fs.statSync(abs).isDirectory()) { |
|
|
|
group.push(subdir + name + '/'); |
|
|
|
subfiles = fs.readdirSync(abs); |
|
|
|
for (s = 0; s < subfiles.length; s++) { |
|
|
|
if (indexRe.test(subfiles[s])) { |
|
|
|
group.push(subdir + name); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch(e) {} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (group.length) { |
|
|
|
completionGroups.push(group); |
|
|
|
} |
|
|
|
|
|
|
|
if (!subdir) { |
|
|
|
// Kind of lame that this needs to be updated manually.
|
|
|
|
// Intentionally excluding moved modules: posix, utils.
|
|
|
|
var builtinLibs = ['assert', 'buffer', 'child_process', 'crypto', 'dgram', |
|
|
|
'dns', 'events', 'file', 'freelist', 'fs', 'http', 'net', 'path', |
|
|
|
'querystring', 'readline', 'repl', 'string_decoder', 'sys', 'tcp', 'url']; |
|
|
|
completionGroups.push(builtinLibs); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Handle variable member lookup.
|
|
|
|
// We support simple chained expressions like the following (no function
|
|
|
|
// calls, etc.). That is for simplicity and also because we *eval* that
|
|
|
@ -348,6 +415,10 @@ function trimWhitespace (cmd) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function regexpEscape(s) { |
|
|
|
return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Converts commands that use var and function <name>() to use the |
|
|
|
* local exports.context when evaled. This provides a local context |
|
|
|