function SourceUnderline(sourceText, position) {
if (!sourceText) return;
+ var wrapper = require('module').wrapper[0];
+ if (sourceText.indexOf(wrapper) === 0) {
+ sourceText = sourceText.slice(wrapper.length);
+ position -= wrapper.length;
+ }
+
// Create an underline with a caret pointing to the source position. If the
// source contains a tab character the underline will have a tab character in
// the same place otherwise the underline will have a space character.
return result;
}
-
// This class is the repl-enabled debugger interface which is invoked on
// "node debug"
function Interface() {
self.killChild();
});
- this.stdin = process.openStdin();
-
this.repl = new repl.REPLServer('debug> ');
+ this.repl.eval = this.controlEval.bind(this);
// Lift all instance methods to repl context
var proto = Interface.prototype,
ignored = ['pause', 'resume', 'exitRepl', 'handleBreak',
- 'requireConnection', 'killChild', 'trySpawn'];
+ 'requireConnection', 'killChild', 'trySpawn',
+ 'controlEval', 'debugEval'];
for (var i in proto) {
if (proto.hasOwnProperty(i) && ignored.indexOf(i) === -1) {
}
}
- this.quitting = false;
- this.debugRepl = false;
+ this.waiting = null;
this.paused = 0;
this.context = this.repl.context;
};
+
+// Stream control
+
+
Interface.prototype.pause = function() {
if (this.paused++ > 0) return false;
- this.stdin.pause();
this.repl.rli.pause();
+ process.stdin.pause();
};
Interface.prototype.resume = function() {
if (this.paused === 0 || --this.paused !== 0) return false;
- this.stdin.resume();
this.repl.rli.resume();
- process.stdout.write('\n');
this.repl.displayPrompt();
+ process.stdin.resume();
+
+ if (this.waiting) {
+ this.waiting();
+ this.waiting = null;
+ }
};
+
Interface.prototype.handleBreak = function(r) {
this.pause();
- var result = '';
+ var result = '\n';
if (r.breakpoints) {
result += 'breakpoint';
if (r.breakpoints.length > 1) {
this.client.currentFrame = 0;
this.client.currentScript = r.script.name;
- process.stdout.write(result);
+ console.log(result);
this.resume();
};
+Interface.prototype.requireConnection = function() {
+ if (!this.client) throw Error('App isn\'t running... Try `run()` instead');
+};
+
+Interface.prototype.controlEval = function(code, context, filename, callback) {
+ try {
+ var result = vm.runInContext(code, context, filename);
+ if (this.paused === 0) return callback(null, result);
+ this.waiting = function() {
+ callback(null, result);
+ };
+ } catch (e) {
+ callback(e);
+ }
+};
+
+Interface.prototype.debugEval = function(code, context, filename, callback) {
+ var client = this.client;
+
+ if (code === '.scope') {
+ client.reqScopes(callback);
+ return;
+ }
+
+ client.reqEval(code, function(res) {
+ if (!res.success) {
+ if (res.message) {
+ if (/SyntaxError/.test(res.message)) {
+ callback(new SyntaxError(res.message));
+ } else {
+ callback(new Error(res.message));
+ }
+ } else {
+ callback(null);
+ }
+ return;
+ }
+
+ client.mirrorObject(res.body, function(mirror) {
+ callback(null, mirror);
+ });
+ });
+};
+
+
+// Commands
+
function intChars(n) {
// TODO dumb:
if (n < 50) {
return s;
}
+
+// Print help message
Interface.prototype.help = function() {
this.pause();
process.stdout.write(helpMessage);
this.resume();
};
+
+// Run script
Interface.prototype.run = function() {
if (this.child) {
throw Error('App is already running... Try `restart()` instead');
}
};
+
+// Restart script
Interface.prototype.restart = function() {
if (!this.child) throw Error('App isn\'t running... Try `run()` instead');
}, 1000);
};
-Interface.prototype.requireConnection = function() {
- if (!this.client) throw Error('App isn\'t running... Try `run()` instead');
-};
-
+// Print version
Interface.prototype.version = function() {
this.requireConnection();
var self = this;
});
};
+// List source code
Interface.prototype.list = function() {
this.requireConnection();
});
};
+// Print backtrace
Interface.prototype.backtrace = function() {
this.requireConnection();
text += '\n';
}
- process.stdout.write(text);
+ console.log(text);
}
self.resume();
});
};
+
// argument full tells if it should display internal node scripts or not
Interface.prototype.scripts = function(displayNatives) {
this.requireConnection();
}
}
}
- process.stdout.write(text);
+ console.log(text);
this.resume();
};
+
+// Continue execution of script
Interface.prototype.cont = function() {
this.requireConnection();
this.pause();
});
};
+
+// Jump to next command
Interface.prototype.next = function() {
this.requireConnection();
});
};
+
+// Step in
Interface.prototype.step = function() {
this.requireConnection();
});
};
+
+// Step out
Interface.prototype.out = function() {
this.requireConnection();
});
};
+
+// Show breakpoints
Interface.prototype.breakpoints = function() {
this.requireConnection();
this.pause();
});
};
+
+// Kill child process
Interface.prototype.kill = function() {
if (!this.child) return;
this.killChild();
};
+
+// Activate debug repl
Interface.prototype.repl = function() {
- if (!this.child) throw Error('App isn\'t running... Try `run()` instead');
+ this.requireConnection();
var self = this;
- this.debugRepl = true;
-
+ // Exit debug repl on Ctrl + C
this.repl.rli.once('SIGINT', function() {
self.exitRepl();
});
- var client = this.client;
-
- // Save old eval
- this.repl._eval = this.repl.eval;
-
// Set new
- this.repl.eval = function(code, context, filename, callback) {
- if (code === '.scope') {
- client.reqScopes(callback);
- return;
- }
-
- client.reqEval(code, function(res) {
- if (!res.success) {
- if (res.message) {
- if (/SyntaxError/.test(res.message)) {
- callback(new SyntaxError(res.message));
- } else {
- callback(new Error(res.message));
- }
- } else {
- callback(null);
- }
- return;
- }
-
- client.mirrorObject(res.body, function(mirror) {
- callback(null, mirror);
- });
- });
- };
+ this.repl.eval = this.debugEval.bind(this);
this.repl.context = {};
this.repl.prompt = '> ';
this.repl.displayPrompt();
};
+
+// Exit debug repl
Interface.prototype.exitRepl = function() {
- this.debugRepl = false;
- this.repl.eval = this.repl._eval;
+ this.repl.eval = this.controlEval.bind(this);
+
this.repl.context = this.context;
this.repl.prompt = 'debug> ';
this.repl.rli.setPrompt('debug> ');
var connectionAttempts = 0;
client.once('ready', function() {
- process.stdout.write(' ok');
+ process.stdout.write(' ok\n');
// since we did debug-brk, we're hitting a break point immediately
// continue before anything else.
attemptConnect();
}, 50);
};
-
-
-
-
-