From 4a52814a795e234afe401723fd38f14a2ae52e10 Mon Sep 17 00:00:00 2001 From: Alon Salant Date: Tue, 15 Jan 2013 23:31:40 -0800 Subject: [PATCH] Multiline WIP --- lib/coffee-script/repl.js | 54 +++++++++++++++++++++++++++++++++++---- src/repl.coffee | 46 ++++++++++++++++++++++++++++++--- 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/lib/coffee-script/repl.js b/lib/coffee-script/repl.js index 0e1b2432..2b39ec01 100644 --- a/lib/coffee-script/repl.js +++ b/lib/coffee-script/repl.js @@ -1,22 +1,23 @@ // Generated by CoffeeScript 1.5.0-pre (function() { - var CoffeeScript, merge, repl, replDefaults, vm; + var CoffeeScript, addMultilineHandler, merge, nodeREPL, replDefaults, vm; vm = require('vm'); - repl = require('repl'); + nodeREPL = require('repl'); CoffeeScript = require('./coffee-script'); merge = require('./helpers').merge; replDefaults = { - prompt: "coffee> ", + prompt: 'coffee> ', "eval": function(code, context, file, cb) { try { if (/^\(\s+\)$/.test(code)) { - code = ''; + return cb(null); } + code = code.replace(/子/mg, '\n'); code = CoffeeScript.compile(code, { filename: file, bare: true @@ -28,12 +29,55 @@ } }; + addMultilineHandler = function(repl) { + var inputStream, multiline, nodeLineListener, outputStream, rli; + rli = repl.rli, inputStream = repl.inputStream, outputStream = repl.outputStream; + multiline = { + enabled: false, + prompt: new Array(repl.prompt.length).join('.') + ' ', + buffer: '' + }; + nodeLineListener = rli.listeners('line')[0]; + rli.removeListener('line', nodeLineListener); + rli.on('line', function(cmd) { + if (multiline.enabled === true) { + multiline.buffer += "" + cmd + "\n"; + return rli.prompt(true); + } else { + return nodeLineListener(cmd); + } + }); + return inputStream.on('keypress', function(char, key) { + if (!(key && key.ctrl && !key.meta && !key.shift && key.name === 'v')) { + return; + } + multiline.enabled = !multiline.enabled; + if (multiline.enabled === false) { + if (!multiline.buffer.match(/\n/)) { + rli.setPrompt(repl.prompt); + rli.prompt(true); + return; + } + multiline.buffer = multiline.buffer.replace(/\n/mg, '子'); + rli.emit('line', multiline.buffer); + return multiline.buffer = ''; + } else { + rli.setPrompt(multiline.prompt); + return rli.prompt(true); + } + }); + }; + module.exports = { start: function(opts) { + var repl; if (opts == null) { opts = {}; } - return repl.start(merge(replDefaults, opts)); + opts = merge(replDefaults, opts); + repl = nodeREPL.start(opts); + addMultilineHandler(repl); + return repl; } }; diff --git a/src/repl.coffee b/src/repl.coffee index 393aac28..7a853caf 100644 --- a/src/repl.coffee +++ b/src/repl.coffee @@ -1,5 +1,5 @@ vm = require 'vm' -repl = require 'repl' +nodeREPL = require 'repl' CoffeeScript = require './coffee-script' {merge} = require './helpers' @@ -7,12 +7,52 @@ replDefaults = prompt: 'coffee> ', eval: (code, context, file, cb) -> try - code = '' if /^\(\s+\)$/.test code # Empty command won't parse + return cb(null) if /^\(\s+\)$/.test code # Empty command + code = code.replace /子/mg, '\n' # Temporary hack, see TODO below code = CoffeeScript.compile(code, {filename: file, bare: true}) cb(null, vm.runInContext(code, context, file)) catch err cb(err) +# TODO: how to test? +addMultilineHandler = (repl) -> + {rli, inputStream, outputStream} = repl + + multiline = + enabled: off + prompt: new Array(repl.prompt.length).join('.') + ' ' + buffer: '' + + # Proxy node's line listener + nodeLineListener = rli.listeners('line')[0] + rli.removeListener 'line', nodeLineListener + rli.on 'line', (cmd) -> + if multiline.enabled is on + multiline.buffer += "#{cmd}\n" + rli.prompt true + else + nodeLineListener(cmd) + + # Handle Ctrl-v + inputStream.on 'keypress', (char, key) -> + return unless key and key.ctrl and not key.meta and not key.shift and key.name is 'v' + multiline.enabled = !multiline.enabled + if multiline.enabled is off + unless multiline.buffer.match /\n/ + rli.setPrompt repl.prompt + rli.prompt true + return + # TODO: how to encode line breaks so the node repl will pass the complete multiline to our eval? + multiline.buffer = multiline.buffer.replace /\n/mg, '子' + rli.emit 'line', multiline.buffer + multiline.buffer = '' + else + rli.setPrompt multiline.prompt + rli.prompt true + module.exports = start: (opts = {}) -> - repl.start merge(replDefaults, opts) + opts = merge(replDefaults, opts) + repl = nodeREPL.start opts + addMultilineHandler(repl) + repl \ No newline at end of file