1 |
|
2 | (function() {
|
3 | var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, ref, replDefaults, runInContext, updateSyntaxError, vm;
|
4 |
|
5 | fs = require('fs');
|
6 |
|
7 | path = require('path');
|
8 |
|
9 | vm = require('vm');
|
10 |
|
11 | nodeREPL = require('repl');
|
12 |
|
13 | CoffeeScript = require('./coffee-script');
|
14 |
|
15 | ref = require('./helpers'), merge = ref.merge, updateSyntaxError = ref.updateSyntaxError;
|
16 |
|
17 | replDefaults = {
|
18 | prompt: 'coffee> ',
|
19 | historyFile: process.env.HOME ? path.join(process.env.HOME, '.coffee_history') : void 0,
|
20 | historyMaxInputSize: 10240,
|
21 | "eval": function(input, context, filename, cb) {
|
22 | var Assign, Block, Literal, Value, ast, err, js, ref1, referencedVars, token, tokens;
|
23 | input = input.replace(/\uFF00/g, '\n');
|
24 | input = input.replace(/^\(([\s\S]*)\n\)$/m, '$1');
|
25 | ref1 = require('./nodes'), Block = ref1.Block, Assign = ref1.Assign, Value = ref1.Value, Literal = ref1.Literal;
|
26 | try {
|
27 | tokens = CoffeeScript.tokens(input);
|
28 | referencedVars = (function() {
|
29 | var i, len, results;
|
30 | results = [];
|
31 | for (i = 0, len = tokens.length; i < len; i++) {
|
32 | token = tokens[i];
|
33 | if (token.variable) {
|
34 | results.push(token[1]);
|
35 | }
|
36 | }
|
37 | return results;
|
38 | })();
|
39 | ast = CoffeeScript.nodes(tokens);
|
40 | ast = new Block([new Assign(new Value(new Literal('_')), ast, '=')]);
|
41 | js = ast.compile({
|
42 | bare: true,
|
43 | locals: Object.keys(context),
|
44 | referencedVars: referencedVars
|
45 | });
|
46 | return cb(null, runInContext(js, context, filename));
|
47 | } catch (_error) {
|
48 | err = _error;
|
49 | updateSyntaxError(err, input);
|
50 | return cb(err);
|
51 | }
|
52 | }
|
53 | };
|
54 |
|
55 | runInContext = function(js, context, filename) {
|
56 | if (context === global) {
|
57 | return vm.runInThisContext(js, filename);
|
58 | } else {
|
59 | return vm.runInContext(js, context, filename);
|
60 | }
|
61 | };
|
62 |
|
63 | addMultilineHandler = function(repl) {
|
64 | var inputStream, multiline, nodeLineListener, origPrompt, outputStream, ref1, rli;
|
65 | rli = repl.rli, inputStream = repl.inputStream, outputStream = repl.outputStream;
|
66 | origPrompt = (ref1 = repl._prompt) != null ? ref1 : repl.prompt;
|
67 | multiline = {
|
68 | enabled: false,
|
69 | initialPrompt: origPrompt.replace(/^[^> ]*/, function(x) {
|
70 | return x.replace(/./g, '-');
|
71 | }),
|
72 | prompt: origPrompt.replace(/^[^> ]*>?/, function(x) {
|
73 | return x.replace(/./g, '.');
|
74 | }),
|
75 | buffer: ''
|
76 | };
|
77 | nodeLineListener = rli.listeners('line')[0];
|
78 | rli.removeListener('line', nodeLineListener);
|
79 | rli.on('line', function(cmd) {
|
80 | if (multiline.enabled) {
|
81 | multiline.buffer += cmd + "\n";
|
82 | rli.setPrompt(multiline.prompt);
|
83 | rli.prompt(true);
|
84 | } else {
|
85 | rli.setPrompt(origPrompt);
|
86 | nodeLineListener(cmd);
|
87 | }
|
88 | });
|
89 | return inputStream.on('keypress', function(char, key) {
|
90 | if (!(key && key.ctrl && !key.meta && !key.shift && key.name === 'v')) {
|
91 | return;
|
92 | }
|
93 | if (multiline.enabled) {
|
94 | if (!multiline.buffer.match(/\n/)) {
|
95 | multiline.enabled = !multiline.enabled;
|
96 | rli.setPrompt(origPrompt);
|
97 | rli.prompt(true);
|
98 | return;
|
99 | }
|
100 | if ((rli.line != null) && !rli.line.match(/^\s*$/)) {
|
101 | return;
|
102 | }
|
103 | multiline.enabled = !multiline.enabled;
|
104 | rli.line = '';
|
105 | rli.cursor = 0;
|
106 | rli.output.cursorTo(0);
|
107 | rli.output.clearLine(1);
|
108 | multiline.buffer = multiline.buffer.replace(/\n/g, '\uFF00');
|
109 | rli.emit('line', multiline.buffer);
|
110 | multiline.buffer = '';
|
111 | } else {
|
112 | multiline.enabled = !multiline.enabled;
|
113 | rli.setPrompt(multiline.initialPrompt);
|
114 | rli.prompt(true);
|
115 | }
|
116 | });
|
117 | };
|
118 |
|
119 | addHistory = function(repl, filename, maxSize) {
|
120 | var buffer, fd, lastLine, readFd, size, stat;
|
121 | lastLine = null;
|
122 | try {
|
123 | stat = fs.statSync(filename);
|
124 | size = Math.min(maxSize, stat.size);
|
125 | readFd = fs.openSync(filename, 'r');
|
126 | buffer = new Buffer(size);
|
127 | fs.readSync(readFd, buffer, 0, size, stat.size - size);
|
128 | fs.close(readFd);
|
129 | repl.rli.history = buffer.toString().split('\n').reverse();
|
130 | if (stat.size > maxSize) {
|
131 | repl.rli.history.pop();
|
132 | }
|
133 | if (repl.rli.history[0] === '') {
|
134 | repl.rli.history.shift();
|
135 | }
|
136 | repl.rli.historyIndex = -1;
|
137 | lastLine = repl.rli.history[0];
|
138 | } catch (_error) {}
|
139 | fd = fs.openSync(filename, 'a');
|
140 | repl.rli.addListener('line', function(code) {
|
141 | if (code && code.length && code !== '.history' && lastLine !== code) {
|
142 | fs.write(fd, code + "\n");
|
143 | return lastLine = code;
|
144 | }
|
145 | });
|
146 | repl.on('exit', function() {
|
147 | return fs.close(fd);
|
148 | });
|
149 | return repl.commands[getCommandId(repl, 'history')] = {
|
150 | help: 'Show command history',
|
151 | action: function() {
|
152 | repl.outputStream.write((repl.rli.history.slice(0).reverse().join('\n')) + "\n");
|
153 | return repl.displayPrompt();
|
154 | }
|
155 | };
|
156 | };
|
157 |
|
158 | getCommandId = function(repl, commandName) {
|
159 | var commandsHaveLeadingDot;
|
160 | commandsHaveLeadingDot = repl.commands['.help'] != null;
|
161 | if (commandsHaveLeadingDot) {
|
162 | return "." + commandName;
|
163 | } else {
|
164 | return commandName;
|
165 | }
|
166 | };
|
167 |
|
168 | module.exports = {
|
169 | start: function(opts) {
|
170 | var build, major, minor, ref1, repl;
|
171 | if (opts == null) {
|
172 | opts = {};
|
173 | }
|
174 | ref1 = process.versions.node.split('.').map(function(n) {
|
175 | return parseInt(n);
|
176 | }), major = ref1[0], minor = ref1[1], build = ref1[2];
|
177 | if (major === 0 && minor < 8) {
|
178 | console.warn("Node 0.8.0+ required for CoffeeScript REPL");
|
179 | process.exit(1);
|
180 | }
|
181 | CoffeeScript.register();
|
182 | process.argv = ['coffee'].concat(process.argv.slice(2));
|
183 | opts = merge(replDefaults, opts);
|
184 | repl = nodeREPL.start(opts);
|
185 | if (opts.prelude) {
|
186 | runInContext(opts.prelude, repl.context, 'prelude');
|
187 | }
|
188 | repl.on('exit', function() {
|
189 | if (!repl.rli.closed) {
|
190 | return repl.outputStream.write('\n');
|
191 | }
|
192 | });
|
193 | addMultilineHandler(repl);
|
194 | if (opts.historyFile) {
|
195 | addHistory(repl, opts.historyFile, opts.historyMaxInputSize);
|
196 | }
|
197 | repl.commands[getCommandId(repl, 'load')].help = 'Load code from a file into this REPL session';
|
198 | return repl;
|
199 | }
|
200 | };
|
201 |
|
202 | }).call(this);
|