From 19194f87c5a3a6184168babb6f8d2629a2443c0a Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Wed, 14 Sep 2011 16:24:46 +0700 Subject: [PATCH] [debugger] setBreakpoint, clearBreakpoint, fix reqSource error handling, show breakpoints in list() --- lib/_debugger.js | 133 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 114 insertions(+), 19 deletions(-) diff --git a/lib/_debugger.js b/lib/_debugger.js index a15a17610fe..55140dbdccc 100644 --- a/lib/_debugger.js +++ b/lib/_debugger.js @@ -149,6 +149,7 @@ function Client() { this.currentSource = null; this.handles = {}; this.scripts = {}; + this.breakpoints = []; // Note that 'Protocol' requires strings instead of Buffers. socket.setEncoding('utf8'); @@ -432,6 +433,17 @@ Client.prototype.setBreakpoint = function(req, cb) { }); }; +Client.prototype.clearBreakpoint = function(req, cb) { + var req = { + command: 'clearbreakpoint', + arguments: req + }; + + this.req(req, function(res) { + if (cb) cb(res); + }); +}; + Client.prototype.reqSource = function(from, to, cb) { var req = { command: 'source', @@ -440,7 +452,7 @@ Client.prototype.reqSource = function(from, to, cb) { }; this.req(req, function(res) { - if (cb) cb(res.body); + if (cb) cb(!res.success && (res.message || true), res.body); }); }; @@ -695,7 +707,9 @@ function Interface() { 'next': 'n', 'step': 's', 'out': 'o', - 'backtrace': 'bt' + 'backtrace': 'bt', + 'setBreakpoint': 'sb', + 'clearBreakpoint': 'cb' }; function defineProperty(key, protoKey) { @@ -860,12 +874,12 @@ function intChars(n) { } -function leftPad(n) { +function leftPad(n, prefix) { var s = n.toString(); var nchars = intChars(n); var nspaces = nchars - s.length; for (var i = 0; i < nspaces; i++) { - s = ' ' + s; + s = (prefix || ' ') + s; } return s; } @@ -926,8 +940,10 @@ Interface.prototype.list = function() { to = client.currentSourceLine + delta + 1; self.pause(); - client.reqSource(from, to, function(res) { - if (!res.source) return self.error('You can\'t list source code right now'); + client.reqSource(from, to, function(err, res) { + if (err || !res) { + return self.error('You can\'t list source code right now'); + } var lines = res.source.split('\n'); for (var i = 0; i < lines.length; i++) { @@ -941,17 +957,22 @@ Interface.prototype.list = function() { lines[i] = lines[i].slice(wrapper.length); } + var breakpoint = client.breakpoints.some(function(bp) { + return bp.script === client.currentScript && + bp.line == lineno; + }); + if (lineno == 1 + client.currentSourceLine) { - var nchars = intChars(lineno); - var pointer = ''; - for (var j = 0; j < nchars - 1; j++) { + var nchars = intChars(lineno), + pointer = breakpoint ? '*' : '='; + for (var j = 1; j < nchars - 1; j++) { pointer += '='; } pointer += '>'; - self.print(pointer + ' ' + SourceUnderline(lines[i], - client.currentSourceColumn)); + self.print(pointer + ' ' + + SourceUnderline(lines[i], client.currentSourceColumn)); } else { - self.print(leftPad(lineno) + ' ' + lines[i]); + self.print(leftPad(lineno, breakpoint && '*') + ' ' + lines[i]); } } self.resume(); @@ -1009,6 +1030,7 @@ Interface.prototype.scripts = function(displayNatives) { !script.isNative) { scripts.push( (script.name == client.currentScript ? '* ' : ' ') + + id + ': ' + require('path').basename(script.name) ); } @@ -1060,18 +1082,91 @@ Interface.prototype.out = Interface.stepGenerator('out', 1); // Add breakpoint Interface.prototype.setBreakpoint = function(script, line, condition) { + if (!this.requireConnection()) return; + var self = this, - req = { - type: 'script', - target: script, - line: line, - condition: condition - }; + scriptId, + ambiguous; + + if (!this.client.scripts[script]) { + Object.keys(this.client.scripts).forEach(function(id) { + if (self.client.scripts[id].name.indexOf(script) !== -1) { + if (scriptId) { + ambiguous = true; + } + scriptId = id; + } + }); + } else { + scriptId = script; + } + + if (!scriptId) return this.error('Script : ' + script + ' not found'); + if (ambiguous) return this.error('Script name is ambiguous'); + if (line <= 0) return this.error('Line should be a positive value'); + + var req = { + type: 'scriptId', + target: scriptId, + line: line - 1, + condition: condition + }; self.pause(); self.client.setBreakpoint(req, function(res) { if (res.success) { - self.print('ok'); + self.list(5); + self.client.breakpoints.push({ + id: res.body.breakpoint, + scriptId: scriptId, + script: self.client.scripts[scriptId].name, + line: line + }); + + } else { + self.print(req.message || 'error!'); + } + self.resume(); + }); +}; + +// Clear breakpoint +Interface.prototype.clearBreakpoint = function(script, line) { + if (!this.requireConnection()) return; + + var ambiguous, + breakpoint, + index; + + this.client.breakpoints.some(function(bp, i) { + if (bp.scriptId === script || bp.script.indexOf(script) !== -1) { + if (index !== undefined) { + ambiguous = true; + } + if (bp.line === line) { + index = i; + breakpoint = bp.id; + return true; + } + } + }); + + if (ambiguous) return this.error('Script name is ambiguous'); + + if (breakpoint === undefined) { + return this.error('Script : ' + script + ' not found'); + } + + var self = this, + req = { + breakpoint: breakpoint + }; + + self.pause(); + self.client.clearBreakpoint(req, function(res) { + if (res.success) { + self.client.breakpoints = self.client.breakpoints.splice(index, -1); + self.list(5); } else { self.print(req.message || 'error!'); }