From eab65e214e6505f308e91d4aaf1896f92e5dca5e Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Wed, 7 Sep 2011 17:31:29 +0700 Subject: [PATCH] [repl] Async global completion --- lib/repl.js | 99 +++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 36 deletions(-) diff --git a/lib/repl.js b/lib/repl.js index 3948a98..db0d06f 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -171,43 +171,36 @@ function REPLServer(prompt, stream) { e.constructor.name === 'SyntaxError')) { finish(e); } else { - tryExpr(); + tryExpr(e); } return; } - if (typeof ret !== 'function') { - return tryExpr(ret); - } - - tryExpr(); + tryExpr(typeof ret === 'function', ret); }); }; // Now as statement without parens. - function tryExpr(ret) { - - self.bufferedCommand = ''; - - if (ret !== undefined) { - self.context._ = ret; - self.outputStream.write(exports.writer(ret) + '\n'); - return finish(null); - } + function tryExpr(e, ret) { + if (!e) return finish(null, ret); self.eval(self.bufferedCommand, self.context, 'repl', function(e, ret) { if (e) { // instanceof doesn't work across context switches. - if (!(e && e.constructor && e.constructor.name === 'SyntaxError')) { + if (!(e && e.constructor && + e.constructor.name === 'SyntaxError')) { return finish(e); - // It could also be an error from JSON.parse + // It could also be an error from JSON.parse } else if (e && e.stack && e.stack.match(/^SyntaxError: Unexpected token .*\n/) && e.stack.match(/\n at Object.parse \(native\)\n/)) { return finish(e); + } else { + finish(true); + return; } } finish(null, ret); @@ -222,12 +215,23 @@ function REPLServer(prompt, stream) { if (e) { if (e.stack) { self.outputStream.write(e.stack + '\n'); + } else if (e === true) { + self.displayPrompt(); + return; } else { self.outputStream.write(e.toString() + '\n'); } // On error: Print the error and clear the buffer self.bufferedCommand = ''; + } else { + self.bufferedCommand = ''; + } + + if (ret !== undefined) { + self.context._ = ret; + self.outputStream.write(exports.writer(ret) + '\n'); } + self.displayPrompt(); }; }); @@ -413,25 +417,48 @@ REPLServer.prototype.complete = function(line, callback) { // Resolve expr and get its completions. var obj, memberGroups = []; if (!expr) { - completionGroups.push(Object.getOwnPropertyNames(this.context)); - // Global object properties - // (http://www.ecma-international.org/publications/standards/Ecma-262.htm) - completionGroups.push(['NaN', 'Infinity', 'undefined', - 'eval', 'parseInt', 'parseFloat', 'isNaN', 'isFinite', 'decodeURI', - 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', - 'Object', 'Function', 'Array', 'String', 'Boolean', 'Number', - 'Date', 'RegExp', 'Error', 'EvalError', 'RangeError', - 'ReferenceError', 'SyntaxError', 'TypeError', 'URIError', - 'Math', 'JSON']); - // Common keywords. Exclude for completion on the empty string, b/c - // they just get in the way. - if (filter) { - completionGroups.push(['break', 'case', 'catch', 'const', - 'continue', 'debugger', 'default', 'delete', 'do', 'else', 'export', - 'false', 'finally', 'for', 'function', 'if', 'import', 'in', - 'instanceof', 'let', 'new', 'null', 'return', 'switch', 'this', - 'throw', 'true', 'try', 'typeof', 'undefined', 'var', 'void', - 'while', 'with', 'yield']); + if (this.context.constructor.name === 'Context') { + completionGroups.push(Object.getOwnPropertyNames(this.context)); + next(); + } else { + this.eval('.scope', this.context, 'repl', function(err, globals) { + if (Array.isArray(globals[0])) { + // Add grouped globals + globals.forEach(function(group) { + completionGroups.push(group); + }); + finish(); + } else { + completionGroups.push(globals); + next(); + } + }); + } + + return; + + function next() { + // Global object properties + // (http://www.ecma-international.org/publications/standards/Ecma-262.htm) + completionGroups.push(['NaN', 'Infinity', 'undefined', + 'eval', 'parseInt', 'parseFloat', 'isNaN', 'isFinite', 'decodeURI', + 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', + 'Object', 'Function', 'Array', 'String', 'Boolean', 'Number', + 'Date', 'RegExp', 'Error', 'EvalError', 'RangeError', + 'ReferenceError', 'SyntaxError', 'TypeError', 'URIError', + 'Math', 'JSON']); + // Common keywords. Exclude for completion on the empty string, b/c + // they just get in the way. + if (filter) { + completionGroups.push(['break', 'case', 'catch', 'const', + 'continue', 'debugger', 'default', 'delete', 'do', 'else', 'export', + 'false', 'finally', 'for', 'function', 'if', 'import', 'in', + 'instanceof', 'let', 'new', 'null', 'return', 'switch', 'this', + 'throw', 'true', 'try', 'typeof', 'undefined', 'var', 'void', + 'while', 'with', 'yield']); + } + + finish(); } } else { this.eval(expr, this.context, 'repl', function(e, obj) { -- 2.7.4