Compare commits

...

9 commits

Author SHA1 Message Date
Sami Samhuri
0a0da46ad4 he's dead, Jim 2013-03-13 23:03:20 -07:00
Sami Samhuri
11b8a6246b 0.9.5 2012-07-11 11:18:36 -07:00
Sami Samhuri
5ccbb46c81 fix for node v0.8.x 2012-07-11 11:18:18 -07:00
Sami Samhuri
91028f439b 0.9.4 2011-11-05 16:32:18 -07:00
Sami Samhuri
80b5dbf3c9 seed the editing tmp file with the last line of history 2011-11-05 16:32:01 -07:00
Sami Samhuri
9c36c8f9c3 use vm.runInContext instead of vm.Script.runInContext 2011-11-05 16:31:09 -07:00
Sami Samhuri
53d322e0ca rename repl vars for clarity, fix style (braces, comma first) 2011-11-05 16:30:16 -07:00
Sami Samhuri
c83c0105b6 add history file support to repl.js 2011-11-05 16:26:46 -07:00
Sami Samhuri
d6d800a44b update Readme 2011-11-05 16:25:56 -07:00
4 changed files with 142 additions and 70 deletions

View file

@ -1,3 +1,13 @@
# I'M NOT DEAD, I'M JUST RESTING
Beautiful plumage. But this project no longer functions and some of the functionality here has been implemented
in Node proper via .load and .save in the REPL. I will no longer maintain it (poorly and infrequently).
If you want to contribute a .edit command to Node that would be pretty snazzy. Now that the REPL sucks less
it's less pressing though. You can paste in some code the REPL doesn't understand, or broken syntax, and
then Ctrl-C your way out of it.
repl-edit
=========
@ -15,7 +25,7 @@ Usage
Typically you just type `require('repl-edit')` in node's repl and it will extend it with new commands, just like `.break` and `.clear` that come with node.
You can also fire up a repl with editing capabilities by running `node-repl-edit` in your shell.
(You can also fire up a repl with editing capabilities by running `node-repl-edit` in your shell)
Commands
========
@ -23,7 +33,7 @@ Commands
.edit
-----
`.edit` opens your editor. Type away and then save and close the file when you're done. The command will be loaded and executed immediately.
The first time you run `.edit` your editor is opened containing the last statement you entered. Type away and then save and close the file when you're done. The code will be loaded and executed immediately. When you subsequently run `.edit` your editor is opened and contains whatever you left there.
Your editor is determined by the `VISUAL` and `EDITOR` environment variables, in that order. You can also change the editor for a single edit by doing something like `.edit vim`.
@ -47,14 +57,9 @@ Your editor is determined by the `VISUAL` and `EDITOR` environment variables, in
`.unstash /path/to/a/file` restores the contents of that file for you to run and/or edit.
TODO
====
The first time `.edit` is run instead of an empty file the command should be seeded with the last command that was executed.
License
=======
Copyright 2010 - 2011 Sami Samhuri <sami@samhuri.net>
MIT license, see the included [LICENSE](/samsonjs/repl-edit/blob/master/LICENSE)
MIT license, see the included [LICENSE](/samsonjs/repl-edit/blob/master/LICENSE)

View file

