var self = this,
child;
- process.on('exit', function() {
- self.killChild();
- });
-
+ // Two eval modes are available: controlEval and debugEval
+ // But controlEval is used by default
this.repl = new repl.REPLServer('debug> ', null,
this.controlEval.bind(this));
+ // Kill child process when repl closed or main process is dead
this.repl.rli.addListener('close', function() {
self.killed = true;
self.killChild();
});
- // Lift all instance methods to repl context
+ process.on('exit', function() {
+ self.killChild();
+ });
+
+
var proto = Interface.prototype,
ignored = ['pause', 'resume', 'exitRepl', 'handleBreak',
'requireConnection', 'killChild', 'trySpawn',
}
};
+ // Copy all prototype methods in repl context
+ // Setup them as getters if possible
for (var i in proto) {
if (proto.hasOwnProperty(i) && ignored.indexOf(i) === -1) {
defineProperty(i, i);
control: []
};
this.breakpoints = [];
+
+ // Run script automatically
+ this.run();
};
};
-// Output
+// Print text to output stream
Interface.prototype.print = function(text) {
if (this.killed) return;
if (process.stdout.isTTY) {
process.stdout.write('\n');
};
+// Format and print text from child process
Interface.prototype.childPrint = function(text) {
this.print(text.toString().split(/\r\n|\r|\n/g).filter(function(chunk) {
return chunk;
this.repl.displayPrompt();
};
+// Errors formatting
Interface.prototype.error = function(text) {
this.print(text);
this.resume();
};
+
+// Debugger's `break` event handler
Interface.prototype.handleBreak = function(r) {
this.pause();
+ // Save execution context's data
this.client.currentSourceLine = r.sourceLine;
this.client.currentSourceLineText = r.sourceLineText;
this.client.currentSourceColumn = r.sourceColumn;
this.client.currentFrame = 0;
this.client.currentScript = r.script.name;
+ // Print break data
this.print(SourceInfo(r));
+
+ // And list source
this.list(2);
+
this.resume();
};
+// Internal method for checking connection state
Interface.prototype.requireConnection = function() {
if (!this.client) {
this.error('App isn\'t running... Try `run` instead');
return true;
};
+
+// Evals
+
+// Used for debugger's commands evaluation and execution
Interface.prototype.controlEval = function(code, context, filename, callback) {
try {
var result = vm.runInContext(code, context, filename);
+ // Repl should not ask for next command
+ // if current one was asynchronous.
if (this.paused === 0) return callback(null, result);
+
+ // Add a callback for asynchronous command
+ // (it will be automatically invoked by .resume() method
this.waiting = function() {
callback(null, result);
};
}
};
+// Used for debugger's remote evaluation (`repl`) commands
Interface.prototype.debugEval = function(code, context, filename, callback) {
var self = this,
client = this.client;
+ // Repl asked for scope variables
if (code === '.scope') {
client.reqScopes(callback);
return;
}
- var frame;
-
- if (client.currentFrame === NO_FRAME) {
- frame = NO_FRAME;
- };
+ var frame = client.currentFrame === NO_FRAME ? frame : undefined;
self.pause();
+
+ // Request remote evaluation globally or in current frame
client.reqFrameEval(code, frame, function(res) {
if (!res.success) {
if (res.message) {
return;
}
+ // Request object by handles (and it's sub-properties)
client.mirrorObject(res.body, 3, function(mirror) {
callback(null, mirror);
self.resume(true);
};
-// Commands
+// Utils
+// Returns number of digits (+1)
function intChars(n) {
// TODO dumb:
if (n < 50) {
}
}
-
+// Adds spaces and prefix to number
function leftPad(n, prefix) {
var s = n.toString();
var nchars = intChars(n);
}
+// Commands
+
+
// Print help message
Interface.prototype.help = function() {
this.print(helpMessage);
};
-// argument full tells if it should display internal node scripts or not
+// First argument tells if it should display internal node scripts or not
+// (available only for internal debugger's functions)
Interface.prototype.scripts = function() {
if (!this.requireConnection()) return;
};
+// Kills child process
Interface.prototype.killChild = function() {
if (this.child) {
this.child.kill();
};
+// Spawns child process (and restores breakpoints)
Interface.prototype.trySpawn = function(cb) {
var self = this,
breakpoints = this.breakpoints || [];