mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
Merge pull request #2886 from danielgtaylor/repl-history
Add history to the coffee interactive interpreter that persists between ...
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
// Generated by CoffeeScript 1.6.2
|
||||
(function() {
|
||||
var CoffeeScript, addMultilineHandler, merge, nodeREPL, prettyErrorMessage, replDefaults, vm, _ref;
|
||||
var CoffeeScript, addHistory, addMultilineHandler, fs, merge, nodeREPL, path, prettyErrorMessage, replDefaults, vm, _ref;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
vm = require('vm');
|
||||
|
||||
@@ -12,6 +16,8 @@
|
||||
|
||||
replDefaults = {
|
||||
prompt: 'coffee> ',
|
||||
historyFile: path.join(process.env.HOME, '.coffee_history'),
|
||||
historyMaxInputSize: 10240,
|
||||
"eval": function(input, context, filename, cb) {
|
||||
var Assign, Block, Literal, Value, ast, err, js, _ref1;
|
||||
input = input.replace(/\uFF00/g, '\n');
|
||||
@@ -86,6 +92,52 @@
|
||||
});
|
||||
};
|
||||
|
||||
addHistory = function(repl, filename, maxSize) {
|
||||
var buffer, fd, readFd, size, stat;
|
||||
try {
|
||||
stat = fs.statSync(filename);
|
||||
size = Math.min(maxSize, stat.size);
|
||||
readFd = fs.openSync(filename, 'r');
|
||||
buffer = new Buffer(size);
|
||||
fs.readSync(readFd, buffer, 0, size, stat.size - size);
|
||||
repl.rli.history = buffer.toString().split('\n').reverse();
|
||||
if (size === maxSize) {
|
||||
repl.rli.history.pop();
|
||||
}
|
||||
if (repl.rli.history[0] === '') {
|
||||
repl.rli.history.shift();
|
||||
}
|
||||
repl.rli.historyIndex = -1;
|
||||
} catch (_error) {}
|
||||
fd = fs.openSync(filename, 'a');
|
||||
repl.rli.addListener('line', function(code) {
|
||||
if (code && code.length && code !== '.history') {
|
||||
return fs.write(fd, "" + code + "\n");
|
||||
}
|
||||
});
|
||||
process.on('exit', function() {
|
||||
return fs.closeSync(fd);
|
||||
});
|
||||
return repl.commands['.history'] = {
|
||||
help: 'Show command history',
|
||||
action: function() {
|
||||
var history, k;
|
||||
history = ((function() {
|
||||
var _i, _len, _ref1, _results;
|
||||
_ref1 = Object.keys(repl.rli.history);
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
||||
k = _ref1[_i];
|
||||
_results.push(repl.rli.history[k]);
|
||||
}
|
||||
return _results;
|
||||
})()).reverse();
|
||||
repl.outputStream.write("" + (history.join('\n')) + "\n");
|
||||
return repl.displayPrompt();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
start: function(opts) {
|
||||
var build, major, minor, repl, _ref1;
|
||||
@@ -105,6 +157,9 @@
|
||||
return repl.outputStream.write('\n');
|
||||
});
|
||||
addMultilineHandler(repl);
|
||||
if (opts.historyFile) {
|
||||
addHistory(repl, opts.historyFile, opts.historyMaxInputSize);
|
||||
}
|
||||
return repl;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
vm = require 'vm'
|
||||
nodeREPL = require 'repl'
|
||||
CoffeeScript = require './coffee-script'
|
||||
@@ -5,6 +7,8 @@ CoffeeScript = require './coffee-script'
|
||||
|
||||
replDefaults =
|
||||
prompt: 'coffee> ',
|
||||
historyFile: path.join(process.env.HOME, '.coffee_history')
|
||||
historyMaxInputSize: 10240
|
||||
eval: (input, context, filename, cb) ->
|
||||
# XXX: multiline hack.
|
||||
input = input.replace /\uFF00/g, '\n'
|
||||
@@ -76,6 +80,42 @@ addMultilineHandler = (repl) ->
|
||||
rli.prompt true
|
||||
return
|
||||
|
||||
# Store and load command history from a file
|
||||
addHistory = (repl, filename, maxSize) ->
|
||||
try
|
||||
# Get file info and at most 10KB of command history
|
||||
stat = fs.statSync filename
|
||||
size = Math.min maxSize, stat.size
|
||||
# Read last `size` bytes from the file
|
||||
readFd = fs.openSync filename, 'r'
|
||||
buffer = new Buffer(size)
|
||||
fs.readSync readFd, buffer, 0, size, stat.size - size
|
||||
# Set the history on the interpreter
|
||||
repl.rli.history = buffer.toString().split('\n').reverse()
|
||||
# If the history file was truncated we should pop off a potential partial line
|
||||
repl.rli.history.pop() if size is maxSize
|
||||
# Shift off the final blank newline
|
||||
repl.rli.history.shift() if repl.rli.history[0] is ''
|
||||
repl.rli.historyIndex = -1
|
||||
|
||||
fd = fs.openSync filename, 'a'
|
||||
|
||||
repl.rli.addListener 'line', (code) ->
|
||||
if code and code.length and code isnt '.history'
|
||||
# Save the latest command in the file
|
||||
fs.write fd, "#{code}\n"
|
||||
|
||||
process.on 'exit', ->
|
||||
fs.closeSync fd
|
||||
|
||||
# Add a command to show the history stack
|
||||
repl.commands['.history'] =
|
||||
help: 'Show command history'
|
||||
action: ->
|
||||
history = (repl.rli.history[k] for k in Object.keys(repl.rli.history)).reverse()
|
||||
repl.outputStream.write "#{history.join '\n'}\n"
|
||||
repl.displayPrompt()
|
||||
|
||||
module.exports =
|
||||
start: (opts = {}) ->
|
||||
[major, minor, build] = process.versions.node.split('.').map (n) -> parseInt(n)
|
||||
@@ -88,4 +128,5 @@ module.exports =
|
||||
repl = nodeREPL.start opts
|
||||
repl.on 'exit', -> repl.outputStream.write '\n'
|
||||
addMultilineHandler repl
|
||||
addHistory repl, opts.historyFile, opts.historyMaxInputSize if opts.historyFile
|
||||
repl
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
return if global.testingBrowser
|
||||
|
||||
fs = require 'fs'
|
||||
|
||||
# REPL
|
||||
# ----
|
||||
Stream = require 'stream'
|
||||
@@ -25,16 +27,23 @@ class MockOutputStream extends Stream
|
||||
lastWrite: (fromEnd = -1) ->
|
||||
@written[@written.length - 1 + fromEnd].replace /\n$/, ''
|
||||
|
||||
# Create a dummy history file
|
||||
historyFile = '.coffee_history_test'
|
||||
fs.writeFileSync historyFile, '1 + 2\n'
|
||||
|
||||
testRepl = (desc, fn) ->
|
||||
input = new MockInputStream
|
||||
output = new MockOutputStream
|
||||
Repl.start {input, output}
|
||||
test desc, -> fn input, output
|
||||
repl = Repl.start {input, output, historyFile}
|
||||
test desc, -> fn input, output, repl
|
||||
|
||||
ctrlV = { ctrl: true, name: 'v'}
|
||||
|
||||
|
||||
testRepl 'reads history file', (input, output, repl) ->
|
||||
input.emitLine repl.rli.history[0]
|
||||
eq '3', output.lastWrite()
|
||||
|
||||
testRepl "starts with coffee prompt", (input, output) ->
|
||||
eq 'coffee> ', output.lastWrite(0)
|
||||
|
||||
@@ -97,3 +106,6 @@ testRepl "keeps running after runtime error", (input, output) ->
|
||||
eq 0, output.lastWrite().indexOf 'ReferenceError: b is not defined'
|
||||
input.emitLine 'a'
|
||||
eq 'undefined', output.lastWrite()
|
||||
|
||||
process.on 'exit', ->
|
||||
fs.unlinkSync historyFile
|
||||
|
||||
Reference in New Issue
Block a user