/documentation/docs/repl.html

http://github.com/jashkenas/coffee-script · HTML · 608 lines · 403 code · 205 blank · 0 comment · 0 complexity · 4d2b8f2ac77e3fe6d7ff3af448aed03f MD5 · raw file

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>repl.coffee</title>
  5. <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  6. <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
  7. <link rel="stylesheet" media="all" href="docco.css" />
  8. </head>
  9. <body>
  10. <div id="container">
  11. <div id="background"></div>
  12. <ul id="jump_to">
  13. <li>
  14. <a class="large" href="javascript:void(0);">Jump To &hellip;</a>
  15. <a class="small" href="javascript:void(0);">+</a>
  16. <div id="jump_wrapper">
  17. <div id="jump_page_wrapper">
  18. <div id="jump_page">
  19. <a class="source" href="browser.html">
  20. browser.coffee
  21. </a>
  22. <a class="source" href="cake.html">
  23. cake.coffee
  24. </a>
  25. <a class="source" href="coffee-script.html">
  26. coffee-script.coffee
  27. </a>
  28. <a class="source" href="command.html">
  29. command.coffee
  30. </a>
  31. <a class="source" href="grammar.html">
  32. grammar.coffee
  33. </a>
  34. <a class="source" href="helpers.html">
  35. helpers.coffee
  36. </a>
  37. <a class="source" href="index.html">
  38. index.coffee
  39. </a>
  40. <a class="source" href="lexer.html">
  41. lexer.coffee
  42. </a>
  43. <a class="source" href="nodes.html">
  44. nodes.coffee
  45. </a>
  46. <a class="source" href="optparse.html">
  47. optparse.coffee
  48. </a>
  49. <a class="source" href="register.html">
  50. register.coffee
  51. </a>
  52. <a class="source" href="repl.html">
  53. repl.coffee
  54. </a>
  55. <a class="source" href="rewriter.html">
  56. rewriter.coffee
  57. </a>
  58. <a class="source" href="scope.html">
  59. scope.litcoffee
  60. </a>
  61. <a class="source" href="sourcemap.html">
  62. sourcemap.litcoffee
  63. </a>
  64. </div>
  65. </div>
  66. </li>
  67. </ul>
  68. <ul class="sections">
  69. <li id="title">
  70. <div class="annotation">
  71. <h1>repl.coffee</h1>
  72. </div>
  73. </li>
  74. <li id="section-1">
  75. <div class="annotation">
  76. <div class="pilwrap ">
  77. <a class="pilcrow" href="#section-1">&#182;</a>
  78. </div>
  79. </div>
  80. <div class="content"><div class='highlight'><pre>fs = <span class="hljs-built_in">require</span> <span class="hljs-string">'fs'</span>
  81. path = <span class="hljs-built_in">require</span> <span class="hljs-string">'path'</span>
  82. vm = <span class="hljs-built_in">require</span> <span class="hljs-string">'vm'</span>
  83. nodeREPL = <span class="hljs-built_in">require</span> <span class="hljs-string">'repl'</span>
  84. CoffeeScript = <span class="hljs-built_in">require</span> <span class="hljs-string">'./coffee-script'</span>
  85. {merge, updateSyntaxError} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./helpers'</span>
  86. replDefaults =
  87. <span class="hljs-attribute">prompt</span>: <span class="hljs-string">'coffee&gt; '</span>,
  88. <span class="hljs-attribute">historyFile</span>: path.join process.env.HOME, <span class="hljs-string">'.coffee_history'</span> <span class="hljs-keyword">if</span> process.env.HOME
  89. <span class="hljs-attribute">historyMaxInputSize</span>: <span class="hljs-number">10240</span>
  90. <span class="hljs-attribute">eval</span>: <span class="hljs-function"><span class="hljs-params">(input, context, filename, cb)</span> -&gt;</span></pre></div></div>
  91. </li>
  92. <li id="section-2">
  93. <div class="annotation">
  94. <div class="pilwrap ">
  95. <a class="pilcrow" href="#section-2">&#182;</a>
  96. </div>
  97. <p>XXX: multiline hack.</p>
  98. </div>
  99. <div class="content"><div class='highlight'><pre> input = input.replace <span class="hljs-regexp">/\uFF00/g</span>, <span class="hljs-string">'\n'</span></pre></div></div>
  100. </li>
  101. <li id="section-3">
  102. <div class="annotation">
  103. <div class="pilwrap ">
  104. <a class="pilcrow" href="#section-3">&#182;</a>
  105. </div>
  106. <p>Nodes REPL sends the input ending with a newline and then wrapped in
  107. parens. Unwrap all that.</p>
  108. </div>
  109. <div class="content"><div class='highlight'><pre> input = input.replace <span class="hljs-regexp">/^\(([\s\S]*)\n\)$/m</span>, <span class="hljs-string">'$1'</span></pre></div></div>
  110. </li>
  111. <li id="section-4">
  112. <div class="annotation">
  113. <div class="pilwrap ">
  114. <a class="pilcrow" href="#section-4">&#182;</a>
  115. </div>
  116. <p>Require AST nodes to do some AST manipulation.</p>
  117. </div>
  118. <div class="content"><div class='highlight'><pre> {Block, Assign, Value, Literal} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./nodes'</span>
  119. <span class="hljs-keyword">try</span></pre></div></div>
  120. </li>
  121. <li id="section-5">
  122. <div class="annotation">
  123. <div class="pilwrap ">
  124. <a class="pilcrow" href="#section-5">&#182;</a>
  125. </div>
  126. <p>Tokenize the clean input.</p>
  127. </div>
  128. <div class="content"><div class='highlight'><pre> tokens = CoffeeScript.tokens input</pre></div></div>
  129. </li>
  130. <li id="section-6">
  131. <div class="annotation">
  132. <div class="pilwrap ">
  133. <a class="pilcrow" href="#section-6">&#182;</a>
  134. </div>
  135. <p>Collect referenced variable names just like in <code>CoffeeScript.compile</code>.</p>
  136. </div>
  137. <div class="content"><div class='highlight'><pre> referencedVars = (
  138. token[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> token <span class="hljs-keyword">in</span> tokens <span class="hljs-keyword">when</span> token.variable
  139. )</pre></div></div>
  140. </li>
  141. <li id="section-7">
  142. <div class="annotation">
  143. <div class="pilwrap ">
  144. <a class="pilcrow" href="#section-7">&#182;</a>
  145. </div>
  146. <p>Generate the AST of the tokens.</p>
  147. </div>
  148. <div class="content"><div class='highlight'><pre> ast = CoffeeScript.nodes tokens</pre></div></div>
  149. </li>
  150. <li id="section-8">
  151. <div class="annotation">
  152. <div class="pilwrap ">
  153. <a class="pilcrow" href="#section-8">&#182;</a>
  154. </div>
  155. <p>Add assignment to <code>_</code> variable to force the input to be an expression.</p>
  156. </div>
  157. <div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Block [
  158. <span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'_'</span>), ast, <span class="hljs-string">'='</span>
  159. ]
  160. js = ast.compile {<span class="hljs-attribute">bare</span>: <span class="hljs-literal">yes</span>, <span class="hljs-attribute">locals</span>: Object.keys(context), referencedVars}
  161. cb <span class="hljs-literal">null</span>, runInContext js, context, filename
  162. <span class="hljs-keyword">catch</span> err</pre></div></div>
  163. </li>
  164. <li id="section-9">
  165. <div class="annotation">
  166. <div class="pilwrap ">
  167. <a class="pilcrow" href="#section-9">&#182;</a>
  168. </div>
  169. <p>ASTs <code>compile</code> does not add source code information to syntax errors.</p>
  170. </div>
  171. <div class="content"><div class='highlight'><pre> updateSyntaxError err, input
  172. cb err
  173. <span class="hljs-function"><span class="hljs-title">runInContext</span> = <span class="hljs-params">(js, context, filename)</span> -&gt;</span>
  174. <span class="hljs-keyword">if</span> context <span class="hljs-keyword">is</span> <span class="hljs-built_in">global</span>
  175. vm.runInThisContext js, filename
  176. <span class="hljs-keyword">else</span>
  177. vm.runInContext js, context, filename
  178. <span class="hljs-function"><span class="hljs-title">addMultilineHandler</span> = <span class="hljs-params">(repl)</span> -&gt;</span>
  179. {rli, inputStream, outputStream} = repl</pre></div></div>
  180. </li>
  181. <li id="section-10">
  182. <div class="annotation">
  183. <div class="pilwrap ">
  184. <a class="pilcrow" href="#section-10">&#182;</a>
  185. </div>
  186. <p>Node 0.11.12 changed API, prompt is now _prompt.</p>
  187. </div>
  188. <div class="content"><div class='highlight'><pre> origPrompt = repl._prompt ? repl.prompt
  189. multiline =
  190. <span class="hljs-attribute">enabled</span>: <span class="hljs-literal">off</span>
  191. <span class="hljs-attribute">initialPrompt</span>: origPrompt.replace <span class="hljs-regexp">/^[^&gt; ]*/</span>, <span class="hljs-function"><span class="hljs-params">(x)</span> -&gt;</span> x.replace <span class="hljs-regexp">/./g</span>, <span class="hljs-string">'-'</span>
  192. <span class="hljs-attribute">prompt</span>: origPrompt.replace <span class="hljs-regexp">/^[^&gt; ]*&gt;?/</span>, <span class="hljs-function"><span class="hljs-params">(x)</span> -&gt;</span> x.replace <span class="hljs-regexp">/./g</span>, <span class="hljs-string">'.'</span>
  193. <span class="hljs-attribute">buffer</span>: <span class="hljs-string">''</span></pre></div></div>
  194. </li>
  195. <li id="section-11">
  196. <div class="annotation">
  197. <div class="pilwrap ">
  198. <a class="pilcrow" href="#section-11">&#182;</a>
  199. </div>
  200. <p>Proxy nodes line listener</p>
  201. </div>
  202. <div class="content"><div class='highlight'><pre> nodeLineListener = rli.listeners(<span class="hljs-string">'line'</span>)[<span class="hljs-number">0</span>]
  203. rli.removeListener <span class="hljs-string">'line'</span>, nodeLineListener
  204. rli.<span class="hljs-literal">on</span> <span class="hljs-string">'line'</span>, <span class="hljs-function"><span class="hljs-params">(cmd)</span> -&gt;</span>
  205. <span class="hljs-keyword">if</span> multiline.enabled
  206. multiline.buffer += <span class="hljs-string">"<span class="hljs-subst">#{cmd}</span>\n"</span>
  207. rli.setPrompt multiline.prompt
  208. rli.prompt <span class="hljs-literal">true</span>
  209. <span class="hljs-keyword">else</span>
  210. rli.setPrompt origPrompt
  211. nodeLineListener cmd
  212. <span class="hljs-keyword">return</span></pre></div></div>
  213. </li>
  214. <li id="section-12">
  215. <div class="annotation">
  216. <div class="pilwrap ">
  217. <a class="pilcrow" href="#section-12">&#182;</a>
  218. </div>
  219. <p>Handle Ctrl-v</p>
  220. </div>
  221. <div class="content"><div class='highlight'><pre> inputStream.<span class="hljs-literal">on</span> <span class="hljs-string">'keypress'</span>, <span class="hljs-function"><span class="hljs-params">(char, key)</span> -&gt;</span>
  222. <span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> key <span class="hljs-keyword">and</span> key.ctrl <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> key.meta <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> key.shift <span class="hljs-keyword">and</span> key.name <span class="hljs-keyword">is</span> <span class="hljs-string">'v'</span>
  223. <span class="hljs-keyword">if</span> multiline.enabled</pre></div></div>
  224. </li>
  225. <li id="section-13">
  226. <div class="annotation">
  227. <div class="pilwrap ">
  228. <a class="pilcrow" href="#section-13">&#182;</a>
  229. </div>
  230. <p>allow arbitrarily switching between modes any time before multiple lines are entered</p>
  231. </div>
  232. <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> multiline.buffer.match <span class="hljs-regexp">/\n/</span>
  233. multiline.enabled = <span class="hljs-keyword">not</span> multiline.enabled
  234. rli.setPrompt origPrompt
  235. rli.prompt <span class="hljs-literal">true</span>
  236. <span class="hljs-keyword">return</span></pre></div></div>
  237. </li>
  238. <li id="section-14">
  239. <div class="annotation">
  240. <div class="pilwrap ">
  241. <a class="pilcrow" href="#section-14">&#182;</a>
  242. </div>
  243. <p>no-op unless the current line is empty</p>
  244. </div>
  245. <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> rli.line? <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> rli.line.match <span class="hljs-regexp">/^\s*$/</span></pre></div></div>
  246. </li>
  247. <li id="section-15">
  248. <div class="annotation">
  249. <div class="pilwrap ">
  250. <a class="pilcrow" href="#section-15">&#182;</a>
  251. </div>
  252. <p>eval, print, loop</p>
  253. </div>
  254. <div class="content"><div class='highlight'><pre> multiline.enabled = <span class="hljs-keyword">not</span> multiline.enabled
  255. rli.line = <span class="hljs-string">''</span>
  256. rli.cursor = <span class="hljs-number">0</span>
  257. rli.output.cursorTo <span class="hljs-number">0</span>
  258. rli.output.clearLine <span class="hljs-number">1</span></pre></div></div>
  259. </li>
  260. <li id="section-16">
  261. <div class="annotation">
  262. <div class="pilwrap ">
  263. <a class="pilcrow" href="#section-16">&#182;</a>
  264. </div>
  265. <p>XXX: multiline hack</p>
  266. </div>
  267. <div class="content"><div class='highlight'><pre> multiline.buffer = multiline.buffer.replace <span class="hljs-regexp">/\n/g</span>, <span class="hljs-string">'\uFF00'</span>
  268. rli.emit <span class="hljs-string">'line'</span>, multiline.buffer
  269. multiline.buffer = <span class="hljs-string">''</span>
  270. <span class="hljs-keyword">else</span>
  271. multiline.enabled = <span class="hljs-keyword">not</span> multiline.enabled
  272. rli.setPrompt multiline.initialPrompt
  273. rli.prompt <span class="hljs-literal">true</span>
  274. <span class="hljs-keyword">return</span></pre></div></div>
  275. </li>
  276. <li id="section-17">
  277. <div class="annotation">
  278. <div class="pilwrap ">
  279. <a class="pilcrow" href="#section-17">&#182;</a>
  280. </div>
  281. <p>Store and load command history from a file</p>
  282. </div>
  283. <div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">addHistory</span> = <span class="hljs-params">(repl, filename, maxSize)</span> -&gt;</span>
  284. lastLine = <span class="hljs-literal">null</span>
  285. <span class="hljs-keyword">try</span></pre></div></div>
  286. </li>
  287. <li id="section-18">
  288. <div class="annotation">
  289. <div class="pilwrap ">
  290. <a class="pilcrow" href="#section-18">&#182;</a>
  291. </div>
  292. <p>Get file info and at most maxSize of command history</p>
  293. </div>
  294. <div class="content"><div class='highlight'><pre> stat = fs.statSync filename
  295. size = Math.min maxSize, stat.size</pre></div></div>
  296. </li>
  297. <li id="section-19">
  298. <div class="annotation">
  299. <div class="pilwrap ">
  300. <a class="pilcrow" href="#section-19">&#182;</a>
  301. </div>
  302. <p>Read last <code>size</code> bytes from the file</p>
  303. </div>
  304. <div class="content"><div class='highlight'><pre> readFd = fs.openSync filename, <span class="hljs-string">'r'</span>
  305. buffer = <span class="hljs-keyword">new</span> Buffer(size)
  306. fs.readSync readFd, buffer, <span class="hljs-number">0</span>, size, stat.size - size
  307. fs.close readFd</pre></div></div>
  308. </li>
  309. <li id="section-20">
  310. <div class="annotation">
  311. <div class="pilwrap ">
  312. <a class="pilcrow" href="#section-20">&#182;</a>
  313. </div>
  314. <p>Set the history on the interpreter</p>
  315. </div>
  316. <div class="content"><div class='highlight'><pre> repl.rli.history = buffer.toString().split(<span class="hljs-string">'\n'</span>).reverse()</pre></div></div>
  317. </li>
  318. <li id="section-21">
  319. <div class="annotation">
  320. <div class="pilwrap ">
  321. <a class="pilcrow" href="#section-21">&#182;</a>
  322. </div>
  323. <p>If the history file was truncated we should pop off a potential partial line</p>
  324. </div>
  325. <div class="content"><div class='highlight'><pre> repl.rli.history.pop() <span class="hljs-keyword">if</span> stat.size &gt; maxSize</pre></div></div>
  326. </li>
  327. <li id="section-22">
  328. <div class="annotation">
  329. <div class="pilwrap ">
  330. <a class="pilcrow" href="#section-22">&#182;</a>
  331. </div>
  332. <p>Shift off the final blank newline</p>
  333. </div>
  334. <div class="content"><div class='highlight'><pre> repl.rli.history.shift() <span class="hljs-keyword">if</span> repl.rli.history[<span class="hljs-number">0</span>] <span class="hljs-keyword">is</span> <span class="hljs-string">''</span>
  335. repl.rli.historyIndex = -<span class="hljs-number">1</span>
  336. lastLine = repl.rli.history[<span class="hljs-number">0</span>]
  337. fd = fs.openSync filename, <span class="hljs-string">'a'</span>
  338. repl.rli.addListener <span class="hljs-string">'line'</span>, <span class="hljs-function"><span class="hljs-params">(code)</span> -&gt;</span>
  339. <span class="hljs-keyword">if</span> code <span class="hljs-keyword">and</span> code.length <span class="hljs-keyword">and</span> code <span class="hljs-keyword">isnt</span> <span class="hljs-string">'.history'</span> <span class="hljs-keyword">and</span> lastLine <span class="hljs-keyword">isnt</span> code</pre></div></div>
  340. </li>
  341. <li id="section-23">
  342. <div class="annotation">
  343. <div class="pilwrap ">
  344. <a class="pilcrow" href="#section-23">&#182;</a>
  345. </div>
  346. <p>Save the latest command in the file</p>
  347. </div>
  348. <div class="content"><div class='highlight'><pre> fs.write fd, <span class="hljs-string">"<span class="hljs-subst">#{code}</span>\n"</span>
  349. lastLine = code
  350. repl.<span class="hljs-literal">on</span> <span class="hljs-string">'exit'</span>,<span class="hljs-function"> -&gt;</span> fs.close fd</pre></div></div>
  351. </li>
  352. <li id="section-24">
  353. <div class="annotation">
  354. <div class="pilwrap ">
  355. <a class="pilcrow" href="#section-24">&#182;</a>
  356. </div>
  357. <p>Add a command to show the history stack</p>
  358. </div>
  359. <div class="content"><div class='highlight'><pre> repl.commands[getCommandId(repl, <span class="hljs-string">'history'</span>)] =
  360. <span class="hljs-attribute">help</span>: <span class="hljs-string">'Show command history'</span>
  361. <span class="hljs-attribute">action</span>:<span class="hljs-function"> -&gt;</span>
  362. repl.outputStream.write <span class="hljs-string">"<span class="hljs-subst">#{repl.rli.history[..].reverse().join <span class="hljs-string">'\n'</span>}</span>\n"</span>
  363. repl.displayPrompt()
  364. <span class="hljs-function"><span class="hljs-title">getCommandId</span> = <span class="hljs-params">(repl, commandName)</span> -&gt;</span></pre></div></div>
  365. </li>
  366. <li id="section-25">
  367. <div class="annotation">
  368. <div class="pilwrap ">
  369. <a class="pilcrow" href="#section-25">&#182;</a>
  370. </div>
  371. <p>Node 0.11 changed API, a command such as .help is now stored as help</p>
  372. </div>
  373. <div class="content"><div class='highlight'><pre> commandsHaveLeadingDot = repl.commands[<span class="hljs-string">'.help'</span>]?
  374. <span class="hljs-keyword">if</span> commandsHaveLeadingDot <span class="hljs-keyword">then</span> <span class="hljs-string">".<span class="hljs-subst">#{commandName}</span>"</span> <span class="hljs-keyword">else</span> commandName
  375. <span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> =
  376. <span class="hljs-attribute">start</span>: <span class="hljs-function"><span class="hljs-params">(opts = {})</span> -&gt;</span>
  377. [major, minor, build] = process.versions.node.split<span class="hljs-function"><span class="hljs-params">(<span class="hljs-string">'.'</span>)</span>.<span class="hljs-title">map</span> <span class="hljs-params">(n)</span> -&gt;</span> parseInt(n)
  378. <span class="hljs-keyword">if</span> major <span class="hljs-keyword">is</span> <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> minor &lt; <span class="hljs-number">8</span>
  379. <span class="hljs-built_in">console</span>.warn <span class="hljs-string">"Node 0.8.0+ required for CoffeeScript REPL"</span>
  380. process.exit <span class="hljs-number">1</span>
  381. CoffeeScript.register()
  382. process.argv = [<span class="hljs-string">'coffee'</span>].concat process.argv[<span class="hljs-number">2.</span>.]
  383. opts = merge replDefaults, opts
  384. repl = nodeREPL.start opts
  385. runInContext opts.prelude, repl.context, <span class="hljs-string">'prelude'</span> <span class="hljs-keyword">if</span> opts.prelude
  386. repl.<span class="hljs-literal">on</span> <span class="hljs-string">'exit'</span>,<span class="hljs-function"> -&gt;</span> repl.outputStream.write <span class="hljs-string">'\n'</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> repl.rli.closed
  387. addMultilineHandler repl
  388. addHistory repl, opts.historyFile, opts.historyMaxInputSize <span class="hljs-keyword">if</span> opts.historyFile</pre></div></div>
  389. </li>
  390. <li id="section-26">
  391. <div class="annotation">
  392. <div class="pilwrap ">
  393. <a class="pilcrow" href="#section-26">&#182;</a>
  394. </div>
  395. <p>Adapt help inherited from the node REPL</p>
  396. </div>
  397. <div class="content"><div class='highlight'><pre> repl.commands[getCommandId(repl, <span class="hljs-string">'load'</span>)].help = <span class="hljs-string">'Load code from a file into this REPL session'</span>
  398. repl</pre></div></div>
  399. </li>
  400. </ul>
  401. </div>
  402. </body>
  403. </html>