[debugger] readline => repl
Started porting to high-level javascript API and repl.
This commit is contained in:
parent
4527de8cba
commit
bd69afbc83
243
lib/_debugger.js
243
lib/_debugger.js
@ -20,7 +20,7 @@
|
|||||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
var net = require('net');
|
var net = require('net');
|
||||||
var readline = require('readline');
|
var repl = require('repl');
|
||||||
var inherits = require('util').inherits;
|
var inherits = require('util').inherits;
|
||||||
var spawn = require('child_process').spawn;
|
var spawn = require('child_process').spawn;
|
||||||
|
|
||||||
@ -597,19 +597,11 @@ function SourceInfo(body) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This class is the readline-enabled debugger interface which is invoked on
|
// This class is the repl-enabled debugger interface which is invoked on
|
||||||
// "node debug"
|
// "node debug"
|
||||||
function Interface() {
|
function Interface() {
|
||||||
var self = this;
|
var self = this,
|
||||||
var child;
|
child;
|
||||||
var client;
|
|
||||||
|
|
||||||
function complete(line) {
|
|
||||||
return self.complete(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
var term = readline.createInterface(process.stdin, process.stdout, complete);
|
|
||||||
this.term = term;
|
|
||||||
|
|
||||||
process.on('exit', function() {
|
process.on('exit', function() {
|
||||||
self.killChild();
|
self.killChild();
|
||||||
@ -617,104 +609,45 @@ function Interface() {
|
|||||||
|
|
||||||
this.stdin = process.openStdin();
|
this.stdin = process.openStdin();
|
||||||
|
|
||||||
term.setPrompt('debug> ');
|
this.repl = repl.start('debug> ');
|
||||||
term.prompt();
|
|
||||||
|
// Lift all instance methods to repl context
|
||||||
|
var proto = Interface.prototype,
|
||||||
|
ignored = ['pause', 'resume', 'handleSIGINT'];
|
||||||
|
|
||||||
|
for (var i in proto) {
|
||||||
|
if (proto.hasOwnProperty(i) && ignored.indexOf(i) === -1) {
|
||||||
|
this.repl.context[i] = proto[i].bind(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.quitting = false;
|
this.quitting = false;
|
||||||
|
this.paused = 0;
|
||||||
|
|
||||||
process.on('SIGINT', function() {
|
process.on('SIGINT', function() {
|
||||||
self.handleSIGINT();
|
self.handleSIGINT();
|
||||||
});
|
});
|
||||||
|
|
||||||
term.on('SIGINT', function() {
|
|
||||||
self.handleSIGINT();
|
|
||||||
});
|
|
||||||
|
|
||||||
term.on('attemptClose', function() {
|
|
||||||
self.tryQuit();
|
|
||||||
});
|
|
||||||
|
|
||||||
term.on('line', function(cmd) {
|
|
||||||
// trim whitespace
|
|
||||||
cmd = cmd.replace(/^\s*/, '').replace(/\s*$/, '');
|
|
||||||
|
|
||||||
if (cmd.length) {
|
|
||||||
self._lastCommand = cmd;
|
|
||||||
self.handleCommand(cmd);
|
|
||||||
} else {
|
|
||||||
self.handleCommand(self._lastCommand);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.complete = function(line) {
|
|
||||||
// Match me with a command.
|
|
||||||
var matches = [];
|
|
||||||
// Remove leading whitespace
|
|
||||||
line = line.replace(/^\s*/, '');
|
|
||||||
|
|
||||||
for (var i = 0; i < commands.length; i++) {
|
|
||||||
if (commands[i].indexOf(line) === 0) {
|
|
||||||
matches.push(commands[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [matches, line];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.handleSIGINT = function() {
|
|
||||||
if (this.paused) {
|
|
||||||
this.child.kill('SIGINT');
|
|
||||||
} else {
|
|
||||||
this.tryQuit();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.quit = function() {
|
|
||||||
if (this.quitting) return;
|
|
||||||
this.quitting = true;
|
|
||||||
this.killChild();
|
|
||||||
this.term.close();
|
|
||||||
process.exit(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.tryQuit = function() {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
if (self.child) {
|
|
||||||
self.quitQuestion(function(yes) {
|
|
||||||
if (yes) {
|
|
||||||
self.quit();
|
|
||||||
} else {
|
|
||||||
self.term.prompt();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
self.quit();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.pause = function() {
|
Interface.prototype.pause = function() {
|
||||||
this.paused = true;
|
if (this.paused++ > 0) return false;
|
||||||
this.stdin.pause();
|
this.stdin.pause();
|
||||||
this.term.pause();
|
this.repl.rli.pause();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.resume = function() {
|
Interface.prototype.resume = function() {
|
||||||
if (!this.paused) return false;
|
if (this.paused === 0 || --this.paused !== 0) return false;
|
||||||
this.paused = false;
|
|
||||||
this.stdin.resume();
|
this.stdin.resume();
|
||||||
this.term.resume();
|
this.repl.rli.resume();
|
||||||
this.term.prompt();
|
process.stdout.write('\n');
|
||||||
return true;
|
this.repl.displayPrompt();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Interface.prototype.handleSIGINT = function() {
|
||||||
|
this.child.kill('SIGINT');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.handleBreak = function(r) {
|
Interface.prototype.handleBreak = function(r) {
|
||||||
var result = '';
|
var result = '';
|
||||||
@ -745,8 +678,6 @@ Interface.prototype.handleBreak = function(r) {
|
|||||||
this.client.currentScript = r.script.name;
|
this.client.currentScript = r.script.name;
|
||||||
|
|
||||||
console.log(result);
|
console.log(result);
|
||||||
|
|
||||||
if (!this.resume()) this.term.prompt();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -774,6 +705,46 @@ function leftPad(n) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Interface.prototype.help = function() {
|
||||||
|
this.pause();
|
||||||
|
process.stdout.write(helpMessage);
|
||||||
|
this.resume();
|
||||||
|
};
|
||||||
|
|
||||||
|
Interface.prototype.run = function() {
|
||||||
|
if (this.child) {
|
||||||
|
throw Error('App is already running... Try `restart()` instead');
|
||||||
|
} else {
|
||||||
|
this.trySpawn();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Interface.prototype.restart = function() {
|
||||||
|
if (!this.child) throw Error('App isn\'t running... Try `run()` instead');
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.killChild();
|
||||||
|
|
||||||
|
// XXX need to wait a little bit for the restart to work?
|
||||||
|
setTimeout(function() {
|
||||||
|
self.trySpawn();
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
Interface.prototype.version = function() {
|
||||||
|
if (!this.child) throw Error('App isn\'t running... Try `run()` instead');
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.pause();
|
||||||
|
this.client.reqVersion(function(v) {
|
||||||
|
process.stdout.write(v);
|
||||||
|
self.resume();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.handleCommand = function(cmd) {
|
Interface.prototype.handleCommand = function(cmd) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -786,29 +757,9 @@ Interface.prototype.handleCommand = function(cmd) {
|
|||||||
self.tryQuit();
|
self.tryQuit();
|
||||||
|
|
||||||
} else if (/^r(un)?/.test(cmd)) {
|
} else if (/^r(un)?/.test(cmd)) {
|
||||||
self._lastCommand = null;
|
// DONE
|
||||||
if (self.child) {
|
|
||||||
self.restartQuestion(function(yes) {
|
|
||||||
if (!yes) {
|
|
||||||
self._lastCommand = null;
|
|
||||||
term.prompt();
|
|
||||||
} else {
|
|
||||||
console.log('restarting...');
|
|
||||||
self.killChild();
|
|
||||||
// XXX need to wait a little bit for the restart to work?
|
|
||||||
setTimeout(function() {
|
|
||||||
self.trySpawn();
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
self.trySpawn();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (/^help/.test(cmd)) {
|
} else if (/^help/.test(cmd)) {
|
||||||
console.log(helpMessage);
|
// DONE
|
||||||
term.prompt();
|
|
||||||
|
|
||||||
} else if ('version' == cmd) {
|
} else if ('version' == cmd) {
|
||||||
if (!client) {
|
if (!client) {
|
||||||
self.printNotConnected();
|
self.printNotConnected();
|
||||||
@ -816,7 +767,6 @@ Interface.prototype.handleCommand = function(cmd) {
|
|||||||
}
|
}
|
||||||
client.reqVersion(function(v) {
|
client.reqVersion(function(v) {
|
||||||
console.log(v);
|
console.log(v);
|
||||||
term.prompt();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} else if (/info +breakpoints/.test(cmd)) {
|
} else if (/info +breakpoints/.test(cmd)) {
|
||||||
@ -826,7 +776,6 @@ Interface.prototype.handleCommand = function(cmd) {
|
|||||||
}
|
}
|
||||||
client.listbreakpoints(function(res) {
|
client.listbreakpoints(function(res) {
|
||||||
console.log(res);
|
console.log(res);
|
||||||
term.prompt();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -864,7 +813,6 @@ Interface.prototype.handleCommand = function(cmd) {
|
|||||||
console.log(leftPad(lineno) + ' ' + lines[i]);
|
console.log(leftPad(lineno) + ' ' + lines[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
term.prompt();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} else if (/^backtrace/.test(cmd) || /^bt/.test(cmd)) {
|
} else if (/^backtrace/.test(cmd) || /^bt/.test(cmd)) {
|
||||||
@ -894,7 +842,6 @@ Interface.prototype.handleCommand = function(cmd) {
|
|||||||
|
|
||||||
console.log(text);
|
console.log(text);
|
||||||
}
|
}
|
||||||
term.prompt();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} else if (cmd == 'scripts' || cmd == 'scripts full') {
|
} else if (cmd == 'scripts' || cmd == 'scripts full') {
|
||||||
@ -903,7 +850,6 @@ Interface.prototype.handleCommand = function(cmd) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.printScripts(cmd.indexOf('full') > 0);
|
self.printScripts(cmd.indexOf('full') > 0);
|
||||||
term.prompt();
|
|
||||||
|
|
||||||
} else if (/^c(ontinue)?/.test(cmd)) {
|
} else if (/^c(ontinue)?/.test(cmd)) {
|
||||||
if (!client) {
|
if (!client) {
|
||||||
@ -931,7 +877,6 @@ Interface.prototype.handleCommand = function(cmd) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.term.prompt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (/^next/.test(cmd) || /^n/.test(cmd)) {
|
} else if (/^next/.test(cmd) || /^n/.test(cmd)) {
|
||||||
@ -960,19 +905,16 @@ Interface.prototype.handleCommand = function(cmd) {
|
|||||||
var i = cmd.indexOf(' ');
|
var i = cmd.indexOf(' ');
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
console.log('print [expression]');
|
console.log('print [expression]');
|
||||||
term.prompt();
|
|
||||||
} else {
|
} else {
|
||||||
cmd = cmd.slice(i);
|
cmd = cmd.slice(i);
|
||||||
client.reqEval(cmd, function(res) {
|
client.reqEval(cmd, function(res) {
|
||||||
if (!res.success) {
|
if (!res.success) {
|
||||||
console.log(res.message);
|
console.log(res.message);
|
||||||
term.prompt();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
client.mirrorObject(res.body, function(mirror) {
|
client.mirrorObject(res.body, function(mirror) {
|
||||||
console.log(mirror);
|
console.log(mirror);
|
||||||
term.prompt();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -982,45 +924,11 @@ Interface.prototype.handleCommand = function(cmd) {
|
|||||||
// If it's not all white-space print this error message.
|
// If it's not all white-space print this error message.
|
||||||
console.log('Unknown command "%s". Try "help"', cmd);
|
console.log('Unknown command "%s". Try "help"', cmd);
|
||||||
}
|
}
|
||||||
term.prompt();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.yesNoQuestion = function(prompt, cb) {
|
|
||||||
var self = this;
|
|
||||||
self.resume();
|
|
||||||
this.term.question(prompt, function(answer) {
|
|
||||||
if (/^y(es)?$/i.test(answer)) {
|
|
||||||
cb(true);
|
|
||||||
} else if (/^n(o)?$/i.test(answer)) {
|
|
||||||
cb(false);
|
|
||||||
} else {
|
|
||||||
console.log('Please answer y or n.');
|
|
||||||
self.yesNoQuestion(prompt, cb);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.restartQuestion = function(cb) {
|
|
||||||
this.yesNoQuestion('The program being debugged has been started already.\n' +
|
|
||||||
'Start it from the beginning? (y or n) ', cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.killQuestion = function(cb) {
|
|
||||||
this.yesNoQuestion('Kill the program being debugged? (y or n) ', cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.quitQuestion = function(cb) {
|
|
||||||
this.yesNoQuestion('A debugging session is active. Quit anyway? (y or n) ',
|
|
||||||
cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.killChild = function() {
|
Interface.prototype.killChild = function() {
|
||||||
if (this.child) {
|
if (this.child) {
|
||||||
this.child.kill();
|
this.child.kill();
|
||||||
@ -1050,26 +958,25 @@ Interface.prototype.trySpawn = function(cb) {
|
|||||||
var connectionAttempts = 0;
|
var connectionAttempts = 0;
|
||||||
|
|
||||||
client.once('ready', function() {
|
client.once('ready', function() {
|
||||||
process.stdout.write(' ok\r\n');
|
process.stdout.write(' ok');
|
||||||
|
|
||||||
// since we did debug-brk, we're hitting a break point immediately
|
// since we did debug-brk, we're hitting a break point immediately
|
||||||
// continue before anything else.
|
// continue before anything else.
|
||||||
client.reqContinue(function() {
|
client.reqContinue(function() {
|
||||||
|
self.resume();
|
||||||
if (cb) cb();
|
if (cb) cb();
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('close', function() {
|
client.on('close', function() {
|
||||||
console.log('\nprogram terminated');
|
console.log('program terminated');
|
||||||
self.client = null;
|
self.client = null;
|
||||||
self.killChild();
|
self.killChild();
|
||||||
if (!self.quitting) self.term.prompt();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('unhandledResponse', function(res) {
|
client.on('unhandledResponse', function(res) {
|
||||||
console.log('\r\nunhandled res:');
|
console.log('\r\nunhandled res:');
|
||||||
console.log(res);
|
console.log(res);
|
||||||
self.term.prompt();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('break', function(res) {
|
client.on('break', function(res) {
|
||||||
@ -1098,12 +1005,6 @@ Interface.prototype.trySpawn = function(cb) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Interface.prototype.printNotConnected = function() {
|
|
||||||
console.log("Program not running. Try 'run'.");
|
|
||||||
this.term.prompt();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// argument full tells if it should display internal node scripts or not
|
// argument full tells if it should display internal node scripts or not
|
||||||
Interface.prototype.printScripts = function(displayNatives) {
|
Interface.prototype.printScripts = function(displayNatives) {
|
||||||
var client = this.client;
|
var client = this.client;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user