|
@ -589,6 +589,12 @@ var helpMessage = 'Commands: ' + commands.join(', '); |
|
|
function SourceUnderline(sourceText, position) { |
|
|
function SourceUnderline(sourceText, position) { |
|
|
if (!sourceText) return; |
|
|
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
|
|
|
// 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
|
|
|
// source contains a tab character the underline will have a tab character in
|
|
|
// the same place otherwise the underline will have a space character.
|
|
|
// the same place otherwise the underline will have a space character.
|
|
@ -623,7 +629,6 @@ function SourceInfo(body) { |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This class is the repl-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() { |
|
@ -634,14 +639,14 @@ function Interface() { |
|
|
self.killChild(); |
|
|
self.killChild(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
this.stdin = process.openStdin(); |
|
|
|
|
|
|
|
|
|
|
|
this.repl = new repl.REPLServer('debug> '); |
|
|
this.repl = new repl.REPLServer('debug> '); |
|
|
|
|
|
this.repl.eval = this.controlEval.bind(this); |
|
|
|
|
|
|
|
|
// Lift all instance methods to repl context
|
|
|
// Lift all instance methods to repl context
|
|
|
var proto = Interface.prototype, |
|
|
var proto = Interface.prototype, |
|
|
ignored = ['pause', 'resume', 'exitRepl', 'handleBreak', |
|
|
ignored = ['pause', 'resume', 'exitRepl', 'handleBreak', |
|
|
'requireConnection', 'killChild', 'trySpawn']; |
|
|
'requireConnection', 'killChild', 'trySpawn', |
|
|
|
|
|
'controlEval', 'debugEval']; |
|
|
|
|
|
|
|
|
for (var i in proto) { |
|
|
for (var i in proto) { |
|
|
if (proto.hasOwnProperty(i) && ignored.indexOf(i) === -1) { |
|
|
if (proto.hasOwnProperty(i) && ignored.indexOf(i) === -1) { |
|
@ -649,29 +654,37 @@ function Interface() { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
this.quitting = false; |
|
|
this.waiting = null; |
|
|
this.debugRepl = false; |
|
|
|
|
|
this.paused = 0; |
|
|
this.paused = 0; |
|
|
this.context = this.repl.context; |
|
|
this.context = this.repl.context; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Stream control
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Interface.prototype.pause = function() { |
|
|
Interface.prototype.pause = function() { |
|
|
if (this.paused++ > 0) return false; |
|
|
if (this.paused++ > 0) return false; |
|
|
this.stdin.pause(); |
|
|
|
|
|
this.repl.rli.pause(); |
|
|
this.repl.rli.pause(); |
|
|
|
|
|
process.stdin.pause(); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
Interface.prototype.resume = function() { |
|
|
Interface.prototype.resume = function() { |
|
|
if (this.paused === 0 || --this.paused !== 0) return false; |
|
|
if (this.paused === 0 || --this.paused !== 0) return false; |
|
|
this.stdin.resume(); |
|
|
|
|
|
this.repl.rli.resume(); |
|
|
this.repl.rli.resume(); |
|
|
process.stdout.write('\n'); |
|
|
|
|
|
this.repl.displayPrompt(); |
|
|
this.repl.displayPrompt(); |
|
|
|
|
|
process.stdin.resume(); |
|
|
|
|
|
|
|
|
|
|
|
if (this.waiting) { |
|
|
|
|
|
this.waiting(); |
|
|
|
|
|
this.waiting = null; |
|
|
|
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Interface.prototype.handleBreak = function(r) { |
|
|
Interface.prototype.handleBreak = function(r) { |
|
|
this.pause(); |
|
|
this.pause(); |
|
|
var result = ''; |
|
|
var result = '\n'; |
|
|
if (r.breakpoints) { |
|
|
if (r.breakpoints) { |
|
|
result += 'breakpoint'; |
|
|
result += 'breakpoint'; |
|
|
if (r.breakpoints.length > 1) { |
|
|
if (r.breakpoints.length > 1) { |
|
@ -698,11 +711,58 @@ Interface.prototype.handleBreak = function(r) { |
|
|
this.client.currentFrame = 0; |
|
|
this.client.currentFrame = 0; |
|
|
this.client.currentScript = r.script.name; |
|
|
this.client.currentScript = r.script.name; |
|
|
|
|
|
|
|
|
process.stdout.write(result); |
|
|
console.log(result); |
|
|
this.resume(); |
|
|
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) { |
|
|
function intChars(n) { |
|
|
// TODO dumb:
|
|
|
// TODO dumb:
|
|
|
if (n < 50) { |
|
|
if (n < 50) { |
|
@ -727,12 +787,16 @@ function leftPad(n) { |
|
|
return s; |
|
|
return s; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Print help message
|
|
|
Interface.prototype.help = function() { |
|
|
Interface.prototype.help = function() { |
|
|
this.pause(); |
|
|
this.pause(); |
|
|
process.stdout.write(helpMessage); |
|
|
process.stdout.write(helpMessage); |
|
|
this.resume(); |
|
|
this.resume(); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Run script
|
|
|
Interface.prototype.run = function() { |
|
|
Interface.prototype.run = function() { |
|
|
if (this.child) { |
|
|
if (this.child) { |
|
|
throw Error('App is already running... Try `restart()` instead'); |
|
|
throw Error('App is already running... Try `restart()` instead'); |
|
@ -741,6 +805,8 @@ Interface.prototype.run = function() { |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Restart script
|
|
|
Interface.prototype.restart = function() { |
|
|
Interface.prototype.restart = function() { |
|
|
if (!this.child) throw Error('App isn\'t running... Try `run()` instead'); |
|
|
if (!this.child) throw Error('App isn\'t running... Try `run()` instead'); |
|
|
|
|
|
|
|
@ -754,11 +820,8 @@ Interface.prototype.restart = function() { |
|
|
}, 1000); |
|
|
}, 1000); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
Interface.prototype.requireConnection = function() { |
|
|
|
|
|
if (!this.client) throw Error('App isn\'t running... Try `run()` instead'); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Print version
|
|
|
Interface.prototype.version = function() { |
|
|
Interface.prototype.version = function() { |
|
|
this.requireConnection(); |
|
|
this.requireConnection(); |
|
|
var self = this; |
|
|
var self = this; |
|
@ -770,6 +833,7 @@ Interface.prototype.version = function() { |
|
|
}); |
|
|
}); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// List source code
|
|
|
Interface.prototype.list = function() { |
|
|
Interface.prototype.list = function() { |
|
|
this.requireConnection(); |
|
|
this.requireConnection(); |
|
|
|
|
|
|
|
@ -808,6 +872,7 @@ Interface.prototype.list = function() { |
|
|
}); |
|
|
}); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Print backtrace
|
|
|
Interface.prototype.backtrace = function() { |
|
|
Interface.prototype.backtrace = function() { |
|
|
this.requireConnection(); |
|
|
this.requireConnection(); |
|
|
|
|
|
|
|
@ -834,12 +899,13 @@ Interface.prototype.backtrace = function() { |
|
|
text += '\n'; |
|
|
text += '\n'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
process.stdout.write(text); |
|
|
console.log(text); |
|
|
} |
|
|
} |
|
|
self.resume(); |
|
|
self.resume(); |
|
|
}); |
|
|
}); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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.scripts = function(displayNatives) { |
|
|
Interface.prototype.scripts = function(displayNatives) { |
|
|
this.requireConnection(); |
|
|
this.requireConnection(); |
|
@ -859,10 +925,12 @@ Interface.prototype.scripts = function(displayNatives) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
process.stdout.write(text); |
|
|
console.log(text); |
|
|
this.resume(); |
|
|
this.resume(); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Continue execution of script
|
|
|
Interface.prototype.cont = function() { |
|
|
Interface.prototype.cont = function() { |
|
|
this.requireConnection(); |
|
|
this.requireConnection(); |
|
|
this.pause(); |
|
|
this.pause(); |
|
@ -873,6 +941,8 @@ Interface.prototype.cont = function() { |
|
|
}); |
|
|
}); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Jump to next command
|
|
|
Interface.prototype.next = function() { |
|
|
Interface.prototype.next = function() { |
|
|
this.requireConnection(); |
|
|
this.requireConnection(); |
|
|
|
|
|
|
|
@ -884,6 +954,8 @@ Interface.prototype.next = function() { |
|
|
}); |
|
|
}); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Step in
|
|
|
Interface.prototype.step = function() { |
|
|
Interface.prototype.step = function() { |
|
|
this.requireConnection(); |
|
|
this.requireConnection(); |
|
|
|
|
|
|
|
@ -895,6 +967,8 @@ Interface.prototype.step = function() { |
|
|
}); |
|
|
}); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Step out
|
|
|
Interface.prototype.out = function() { |
|
|
Interface.prototype.out = function() { |
|
|
this.requireConnection(); |
|
|
this.requireConnection(); |
|
|
|
|
|
|
|
@ -906,6 +980,8 @@ Interface.prototype.out = function() { |
|
|
}); |
|
|
}); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Show breakpoints
|
|
|
Interface.prototype.breakpoints = function() { |
|
|
Interface.prototype.breakpoints = function() { |
|
|
this.requireConnection(); |
|
|
this.requireConnection(); |
|
|
this.pause(); |
|
|
this.pause(); |
|
@ -920,53 +996,27 @@ Interface.prototype.breakpoints = function() { |
|
|
}); |
|
|
}); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Kill child process
|
|
|
Interface.prototype.kill = function() { |
|
|
Interface.prototype.kill = function() { |
|
|
if (!this.child) return; |
|
|
if (!this.child) return; |
|
|
this.killChild(); |
|
|
this.killChild(); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Activate debug repl
|
|
|
Interface.prototype.repl = function() { |
|
|
Interface.prototype.repl = function() { |
|
|
if (!this.child) throw Error('App isn\'t running... Try `run()` instead'); |
|
|
this.requireConnection(); |
|
|
|
|
|
|
|
|
var self = this; |
|
|
var self = this; |
|
|
|
|
|
|
|
|
this.debugRepl = true; |
|
|
// Exit debug repl on Ctrl + C
|
|
|
|
|
|
|
|
|
this.repl.rli.once('SIGINT', function() { |
|
|
this.repl.rli.once('SIGINT', function() { |
|
|
self.exitRepl(); |
|
|
self.exitRepl(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
var client = this.client; |
|
|
|
|
|
|
|
|
|
|
|
// Save old eval
|
|
|
|
|
|
this.repl._eval = this.repl.eval; |
|
|
|
|
|
|
|
|
|
|
|
// Set new
|
|
|
// Set new
|
|
|
this.repl.eval = function(code, context, filename, callback) { |
|
|
this.repl.eval = this.debugEval.bind(this); |
|
|
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.context = {}; |
|
|
this.repl.context = {}; |
|
|
|
|
|
|
|
|
this.repl.prompt = '> '; |
|
|
this.repl.prompt = '> '; |
|
@ -974,9 +1024,11 @@ Interface.prototype.repl = function() { |
|
|
this.repl.displayPrompt(); |
|
|
this.repl.displayPrompt(); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Exit debug repl
|
|
|
Interface.prototype.exitRepl = function() { |
|
|
Interface.prototype.exitRepl = function() { |
|
|
this.debugRepl = false; |
|
|
this.repl.eval = this.controlEval.bind(this); |
|
|
this.repl.eval = this.repl._eval; |
|
|
|
|
|
this.repl.context = this.context; |
|
|
this.repl.context = this.context; |
|
|
this.repl.prompt = 'debug> '; |
|
|
this.repl.prompt = 'debug> '; |
|
|
this.repl.rli.setPrompt('debug> '); |
|
|
this.repl.rli.setPrompt('debug> '); |
|
@ -1013,7 +1065,7 @@ Interface.prototype.trySpawn = function(cb) { |
|
|
var connectionAttempts = 0; |
|
|
var connectionAttempts = 0; |
|
|
|
|
|
|
|
|
client.once('ready', function() { |
|
|
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
|
|
|
// since we did debug-brk, we're hitting a break point immediately
|
|
|
// continue before anything else.
|
|
|
// continue before anything else.
|
|
@ -1062,8 +1114,3 @@ Interface.prototype.trySpawn = function(cb) { |
|
|
attemptConnect(); |
|
|
attemptConnect(); |
|
|
}, 50); |
|
|
}, 50); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|