Browse Source

repl: REPLServer inherits from readline.Interface

This exposes a setPrompt for and other readline features
v0.11.12-release
Yazhong Liu 11 years ago
committed by Timothy J Fontaine
parent
commit
3ae0b17c76
  1. 5
      doc/api/repl.markdown
  2. 58
      lib/repl.js
  3. 29
      test/simple/test-repl-options.js
  4. 2
      test/simple/test-repl-require-cache.js
  5. 49
      test/simple/test-repl-setprompt.js

5
doc/api/repl.markdown

@ -32,8 +32,9 @@ For example, you could add this to your bashrc file:
## repl.start(options) ## repl.start(options)
Returns and starts a `REPLServer` instance. Accepts an "options" Object that Returns and starts a `REPLServer` instance, that inherits from
takes the following values: [Readline Interface][]. Accepts an "options" Object that takes
the following values:
- `prompt` - the prompt and `stream` for all I/O. Defaults to `> `. - `prompt` - the prompt and `stream` for all I/O. Defaults to `> `.

58
lib/repl.js

@ -48,7 +48,6 @@ var path = require('path');
var fs = require('fs'); var fs = require('fs');
var rl = require('readline'); var rl = require('readline');
var Console = require('console').Console; var Console = require('console').Console;
var EventEmitter = require('events').EventEmitter;
var domain = require('domain'); var domain = require('domain');
var debug = util.debuglog('repl'); var debug = util.debuglog('repl');
@ -82,8 +81,6 @@ function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) {
return new REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined); return new REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined);
} }
EventEmitter.call(this);
var options, input, output, dom; var options, input, output, dom;
if (util.isObject(prompt)) { if (util.isObject(prompt)) {
// an options object was given // an options object was given
@ -109,6 +106,9 @@ function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) {
self.useGlobal = !!useGlobal; self.useGlobal = !!useGlobal;
self.ignoreUndefined = !!ignoreUndefined; self.ignoreUndefined = !!ignoreUndefined;
// just for backwards compat, see github.com/joyent/node/pull/7127
self.rli = this;
eval_ = eval_ || defaultEval; eval_ = eval_ || defaultEval;
function defaultEval(code, context, file, cb) { function defaultEval(code, context, file, cb) {
@ -179,19 +179,18 @@ function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) {
self.bufferedCommand = ''; self.bufferedCommand = '';
self.lines.level = []; self.lines.level = [];
self.prompt = !util.isUndefined(prompt) ? prompt : '> ';
function complete(text, callback) { function complete(text, callback) {
self.complete(text, callback); self.complete(text, callback);
} }
var rli = rl.createInterface({ rl.Interface.apply(this, [
input: self.inputStream, self.inputStream,
output: self.outputStream, self.outputStream,
completer: complete, complete,
terminal: options.terminal options.terminal
}); ])
self.rli = rli;
self.setPrompt(!util.isUndefined(prompt) ? prompt : '> ');
this.commands = {}; this.commands = {};
defineDefaultCommands(this); defineDefaultCommands(this);
@ -200,7 +199,7 @@ function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) {
self.writer = options.writer || exports.writer; self.writer = options.writer || exports.writer;
if (util.isUndefined(options.useColors)) { if (util.isUndefined(options.useColors)) {
options.useColors = rli.terminal; options.useColors = self.terminal;
} }
self.useColors = !!options.useColors; self.useColors = !!options.useColors;
@ -211,24 +210,24 @@ function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) {
}; };
} }
rli.setPrompt(self.prompt); self.setPrompt(self._prompt);
rli.on('close', function() { self.on('close', function() {
self.emit('exit'); self.emit('exit');
}); });
var sawSIGINT = false; var sawSIGINT = false;
rli.on('SIGINT', function() { self.on('SIGINT', function() {
var empty = rli.line.length === 0; var empty = self.line.length === 0;
rli.clearLine(); self.clearLine();
if (!(self.bufferedCommand && self.bufferedCommand.length > 0) && empty) { if (!(self.bufferedCommand && self.bufferedCommand.length > 0) && empty) {
if (sawSIGINT) { if (sawSIGINT) {
rli.close(); self.close();
sawSIGINT = false; sawSIGINT = false;
return; return;
} }
rli.output.write('(^C again to quit)\n'); self.output.write('(^C again to quit)\n');
sawSIGINT = true; sawSIGINT = true;
} else { } else {
sawSIGINT = false; sawSIGINT = false;
@ -239,7 +238,7 @@ function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) {
self.displayPrompt(); self.displayPrompt();
}); });
rli.on('line', function(cmd) { self.on('line', function(cmd) {
debug('line %j', cmd); debug('line %j', cmd);
sawSIGINT = false; sawSIGINT = false;
var skipCatchall = false; var skipCatchall = false;
@ -322,13 +321,13 @@ function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) {
}; };
}); });
rli.on('SIGCONT', function() { self.on('SIGCONT', function() {
self.displayPrompt(true); self.displayPrompt(true);
}); });
self.displayPrompt(); self.displayPrompt();
} }
inherits(REPLServer, EventEmitter); inherits(REPLServer, rl.Interface);
exports.REPLServer = REPLServer; exports.REPLServer = REPLServer;
@ -340,7 +339,6 @@ exports.start = function(prompt, source, eval_, useGlobal, ignoreUndefined) {
return repl; return repl;
}; };
REPLServer.prototype.createContext = function() { REPLServer.prototype.createContext = function() {
var context; var context;
if (this.useGlobal) { if (this.useGlobal) {
@ -388,17 +386,17 @@ REPLServer.prototype.resetContext = function() {
}; };
REPLServer.prototype.displayPrompt = function(preserveCursor) { REPLServer.prototype.displayPrompt = function(preserveCursor) {
var prompt = this.prompt; var prompt = this._prompt;
if (this.bufferedCommand.length) { if (this.bufferedCommand.length) {
prompt = '...'; prompt = '...';
var levelInd = new Array(this.lines.level.length).join('..'); var levelInd = new Array(this.lines.level.length).join('..');
prompt += levelInd + ' '; prompt += levelInd + ' ';
} else {
this.setPrompt(prompt);
} }
this.rli.setPrompt(prompt); this.prompt(preserveCursor);
this.rli.prompt(preserveCursor);
}; };
// A stream to push an array into a REPL // A stream to push an array into a REPL
// used in REPLServer.complete // used in REPLServer.complete
function ArrayStream() { function ArrayStream() {
@ -838,7 +836,7 @@ function defineDefaultCommands(repl) {
repl.defineCommand('exit', { repl.defineCommand('exit', {
help: 'Exit the repl', help: 'Exit the repl',
action: function() { action: function() {
this.rli.close(); this.close();
} }
}); });
@ -879,7 +877,7 @@ function defineDefaultCommands(repl) {
this.displayPrompt(); this.displayPrompt();
lines.forEach(function(line) { lines.forEach(function(line) {
if (line) { if (line) {
self.rli.write(line + '\n'); self.write(line + '\n');
} }
}); });
} }

29
test/simple/test-repl-options.js

@ -37,14 +37,23 @@ var r1 = repl.start({
output: stream, output: stream,
terminal: true terminal: true
}); });
assert.equal(r1.input, stream);
assert.equal(r1.output, stream);
assert.equal(r1.input, r1.inputStream);
assert.equal(r1.output, r1.outputStream);
assert.equal(r1.terminal, true);
assert.equal(r1.useColors, r1.terminal);
assert.equal(r1.useGlobal, false);
assert.equal(r1.ignoreUndefined, false);
// test r1 for backwards compact
assert.equal(r1.rli.input, stream); assert.equal(r1.rli.input, stream);
assert.equal(r1.rli.output, stream); assert.equal(r1.rli.output, stream);
assert.equal(r1.rli.input, r1.inputStream); assert.equal(r1.rli.input, r1.inputStream);
assert.equal(r1.rli.output, r1.outputStream); assert.equal(r1.rli.output, r1.outputStream);
assert.equal(r1.rli.terminal, true); assert.equal(r1.rli.terminal, true);
assert.equal(r1.useColors, r1.rli.terminal); assert.equal(r1.useColors, r1.rli.terminal);
assert.equal(r1.useGlobal, false);
assert.equal(r1.ignoreUndefined, false);
// 2 // 2
function writer() {} function writer() {}
@ -59,12 +68,20 @@ var r2 = repl.start({
eval: evaler, eval: evaler,
writer: writer writer: writer
}); });
assert.equal(r2.input, stream);
assert.equal(r2.output, stream);
assert.equal(r2.input, r2.inputStream);
assert.equal(r2.output, r2.outputStream);
assert.equal(r2.terminal, false);
assert.equal(r2.useColors, true);
assert.equal(r2.useGlobal, true);
assert.equal(r2.ignoreUndefined, true);
assert.equal(r2.writer, writer);
// test r2 for backwards compact
assert.equal(r2.rli.input, stream); assert.equal(r2.rli.input, stream);
assert.equal(r2.rli.output, stream); assert.equal(r2.rli.output, stream);
assert.equal(r2.rli.input, r2.inputStream); assert.equal(r2.rli.input, r2.inputStream);
assert.equal(r2.rli.output, r2.outputStream); assert.equal(r2.rli.output, r2.outputStream);
assert.equal(r2.rli.terminal, false); assert.equal(r2.rli.terminal, false);
assert.equal(r2.useColors, true);
assert.equal(r2.useGlobal, true);
assert.equal(r2.ignoreUndefined, true);
assert.equal(r2.writer, writer);

2
test/simple/test-repl-require-cache.js

@ -28,6 +28,6 @@ var common = require('../common'),
require.cache.something = 1; require.cache.something = 1;
assert.equal(require.cache.something, 1); assert.equal(require.cache.something, 1);
repl.start({ useGlobal: false }).rli.close(); repl.start({ useGlobal: false }).close();
assert.equal(require.cache.something, 1); assert.equal(require.cache.something, 1);

49
test/simple/test-repl-setprompt.js

@ -0,0 +1,49 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common'),
assert = require('assert'),
spawn = require('child_process').spawn,
os = require('os'),
util = require('util');
var args = [
'-e',
'var e = new (require("repl")).REPLServer("foo.. "); e.context.e = e;',
];
var p = "bar.. ";
var child = spawn(process.execPath, args);
child.stdout.setEncoding('utf8');
var data = '';
child.stdout.on('data', function(d) { data += d });
child.stdin.end(util.format("e.setPrompt('%s');%s", p, os.EOL));
child.on('close', function(code, signal) {
assert.strictEqual(code, 0);
assert.ok(!signal);
var lines = data.split(/\n/);
assert.strictEqual(lines.pop(), p);
});
Loading…
Cancel
Save