diff --git a/lib/repl.js b/lib/repl.js index 762423be2d..499f95b3be 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -1,6 +1,5 @@ (function() { - var ACCESSOR, CoffeeScript, Module, REPL_PROMPT, REPL_PROMPT_CONTINUATION, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, getCompletions, getPropertyNames, inspect, readline, repl, run, stdin, stdout; - var __hasProp = Object.prototype.hasOwnProperty; + var ACCESSOR, CoffeeScript, Module, REPL_PROMPT, REPL_PROMPT_CONTINUATION, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, getCompletions, inspect, readline, repl, run, sandbox, stdin, stdout; CoffeeScript = require('./coffee-script'); readline = require('readline'); inspect = require('util').inspect; @@ -18,43 +17,40 @@ return stdout.write((err.stack || err.toString()) + '\n\n'); }; backlog = ''; - run = (function() { - var sandbox; - sandbox = Script.createContext(); - sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox; - return function(buffer) { - var code, returnValue, _; - if (!buffer.toString().trim() && !backlog) { - repl.prompt(); - return; - } - code = backlog += buffer; - if (code[code.length - 1] === '\\') { - backlog = "" + backlog.slice(0, -1) + "\n"; - repl.setPrompt(REPL_PROMPT_CONTINUATION); - repl.prompt(); - return; - } - repl.setPrompt(REPL_PROMPT); - backlog = ''; - try { - _ = sandbox._; - returnValue = CoffeeScript.eval("_=(" + code + "\n)", { - sandbox: sandbox, - filename: 'repl', - modulename: 'repl' - }); - if (returnValue === void 0) { - sandbox._ = _; - } else { - process.stdout.write(inspect(returnValue, false, 2, enableColours) + '\n'); - } - } catch (err) { - error(err); + sandbox = Script.createContext(); + sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox; + run = function(buffer) { + var code, returnValue, _; + if (!buffer.toString().trim() && !backlog) { + repl.prompt(); + return; + } + code = backlog += buffer; + if (code[code.length - 1] === '\\') { + backlog = "" + backlog.slice(0, -1) + "\n"; + repl.setPrompt(REPL_PROMPT_CONTINUATION); + repl.prompt(); + return; + } + repl.setPrompt(REPL_PROMPT); + backlog = ''; + try { + _ = sandbox._; + returnValue = CoffeeScript.eval("_=(" + code + "\n)", { + sandbox: sandbox, + filename: 'repl', + modulename: 'repl' + }); + if (returnValue === void 0) { + sandbox._ = _; + } else { + process.stdout.write(inspect(returnValue, false, 2, enableColours) + '\n'); } - return repl.prompt(); - }; - })(); + } catch (err) { + error(err); + } + return repl.prompt(); + }; ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/; SIMPLEVAR = /\s*(\w*)$/i; autocomplete = function(text) { @@ -65,19 +61,20 @@ if (match = text.match(ACCESSOR)) { all = match[0], obj = match[1], prefix = match[2]; try { - val = Script.runInThisContext(obj); + val = Script.runInContext(obj, sandbox); } catch (error) { - return [[], text]; + return; } - completions = getCompletions(prefix, getPropertyNames(val)); + completions = getCompletions(prefix, Object.getOwnPropertyNames(val)); return [completions, prefix]; } }; completeVariable = function(text) { - var completions, free, scope, _ref; + var completions, free, possibilities, vars, _ref; if (free = (_ref = text.match(SIMPLEVAR)) != null ? _ref[1] : void 0) { - scope = Script.runInThisContext('this'); - completions = getCompletions(free, CoffeeScript.RESERVED.concat(getPropertyNames(scope))); + vars = Script.runInContext('Object.getOwnPropertyNames(this)', sandbox); + possibilities = vars.concat(CoffeeScript.RESERVED); + completions = getCompletions(free, possibilities); return [completions, free]; } }; @@ -92,15 +89,6 @@ } return _results; }; - getPropertyNames = function(obj) { - var name, _results; - _results = []; - for (name in obj) { - if (!__hasProp.call(obj, name)) continue; - _results.push(name); - } - return _results; - }; process.on('uncaughtException', error); if (readline.createInterface.length < 3) { repl = readline.createInterface(stdin, autocomplete); diff --git a/src/repl.coffee b/src/repl.coffee index 9a6bc40816..90454e814f 100644 --- a/src/repl.coffee +++ b/src/repl.coffee @@ -31,39 +31,39 @@ error = (err) -> # The current backlog of multi-line code. backlog = '' +# The REPL context; must be visible outside `run` to allow for tab completion +sandbox = Script.createContext() +sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox + # The main REPL function. **run** is called every time a line of code is entered. # Attempt to evaluate the command. If there's an exception, print it out instead # of exiting. -run = do -> - # The REPL context - sandbox = Script.createContext() - sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox - (buffer) -> - if !buffer.toString().trim() and !backlog - repl.prompt() - return - code = backlog += buffer - if code[code.length - 1] is '\\' - backlog = "#{backlog[...-1]}\n" - repl.setPrompt REPL_PROMPT_CONTINUATION - repl.prompt() - return - repl.setPrompt REPL_PROMPT - backlog = '' - try - _ = sandbox._ - returnValue = CoffeeScript.eval "_=(#{code}\n)", { - sandbox, - filename: 'repl' - modulename: 'repl' - } - if returnValue is undefined - sandbox._ = _ - else - process.stdout.write inspect(returnValue, no, 2, enableColours) + '\n' - catch err - error err +run = (buffer) -> + if !buffer.toString().trim() and !backlog + repl.prompt() + return + code = backlog += buffer + if code[code.length - 1] is '\\' + backlog = "#{backlog[...-1]}\n" + repl.setPrompt REPL_PROMPT_CONTINUATION repl.prompt() + return + repl.setPrompt REPL_PROMPT + backlog = '' + try + _ = sandbox._ + returnValue = CoffeeScript.eval "_=(#{code}\n)", { + sandbox, + filename: 'repl' + modulename: 'repl' + } + if returnValue is undefined + sandbox._ = _ + else + process.stdout.write inspect(returnValue, no, 2, enableColours) + '\n' + catch err + error err + repl.prompt() ## Autocompletion @@ -80,27 +80,24 @@ completeAttribute = (text) -> if match = text.match ACCESSOR [all, obj, prefix] = match try - val = Script.runInThisContext obj + val = Script.runInContext obj, sandbox catch error - return [[], text] - completions = getCompletions prefix, getPropertyNames val + return + completions = getCompletions prefix, Object.getOwnPropertyNames val [completions, prefix] # Attempt to autocomplete an in-scope free variable: `one`. completeVariable = (text) -> - if free = text.match(SIMPLEVAR)?[1] - scope = Script.runInThisContext 'this' - completions = getCompletions free, CoffeeScript.RESERVED.concat(getPropertyNames scope) + if free = (text.match SIMPLEVAR)?[1] + vars = Script.runInContext 'Object.getOwnPropertyNames(this)', sandbox + possibilities = vars.concat CoffeeScript.RESERVED + completions = getCompletions free, possibilities [completions, free] # Return elements of candidates for which `prefix` is a prefix. getCompletions = (prefix, candidates) -> (el for el in candidates when el.indexOf(prefix) is 0) -# Return all "own" properties of an object. -getPropertyNames = (obj) -> - (name for own name of obj) - # Make sure that uncaught exceptions don't kill the REPL. process.on 'uncaughtException', error