[debugger] readline => repl
Started porting to high-level javascript API and repl.
This commit is contained in:
parent
4527de8cba
commit
bd69afbc83
243
lib/_debugger.js
243
lib/_debugger.js
@ -20,7 +20,7 @@
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
var net = require('net');
|
||||
var readline = require('readline');
|
||||
var repl = require('repl');
|
||||
var inherits = require('util').inherits;
|
||||
var spawn = require('child_process').spawn;
|
||||
|
||||
@ -597,19 +597,11 @@ function SourceInfo(body) {
|
||||
}
|
||||
|
||||
|
||||
// This class is the readline-enabled debugger interface which is invoked on
|
||||
// This class is the repl-enabled debugger interface which is invoked on
|
||||
// "node debug"
|
||||
function Interface() {
|
||||
var self = this;
|
||||
var child;
|
||||
var client;
|
||||
|
||||
function complete(line) {
|
||||
return self.complete(line);
|
||||
}
|
||||
|
||||
var term = readline.createInterface(process.stdin, process.stdout, complete);
|
||||
this.term = term;
|
||||
var self = this,
|
||||
child;
|
||||
|
||||
process.on('exit', function() {
|
||||
self.killChild();
|
||||
@ -617,104 +609,45 @@ function Interface() {
|
||||
|
||||
this.stdin = process.openStdin();
|
||||
|
||||
term.setPrompt('debug> ');
|
||||
term.prompt();
|
||||
this.repl = repl.start('debug> ');
|
||||
|
||||
// Lift all instance methods to repl context
|
||||
var proto = Interface.prototype,
|
||||
ignored = ['pause', 'resume', 'handleSIGINT'];
|
||||
|
||||
for (var i in proto) {
|
||||
if (proto.hasOwnProperty(i) && ignored.indexOf(i) === -1) {
|
||||
this.repl.context[i] = proto[i].bind(this);
|
||||
}
|
||||
}
|
||||
|
||||
this.quitting = false;
|
||||
this.paused = 0;
|
||||
|
||||
process.on('SIGINT', function() {
|
||||
self.handleSIGINT();
|
||||
});
|
||||
|
||||
term.on('SIGINT', function() {
|
||||
self.handleSIGINT();
|
||||
});
|
||||
|
||||
term.on('attemptClose', function() {
|
||||
self.tryQuit();
|
||||
});
|
||||
|
||||
term.on('line', function(cmd) {
|
||||
// trim whitespace
|
||||
cmd = cmd.replace(/^\s*/, '').replace(/\s*$/, '');
|
||||
|
||||
if (cmd.length) {
|
||||
self._lastCommand = cmd;
|
||||
self.handleCommand(cmd);
|
||||
} else {
|
||||
self.handleCommand(self._lastCommand);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Interface.prototype.complete = function(line) {
|
||||
// Match me with a command.
|
||||
var matches = [];
|
||||
// Remove leading whitespace
|
||||
line = line.replace(/^\s*/, '');
|
||||
|
||||
for (var i = 0; i < commands.length; i++) {
|
||||
if (commands[i].indexOf(line) === 0) {
|
||||
matches.push(commands[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return [matches, line];
|
||||
};
|
||||
|
||||
|
||||
Interface.prototype.handleSIGINT = function() {
|
||||
if (this.paused) {
|
||||
this.child.kill('SIGINT');
|
||||
} else {
|
||||
this.tryQuit();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Interface.prototype.quit = function() {
|
||||
if (this.quitting) return;
|
||||
this.quitting = true;
|
||||
this.killChild();
|
||||
this.term.close();
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
|
||||
Interface.prototype.tryQuit = function() {
|
||||
var self = this;
|
||||
|
||||
if (self.child) {
|
||||
self.quitQuestion(function(yes) {
|
||||
if (yes) {
|
||||
self.quit();
|
||||
} else {
|
||||
self.term.prompt();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.quit();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Interface.prototype.pause = function() {
|
||||
this.paused = true;
|
||||
if (this.paused++ > 0) return false;
|
||||
this.stdin.pause();
|
||||
this.term.pause();
|
||||
this.repl.rli.pause();
|
||||
};
|
||||
|
||||
|
||||
Interface.prototype.resume = function() {
|
||||
if (!this.paused) return false;
|
||||
this.paused = false;
|
||||
if (this.paused === 0 || --this.paused !== 0) return false;
|
||||
this.stdin.resume();
|
||||
this.term.resume();
|
||||
this.term.prompt();
|
||||
return true;
|
||||
this.repl.rli.resume();
|
||||
process.stdout.write('\n');
|
||||
this.repl.displayPrompt();
|
||||
};
|
||||
|
||||
Interface.prototype.handleSIGINT = function() {
|
||||
this.child.kill('SIGINT');
|
||||
};
|
||||
|
||||
|
||||
|
||||
Interface.prototype.handleBreak = function(r) {
|
||||
var result = '';
|
||||
@ -745,8 +678,6 @@ Interface.prototype.handleBreak = function(r) {
|
||||
this.client.currentScript = r.script.name;
|
||||
|
||||
console.log(result);
|
||||
|
||||
if (!this.resume()) this.term.prompt();
|
||||
};
|
||||
|
||||
|
||||
@ -774,6 +705,46 @@ function leftPad(n) {
|
||||
return s;
|
||||
}
|
||||
|
||||
Interface.prototype.help = function() {
|
||||
this.pause();
|
||||
process.stdout.write(helpMessage);
|
||||
this.resume();
|
||||
};
|
||||
|
||||
Interface.prototype.run = function() {
|
||||
if (this.child) {
|
||||
throw Error('App is already running... Try `restart()` instead');
|
||||
} else {
|
||||
this.trySpawn();
|
||||
}
|
||||
};
|
||||
|
||||
Interface.prototype.restart = function() {
|
||||
if (!this.child) throw Error('App isn\'t running... Try `run()` instead');
|
||||
|
||||
var self = this;
|
||||
|
||||
this.killChild();
|
||||
|
||||
// XXX need to wait a little bit for the restart to work?
|
||||
setTimeout(function() {
|
||||
self.trySpawn();
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
Interface.prototype.version = function() {
|
||||
if (!this.child) throw Error('App isn\'t running... Try `run()` instead');
|
||||
|
||||
var self = this;
|
||||
|
||||
this.pause();
|
||||
this.client.reqVersion(function(v) {
|
||||
process.stdout.write(v);
|
||||
self.resume();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
Interface.prototype.handleCommand = function(cmd) {
|
||||
var self = this;
|
||||
@ -786,29 +757,9 @@ Interface.prototype.handleCommand = function(cmd) {
|
||||
self.tryQuit();
|
||||
|
||||
} else if (/^r(un)?/.test(cmd)) {
|
||||
self._lastCommand = null;
|
||||
if (self.child) {
|
||||
self.restartQuestion(function(yes) {
|
||||
if (!yes) {
|
||||
self._lastCommand = null;
|
||||
term.prompt();
|
||||
} else {
|
||||
console.log('restarting...');
|
||||
self.killChild();
|
||||
// XXX need to wait a little bit for the restart to work?
|
||||
setTimeout(function() {
|
||||
self.trySpawn();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.trySpawn();
|
||||
}
|
||||
|
||||
// DONE
|
||||
} else if (/^help/.test(cmd)) {
|
||||
console.log(helpMessage);
|
||||
term.prompt();
|
||||
|
||||
// DONE
|
||||
} else if ('version' == cmd) {
|
||||
if (!client) {
|
||||
self.printNotConnected();
|
||||
@ -816,7 +767,6 @@ Interface.prototype.handleCommand = function(cmd) {
|
||||
}
|
||||
client.reqVersion(function(v) {
|
||||
console.log(v);
|
||||
term.prompt();
|
||||
});
|
||||
|
||||
} else if (/info +breakpoints/.test(cmd)) {
|
||||
@ -826,7 +776,6 @@ Interface.prototype.handleCommand = function(cmd) {
|
||||
}
|
||||
client.listbreakpoints(function(res) {
|
||||
console.log(res);
|
||||
term.prompt();
|
||||
});
|
||||
|
||||
|
||||
@ -864,7 +813,6 @@ Interface.prototype.handleCommand = function(cmd) {
|
||||
console.log(leftPad(lineno) + ' ' + lines[i]);
|
||||
}
|
||||
}
|
||||
term.prompt();
|
||||
});
|
||||
|
||||
} else if (/^backtrace/.test(cmd) || /^bt/.test(cmd)) {
|
||||
@ -894,7 +842,6 @@ Interface.prototype.handleCommand = function(cmd) {
|
||||
|
||||
console.log(text);
|
||||
}
|
||||
term.prompt();
|
||||
});
|
||||
|
||||
} else if (cmd == 'scripts' || cmd == 'scripts full') {
|
||||
@ -903,7 +850,6 @@ Interface.prototype.handleCommand = function(cmd) {
|
||||
return;
|
||||
}
|
||||
self.printScripts(cmd.indexOf('full') > 0);
|
||||
term.prompt();
|
||||
|
||||
} else if (/^c(ontinue)?/.test(cmd)) {
|
||||
if (!client) {
|
||||
@ -931,7 +877,6 @@ Interface.prototype.handleCommand = function(cmd) {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.term.prompt();
|
||||
}
|
||||
|
||||
} else if (/^next/.test(cmd) || /^n/.test(cmd)) {
|
||||
@ -960,19 +905,16 @@ Interface.prototype.handleCommand = function(cmd) {
|
||||
var i = cmd.indexOf(' ');
|
||||
if (i < 0) {
|
||||
console.log('print [expression]');
|
||||
term.prompt();
|
||||
} else {
|
||||
cmd = cmd.slice(i);
|
||||
client.reqEval(cmd, function(res) {
|
||||
if (!res.success) {
|
||||
console.log(res.message);
|
||||
term.prompt();
|
||||
return;
|
||||
}
|
||||
|
||||
client.mirrorObject(res.body, function(mirror) {
|
||||
console.log(mirror);
|
||||
term.prompt();
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -982,45 +924,11 @@ Interface.prototype.handleCommand = function(cmd) {
|
||||
// If it's not all white-space print this error message.
|
||||
console.log('Unknown command "%s". Try "help"', cmd);
|
||||
}
|
||||
term.prompt();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
Interface.prototype.yesNoQuestion = function(prompt, cb) {
|
||||
var self = this;
|
||||
self.resume();
|
||||
this.term.question(prompt, function(answer) {
|
||||
if (/^y(es)?$/i.test(answer)) {
|
||||
cb(true);
|
||||
} else if (/^n(o)?$/i.test(answer)) {
|
||||
cb(false);
|
||||
} else {
|
||||
console.log('Please answer y or n.');
|
||||
self.yesNoQuestion(prompt, cb);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Interface.prototype.restartQuestion = function(cb) {
|
||||
this.yesNoQuestion('The program being debugged has been started already.\n' +
|
||||
'Start it from the beginning? (y or n) ', cb);
|
||||
};
|
||||
|
||||
|
||||
Interface.prototype.killQuestion = function(cb) {
|
||||
this.yesNoQuestion('Kill the program being debugged? (y or n) ', cb);
|
||||
};
|
||||
|
||||
|
||||
Interface.prototype.quitQuestion = function(cb) {
|
||||
this.yesNoQuestion('A debugging session is active. Quit anyway? (y or n) ',
|
||||
cb);
|
||||
};
|
||||
|
||||
|
||||
Interface.prototype.killChild = function() {
|
||||
if (this.child) {
|
||||
this.child.kill();
|
||||
@ -1050,26 +958,25 @@ Interface.prototype.trySpawn = function(cb) {
|
||||
var connectionAttempts = 0;
|
||||
|
||||
client.once('ready', function() {
|
||||
process.stdout.write(' ok\r\n');
|
||||
process.stdout.write(' ok');
|
||||
|
||||
// since we did debug-brk, we're hitting a break point immediately
|
||||
// continue before anything else.
|
||||
client.reqContinue(function() {
|
||||
self.resume();
|
||||
if (cb) cb();
|
||||
});
|
||||
|
||||
client.on('close', function() {
|
||||
console.log('\nprogram terminated');
|
||||
console.log('program terminated');
|
||||
self.client = null;
|
||||
self.killChild();
|
||||
if (!self.quitting) self.term.prompt();
|
||||
});
|
||||
});
|
||||
|
||||
client.on('unhandledResponse', function(res) {
|
||||
console.log('\r\nunhandled res:');
|
||||
console.log(res);
|
||||
self.term.prompt();
|
||||
});
|
||||
|
||||
client.on('break', function(res) {
|
||||
@ -1098,12 +1005,6 @@ Interface.prototype.trySpawn = function(cb) {
|
||||
};
|
||||
|
||||
|
||||
Interface.prototype.printNotConnected = function() {
|
||||
console.log("Program not running. Try 'run'.");
|
||||
this.term.prompt();
|
||||
};
|
||||
|
||||
|
||||
// argument full tells if it should display internal node scripts or not
|
||||
Interface.prototype.printScripts = function(displayNatives) {
|
||||
var client = this.client;
|
||||
|
Loading…
x
Reference in New Issue
Block a user