repl.coffee | |
---|---|
A very simple Read-Eval-Print-Loop. Compiles one line at a time to JavaScript and evaluates it. Good for simple tests, or poking around the Node.js API. Using it looks like this: | |
Require the coffee-script module to get access to the compiler. | CoffeeScript = require './coffee-script'
readline = require 'readline'
{inspect} = require 'util'
{Script} = require 'vm' |
REPL Setup | |
Config | enableColours = no
unless process.platform is 'win32'
enableColours = not process.env.NODE_DISABLE_COLORS |
Start by opening up | stdin = process.openStdin()
stdout = process.stdout |
Log an error. | 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 ->
sandbox =
require: require
module : { exports: {} }
sandbox[g] = global[g] for g of global
sandbox.global = sandbox
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox
(buffer) ->
code = backlog += '\n' + buffer.toString()
if code[code.length - 1] is '\\'
return backlog = backlog[0...backlog.length - 1]
backlog = ''
try
val = CoffeeScript.eval code, {
sandbox,
bare: on,
filename: 'repl'
}
unless val is undefined
process.stdout.write inspect(val, no, 2, enableColours) + '\n'
catch err
error err
repl.prompt() |
Autocompletion | |
Regexes to match complete-able bits of text. | ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/
SIMPLEVAR = /\s*(\w*)$/i |
Returns a list of completions, and the completed text. | autocomplete = (text) ->
completeAttribute(text) or completeVariable(text) or [[], text] |
Attempt to autocomplete a chained dotted attribute: | completeAttribute = (text) ->
if match = text.match ACCESSOR
[all, obj, prefix] = match
try
val = Script.runInThisContext obj
catch error
return [[], text]
completions = getCompletions prefix, getPropertyNames val
[completions, prefix] |
Attempt to autocomplete an in-scope free variable: | completeVariable = (text) ->
if free = text.match(SIMPLEVAR)?[1]
scope = Script.runInThisContext 'this'
completions = getCompletions free, CoffeeScript.RESERVED.concat(getPropertyNames scope)
[completions, free] |
Return elements of candidates for which | 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 |
Create the REPL by listening to stdin. | if readline.createInterface.length < 3
repl = readline.createInterface stdin, autocomplete
stdin.on 'data', (buffer) -> repl.write buffer
else
repl = readline.createInterface stdin, stdout, autocomplete
repl.setPrompt 'coffee> '
repl.on 'close', -> stdin.destroy()
repl.on 'line', run
repl.prompt()
|