added comments, spawn child process automatically at debugger's start
authorFedor Indutny <fedor.indutny@gmail.com>
Tue, 20 Sep 2011 08:30:39 +0000 (15:30 +0700)
committerRyan Dahl <ry@tinyclouds.org>
Tue, 20 Sep 2011 15:35:15 +0000 (08:35 -0700)
lib/_debugger.js

index 69970bf..9e1c584 100644 (file)
@@ -697,19 +697,22 @@ function Interface() {
   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',
@@ -737,6 +740,8 @@ function Interface() {
     }
   };
 
+  // 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);
@@ -753,6 +758,9 @@ function Interface() {
     control: []
   };
   this.breakpoints = [];
+
+  // Run script automatically
+  this.run();
 };
 
 
@@ -780,7 +788,7 @@ Interface.prototype.resume = function(silent) {
 };
 
 
-// Output
+// Print text to output stream
 Interface.prototype.print = function(text) {
   if (this.killed) return;
   if (process.stdout.isTTY) {
@@ -791,6 +799,7 @@ Interface.prototype.print = function(text) {
   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;
@@ -800,26 +809,35 @@ Interface.prototype.childPrint = function(text) {
   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');
@@ -828,11 +846,20 @@ Interface.prototype.requireConnection = function() {
   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);
     };
@@ -841,22 +868,22 @@ Interface.prototype.controlEval = function(code, context, filename, callback) {
   }
 };
 
+// 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) {
@@ -868,6 +895,7 @@ Interface.prototype.debugEval = function(code, context, filename, callback) {
       return;
     }
 
+    // Request object by handles (and it's sub-properties)
     client.mirrorObject(res.body, 3, function(mirror) {
       callback(null, mirror);
       self.resume(true);
@@ -876,8 +904,9 @@ Interface.prototype.debugEval = function(code, context, filename, callback) {
 };
 
 
-// Commands
+// Utils
 
+// Returns number of digits (+1)
 function intChars(n) {
   // TODO dumb:
   if (n < 50) {
@@ -891,7 +920,7 @@ function intChars(n) {
   }
 }
 
-
+// Adds spaces and prefix to number
 function leftPad(n, prefix) {
   var s = n.toString();
   var nchars = intChars(n);
@@ -903,6 +932,9 @@ function leftPad(n, prefix) {
 }
 
 
+// Commands
+
+
 // Print help message
 Interface.prototype.help = function() {
   this.print(helpMessage);
@@ -1028,7 +1060,8 @@ Interface.prototype.backtrace = function() {
 };
 
 
-// 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;
 
@@ -1281,6 +1314,7 @@ Interface.prototype.exitRepl = function() {
 };
 
 
+// Kills child process
 Interface.prototype.killChild = function() {
   if (this.child) {
     this.child.kill();
@@ -1297,6 +1331,7 @@ Interface.prototype.killChild = function() {
 };
 
 
+// Spawns child process (and restores breakpoints)
 Interface.prototype.trySpawn = function(cb) {
   var self = this,
       breakpoints = this.breakpoints || [];