Permalink
Browse files

repl completion: completion for arguments to "require"

  • Loading branch information...
1 parent 2134982 commit 5c1ffa165f67a2bb0fc726e4b7402249b7a895ab @trentm trentm committed with ry Aug 17, 2010
Showing with 72 additions and 1 deletion.
  1. +72 −1 lib/repl.js
View
@@ -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

0 comments on commit 5c1ffa1

Please sign in to comment.