From b5aed43f04b50b2e21bf2c370b859f9b8fbd0270 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 22 Dec 2010 18:30:56 -0800 Subject: [PATCH] Add better breakpoint text --- lib/_debugger.js | 145 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 119 insertions(+), 26 deletions(-) diff --git a/lib/_debugger.js b/lib/_debugger.js index 83bc6c8fba0..d1920943ae4 100644 --- a/lib/_debugger.js +++ b/lib/_debugger.js @@ -142,7 +142,10 @@ Client.prototype._onResponse = function(res) { if (res.headers.Type == 'connect') { // do nothing + console.log(res); this.emit('ready'); + } else if (res.body && res.body.event == 'break') { + this.emit('break', res.body); } else if (cb) { this._reqCallbacks.splice(i, 1); cb(res.body); @@ -214,33 +217,76 @@ Client.prototype.reqScripts = function(cb) { Client.prototype.reqContinue = function(cb) { this.req({ command: 'continue' } , function (res) { - if (cb) cb(res.body); + if (cb) cb(res); }); }; var helpMessage = "Commands: scripts, backtrace, version, eval, help, quit"; +function SourceUnderline(source_text, position) { + if (!source_text) { + return; + } + + // 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. + var underline = ''; + for (var i = 0; i < position; i++) { + if (source_text[i] == '\t') { + underline += '\t'; + } else { + underline += ' '; + } + } + underline += '^'; + + // Return the source line text with the underline beneath. + return source_text + '\n' + underline; +} + +function SourceInfo(body) { + var result = ''; + + if (body.script) { + if (body.script.name) { + result += body.script.name; + } else { + result += '[unnamed]'; + } + } + result += ' line '; + result += body.sourceLine + 1; + result += ' column '; + result += body.sourceColumn + 1; + + return result; +} + + + + function startInterface() { - var i = readline.createInterface(process.stdout); + var term = readline.createInterface(process.stdout); var stdin = process.openStdin(); stdin.addListener('data', function(chunk) { - i.write(chunk); + term.write(chunk); }); var prompt = 'debug> '; - i.setPrompt(prompt); - i.prompt(); + term.setPrompt('debug> '); + term.prompt(); var quitTried = false; function tryQuit() { if (quitTried) return; quitTried = true; - i.close(); + term.close(); console.log("debug done\n"); if (c.writable) { c.reqContinue(function (res) { @@ -251,45 +297,64 @@ function startInterface() { } } - i.on('SIGINT', tryQuit); - i.on('close', tryQuit); + term.on('SIGINT', tryQuit); + term.on('close', tryQuit); + c.on('close', function () { + process.exit(0); + }); - i.on('line', function(cmd) { + term.on('line', function(cmd) { if (cmd == 'quit') { tryQuit(); } else if (/^help/.test(cmd)) { console.log(helpMessage); - i.prompt(); + term.prompt(); } else if ('version' == cmd) { c.reqVersion(function (v) { console.log(v); - i.prompt(); + term.prompt(); }); - } else if ('backtrace' == cmd || 'bt' == cmd) { + } else if (/^backtrace/.test(cmd) || /^bt/.test(cmd)) { c.reqBacktrace(function (bt) { - console.log(bt); - i.prompt(); + if (/full/.test(cmd)) { + console.log(bt); + } else if (bt.totalFrames == 0) { + console.log('(empty stack)'); + } else { + var result = 'Frames #' + bt.fromFrame + + ' to #' + (bt.toFrame - 1) + + ' of ' + bt.totalFrames + '\n'; + for (j = 0; j < bt.frames.length; j++) { + if (j != 0) result += '\n'; + result += bt.frames[j].text; + } + console.log(result); + } + term.prompt(); }); - } else if ('continue' == cmd || 'c' == cmd) { + } else if (/^continue/.test(cmd) || /^c/.test(cmd)) { c.reqContinue(function (res) { - console.log(res); - i.prompt(); + // Wait for break point. (disable raw mode?) }); } else if (/^scripts/.test(cmd)) { c.reqScripts(function (res) { - var text = res.map(function (x) { return x.text; }); - console.log(text.join('\n')); - i.prompt(); + if (/full/.test(cmd)) { + console.log(res); + } else { + var text = res.map(function (x) { return x.text; }); + console.log(text.join('\n')); + } + term.prompt(); }); } else if (/^eval/.test(cmd)) { c.reqEval(cmd.slice(5), function (res) { console.log(res); - i.prompt(); + term.prompt(); }); } else { @@ -297,17 +362,45 @@ function startInterface() { // If it's not all white-space print this error message. console.log('Unknown command "%s". Try "help"', cmd); } - i.prompt(); + term.prompt(); } }); c.on('unhandledResponse', function (res) { console.log("\r\nunhandled res:"); - console.log(res.body); - i.prompt(); + console.log(res); + term.prompt(); }); - i.on('close', function() { - stdin.destroy(); + c.on('break', function (res) { + var result = ''; + if (res.body.breakpoints) { + result += 'breakpoint'; + if (res.body.breakpoints.length > 1) { + result += 's'; + } + result += ' #'; + for (var i = 0; i < res.body.breakpoints.length; i++) { + if (i > 0) { + result += ', #'; + } + result += res.body.breakpoints[i]; + } + } else { + result += 'break'; + } + result += ' in '; + result += res.body.invocationText; + result += ', '; + result += SourceInfo(res.body); + result += '\n'; + result += SourceUnderline(res.body.sourceLineText, res.body.sourceColumn); + + c.currentSourceLine = res.body.sourceLine; + c.currentFrame = 0; + + console.log(result); + + term.prompt(); }); }