@ -8,106 +8,127 @@
// TODO proper error handling, better intregration with node/lib/repl.js
var fs = require('fs')
, replModule = require('repl')
, spawn = require('child_process').spawn
, util = require('util')
, vm = require('vm')
, Hint = 'Commands: .edit, .run, .stash <filename>, .unstash <filename>, .editor <editor>'
, replModule = require('repl')
, repl
, theRepl
module.exports = { startRepl: startRepl, extendRepl: extendRepl }
// Start a repl
function startRepl() {
if (repl) {
if (theRepl) {
console.error('repl is already running, only one instance is allowed')
return
}
extendRepl(require('repl').start())
return extendRepl(replModule.start('> '))
}
function log(s) {
repl.outputStream.write(s + '\n' + repl.prompt)
repl.displayPrompt()
if (theRepl.outputStream) {
theRepl.outputStream.write(s + '\n' + theRepl.prompt)
theRepl.displayPrompt()
}
}
function extendRepl(theRepl) {
if (repl) {
function extendRepl(aRepl) {
if (theRepl) {
console.error('repl is already running, only one instance is allowed')
return
}
if (!theRepl || typeof theRepl.defineCommand !== 'function') {
if (!aRepl || typeof aRepl.defineCommand !== 'function') {
console.error('bad argument, repl is not compatible')
return
}
repl = theRepl
theRepl = aRepl
var tmpfile = makeTempfile()
process.on('exit', function() {
try {
fs.unlinkSync(tmpfile)
} catch (e) {
}
catch (e) {
// might not exist
}
})
log(Hint)
repl.defineCommand('edit', {
help: 'Edit the current command in your text editor',
action: function(editor) {
theRepl.defineCommand('edit', {
help: 'Edit the current command in your text editor'
, action: function(editor) {
edit(tmpfile, editor)
}
})
repl.defineCommand('run', {
help: 'Run the previously edited command',
action: function() {
theRepl.defineCommand('run', {
help: 'Run the previously edited command'
, action: function() {
pause()
run(tmpfile, function() { unpause() })
}
})
repl.defineCommand('stash', {
help: 'Write the current command to the named file',
action: function(dest) {
theRepl.defineCommand('stash', {
help: 'Write the current command to the named file'
, action: function(dest) {
stash(tmpfile, dest)
}
})
repl.defineCommand('unstash', {
help: 'Replace the current command with the contents of the named file',
action: function(source) {
theRepl.defineCommand('unstash', {
help: 'Replace the current command with the contents of the named file'
, action: function(source) {
unstash(tmpfile, source)
}
})
repl.defineCommand('editor', function(editor) {
theRepl.defineCommand('editor', function(editor) {
process.env['VISUAL'] = editor
})
return theRepl
}
// Commands
function edit(cmdfile, editor) {
function edit(cmdFile, editor) {
editor = editor || process.env['VISUAL'] || process.env['EDITOR']
// TODO seed the file with repl.context._ if the file doesn't exist yet
var fds = [process.openStdin(), process.stdout, process.stdout]
, args = [cmdfile]
, args = [cmdFile]
// handle things like 'mate -w' and 'emacsclient --server-file <filename>'
if (editor.match(/\s/)) {
var words = editor.split(/\s+/) // FIXME this should do proper word splitting ...
args = words.slice(1).concat(args)
editor = words[0]
}
// seed the file with repl.context._ if the file doesn't exist yet
try {
fs.statSync(cmdFile)
}
catch (e) {
// skip history[0], it's the .edit command
var lastCmd = theRepl.rli.history[1]
if (lastCmd && lastCmd[0] !== '.') {
fs.writeFileSync(cmdFile, lastCmd)
}
}
pause()
spawn(editor, args, {customFds: fds}).on('exit', function(code) {
// some editors change the terminal resulting in skewed output, clean up
spawn('reset').on('exit', function(_) {
if (code === 0) {
run(cmdfile, function() { unpause() })
} else {
run(cmdFile, function() { unpause() })
}
else {
unpause()
}
})
@ -117,7 +138,8 @@ function edit(cmdfile, editor) {
function stash(cmdFile, dest) {
try {
fs.statSync(cmdFile)
} catch (e) {
}
catch (e) {
log('nothing to stash')
return
}
@ -143,7 +165,8 @@ function unstash(cmdFile, source) {
}
try {
fs.statSync(source)
} catch (e) {
}
catch (e) {
log('no stash at ' + source)
return
}
@ -160,31 +183,30 @@ function run(filename, callback) {
// check if file exists. might not have been saved.
try {
fs.statSync(filename)
} catch (e) {
}
catch (e) {
log('nothing to run\n')
callback()
return
}
var evalcx = require('vm').Script.runInContext
, read = fs.createReadStream(filename)
, s = ''
read.on('data', function(d) { s += d })
var read = fs.createReadStream(filename)
, cmd = ''
read.on('data', function(d) { cmd += d })
read.on('end', function() {
// The catchall for errors
try {
// Use evalcx to supply the global context
var ret = evalcx(s, repl.context, "repl");
if (ret !== undefined) {
repl.context._ = ret
repl.outputStream.write(replModule.writer(ret) + '\n')
}
} catch (e) {
var ret = vm.runInContext(cmd, theRepl.context, 'repl');
theRepl.context._ = ret
theRepl.outputStream.write(replModule.writer(ret) + '\n')
}
catch (e) {
// On error: Print the error and clear the buffer
if (e.stack) {
log(e.stack + "\n")
} else {
log(e.toString() + "\n")
log(e.stack + '\n')
}
else {
log(e.toString() + '\n')
}
}
if (callback) callback()
@ -195,19 +217,19 @@ function run(filename, callback) {
var origPrompt
function unpause() {
repl.prompt = origPrompt
repl.rli.enabled = true
repl.outputStream.resume()
repl.inputStream.resume()
repl.displayPrompt()
theRepl.prompt = origPrompt
theRepl.rli.enabled = true
theRepl.outputStream.resume()
theRepl.inputStream.resume()
theRepl.displayPrompt()
}
function pause() {
repl.outputStream.pause()
repl.inputStream.pause()
repl.rli.enabled = false
origPrompt = repl.prompt || '> '
repl.prompt = ''
theRepl.outputStream.pause()
theRepl.inputStream.pause()
theRepl.rli.enabled = false
origPrompt = theRepl.prompt || '> '
theRepl.prompt = ''
}
function makeTempfile() {
@ -227,5 +249,9 @@ function makeTempfile() {
return path.join(tmpdir, 'node-repl-' + process.pid + '.js')
}
if (require.main === module) startRepl()
else if (module.parent && module.parent.id === 'repl') extendRepl(module.parent.exports.repl)
if (require.main === module) {
startRepl()
}
else if (module.parent && module.parent.id === 'repl') {
extendRepl(module.parent.exports.repl)
}

View file

@ -1,7 +1,7 @@
{
"name": "repl-edit",
"description": "Edit code in the repl using a real text editor",
"version": "0.9.3",
"version": "0.9.5",
"homepage": "http://samhuri.net/proj/repl-edit",
"author": "Sami Samhuri <sami@samhuri.net>",
"repository": {
@ -29,5 +29,6 @@
}
],
"dependencies": {},
"devDependencies": {}
}
"devDependencies": {},
"optionalDependencies": {}
}

42
repl.js
View file

@ -1,3 +1,43 @@
#!/usr/bin/env node
require('./lib/index').startRepl()
var fs = require('fs')
, path = require('path')
, repl = require('./lib/index').startRepl()
, DefaultHistoryFile = path.join(process.env.HOME, '.node_history')
, historyFile
if ('NODE_HISTORY' in process.env)
historyFile = process.env.NODE_HISTORY
else
historyFile = DefaultHistoryFile
// restore history immediately
if (historyFile) {
try {
fs.statSync(historyFile)
var json = fs.readFileSync(historyFile)
repl.rli.history = JSON.parse(json)
}
catch (e) {
if (e.code !== 'ENOENT') {
console.error('!!! Error reading history from ' + historyFile)
if (e.message === 'Unexpected token ILLEGAL') {
console.error('is this a JSON array of strings? -> ' + json)
}
else {
console.error(e.message)
}
}
}
// save history on exit
process.on('exit', function() {
try {
fs.writeFileSync(historyFile, JSON.stringify(repl.rli.history))
}
catch (e) {
console.error('Error writing history file to ' + historyFile)
console.error(e)
}
})
}