From 2a9fd34a035e573934427af1a4d5f2397bad6565 Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Wed, 6 Jul 2011 16:31:48 -0400 Subject: [PATCH] Made line continuations in the REPL much, much nicer and moved all of the REPL-specific code out of CoffeeScript.eval and into the REPL function (thanks for the suggestion, @TrevorBurnham) --- lib/coffee-script.js | 11 +++-------- lib/repl.js | 33 +++++++++++++++++++++++---------- src/coffee-script.coffee | 7 ++----- src/repl.coffee | 29 +++++++++++++++++++++-------- 4 files changed, 49 insertions(+), 31 deletions(-) diff --git a/lib/coffee-script.js b/lib/coffee-script.js index 84a7c3b7bf..c0536cfaf2 100755 --- a/lib/coffee-script.js +++ b/lib/coffee-script.js @@ -62,7 +62,7 @@ } }; exports.eval = function(code, options) { - var js, k, o, r, returnValue, sandbox, v, _, _i, _len, _module, _ref2, _ref3, _require; + var js, k, o, r, sandbox, v, _i, _len, _module, _ref2, _ref3, _require; if (options == null) { options = {}; } @@ -109,13 +109,8 @@ o[k] = v; } o.bare = true; - js = compile("_=(" + code + "\n)", o); - _ = sandbox._; - returnValue = Script.runInContext(js, sandbox); - if (returnValue === void 0) { - sandbox._ = _; - } - return returnValue; + js = compile(code, o); + return Script.runInContext(js, sandbox); }; lexer = new Lexer; parser.lexer = { diff --git a/lib/repl.js b/lib/repl.js index fb2392bafe..daf32632ac 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -1,11 +1,13 @@ (function() { - var ACCESSOR, CoffeeScript, Module, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, getCompletions, getPropertyNames, inspect, readline, repl, run, stdin, stdout; + var ACCESSOR, CoffeeScript, Module, REPL_PROMPT, REPL_PROMPT_CONTINUATION, SIMPLEVAR, Script, autocomplete, completeAttribute, completeVariable, enableColours, error, getCompletions, getPropertyNames, inspect, readline, repl, run, stdin, stdout; var __hasProp = Object.prototype.hasOwnProperty; CoffeeScript = require('./coffee-script'); readline = require('readline'); inspect = require('util').inspect; Script = require('vm').Script; Module = require('module'); + REPL_PROMPT = 'coffee> '; + REPL_PROMPT_CONTINUATION = '......> '; enableColours = false; if (process.platform !== 'win32') { enableColours = !process.env.NODE_DISABLE_COLORS; @@ -15,26 +17,37 @@ error = function(err) { return stdout.write((err.stack || err.toString()) + '\n\n'); }; - backlog = ''; run = (function() { - var sandbox; + var backlog, sandbox; + backlog = ''; sandbox = Script.createContext(); sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox; return function(buffer) { - var code, val; - code = backlog += '\n' + buffer.toString(); + var code, returnValue, _; + if (!buffer.toString().trim()) { + repl.prompt(); + return; + } + code = backlog += buffer; if (code[code.length - 1] === '\\') { - return backlog = backlog.slice(0, backlog.length - 1); + backlog = "" + backlog.slice(0, -1) + "\n"; + repl.setPrompt(REPL_PROMPT_CONTINUATION); + repl.prompt(); + return; } + repl.setPrompt(REPL_PROMPT); backlog = ''; try { - val = CoffeeScript.eval(code, { + _ = sandbox._; + returnValue = CoffeeScript.eval("_=(" + code + "\n)", { sandbox: sandbox, filename: 'repl', modulename: 'repl' }); - if (val !== void 0) { - process.stdout.write(inspect(val, false, 2, enableColours) + '\n'); + if (returnValue === void 0) { + sandbox._ = _; + } else { + process.stdout.write(inspect(returnValue, false, 2, enableColours) + '\n'); } } catch (err) { error(err); @@ -97,7 +110,7 @@ } else { repl = readline.createInterface(stdin, stdout, autocomplete); } - repl.setPrompt('coffee> '); + repl.setPrompt(REPL_PROMPT); repl.on('close', function() { process.stdout.write('\n'); return stdin.destroy(); diff --git a/src/coffee-script.coffee b/src/coffee-script.coffee index c5fc8251b1..7a22875665 100755 --- a/src/coffee-script.coffee +++ b/src/coffee-script.coffee @@ -101,11 +101,8 @@ exports.eval = (code, options = {}) -> o = {} o[k] = v for own k, v of options o.bare = on # ensure return value - js = compile "_=(#{code}\n)", o - _ = sandbox._ - returnValue = Script.runInContext js, sandbox - sandbox._ = _ if returnValue is undefined - returnValue + js = compile code, o + Script.runInContext js, sandbox # Instantiate a Lexer for our use here. lexer = new Lexer diff --git a/src/repl.coffee b/src/repl.coffee index 0ffac23bcc..cec5a06ba6 100644 --- a/src/repl.coffee +++ b/src/repl.coffee @@ -14,6 +14,8 @@ Module = require 'module' # REPL Setup # Config +REPL_PROMPT = 'coffee> ' +REPL_PROMPT_CONTINUATION = '......> ' enableColours = no unless process.platform is 'win32' enableColours = not process.env.NODE_DISABLE_COLORS @@ -26,28 +28,39 @@ stdout = process.stdout error = (err) -> stdout.write (err.stack or err.toString()) + '\n\n' -# The current backlog of multi-line code. -backlog = '' # 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 current backlog of multi-line code. + backlog = '' + # The REPL context sandbox = Script.createContext() sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox (buffer) -> - code = backlog += '\n' + buffer.toString() + unless buffer.toString().trim() + repl.prompt() + return + code = backlog += buffer if code[code.length - 1] is '\\' - return backlog = backlog[0...backlog.length - 1] + backlog = "#{backlog[...-1]}\n" + repl.setPrompt REPL_PROMPT_CONTINUATION + repl.prompt() + return + repl.setPrompt REPL_PROMPT backlog = '' try - val = CoffeeScript.eval code, { + _ = sandbox._ + returnValue = CoffeeScript.eval "_=(#{code}\n)", { sandbox, filename: 'repl' modulename: 'repl' } - unless val is undefined - process.stdout.write inspect(val, no, 2, enableColours) + '\n' + if returnValue is undefined + sandbox._ = _ + else + process.stdout.write inspect(returnValue, no, 2, enableColours) + '\n' catch err error err repl.prompt() @@ -98,7 +111,7 @@ if readline.createInterface.length < 3 else repl = readline.createInterface stdin, stdout, autocomplete -repl.setPrompt 'coffee> ' +repl.setPrompt REPL_PROMPT repl.on 'close', -> process.stdout.write '\n' stdin.destroy()