diff --git a/doc/api/debugger.markdown b/doc/api/debugger.markdown index 2bbaf9049eb5fb..400192ee00c2da 100644 --- a/doc/api/debugger.markdown +++ b/doc/api/debugger.markdown @@ -84,6 +84,9 @@ The `repl` command allows code to be evaluated remotely. The `next` command steps over to the next line. Type `help` to see what other commands are available. +Pressing `enter` without typing a command will repeat the previous debugger +command. + ## Watchers It is possible to watch expression and variable values while debugging. On diff --git a/lib/_debugger.js b/lib/_debugger.js index 8a72121f60176a..5ad200a43a87ee 100644 --- a/lib/_debugger.js +++ b/lib/_debugger.js @@ -673,6 +673,9 @@ var helpMessage = 'Commands: ' + commands.map(function(group) { return group.join(', '); }).join(',\n'); +// Previous command received. Initialize to empty command. +var lastCommand = '\n'; + function SourceUnderline(sourceText, position, repl) { if (!sourceText) return ''; @@ -944,10 +947,10 @@ Interface.prototype.requireConnection = function() { Interface.prototype.controlEval = function(code, context, filename, callback) { try { // Repeat last command if empty line are going to be evaluated - if (this.repl.rli.history && this.repl.rli.history.length > 0) { - if (code === '\n') { - code = this.repl.rli.history[0] + '\n'; - } + if (code === '\n') { + code = lastCommand; + } else { + lastCommand = code; } // exec process.title => exec("process.title"); diff --git a/lib/repl.js b/lib/repl.js index 1dce26ce6aa77e..e63016e526d36c 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -222,6 +222,10 @@ function REPLServer(prompt, function defaultEval(code, context, file, cb) { var err, result, retry = false, input = code, wrappedErr; // first, create the Script object to check the syntax + + if (code === '\n') + return cb(null); + while (true) { try { if (!/^\s*$/.test(code) && @@ -419,28 +423,24 @@ function REPLServer(prompt, } } - if (cmd || self.bufferedCommand) { - var evalCmd = self.bufferedCommand + cmd; - if (/^\s*\{/.test(evalCmd) && /\}\s*$/.test(evalCmd)) { - // It's confusing for `{ a : 1 }` to be interpreted as a block - // statement rather than an object literal. So, we first try - // to wrap it in parentheses, so that it will be interpreted as - // an expression. - evalCmd = '(' + evalCmd + ')\n'; - self.wrappedCmd = true; - } else { - // otherwise we just append a \n so that it will be either - // terminated, or continued onto the next expression if it's an - // unexpected end of input. - evalCmd = evalCmd + '\n'; - } - - debug('eval %j', evalCmd); - self.eval(evalCmd, self.context, 'repl', finish); + var evalCmd = self.bufferedCommand + cmd; + if (/^\s*\{/.test(evalCmd) && /\}\s*$/.test(evalCmd)) { + // It's confusing for `{ a : 1 }` to be interpreted as a block + // statement rather than an object literal. So, we first try + // to wrap it in parentheses, so that it will be interpreted as + // an expression. + evalCmd = '(' + evalCmd + ')\n'; + self.wrappedCmd = true; } else { - finish(null); + // otherwise we just append a \n so that it will be either + // terminated, or continued onto the next expression if it's an + // unexpected end of input. + evalCmd = evalCmd + '\n'; } + debug('eval %j', evalCmd); + self.eval(evalCmd, self.context, 'repl', finish); + function finish(e, ret) { debug('finish', e, ret); self.memory(cmd); diff --git a/test/fixtures/debugger-repeat-last.js b/test/fixtures/debugger-repeat-last.js new file mode 100644 index 00000000000000..86df8eebcb76a7 --- /dev/null +++ b/test/fixtures/debugger-repeat-last.js @@ -0,0 +1,7 @@ +var a = 1; + +var b = 2; + +var c = 3; + +b = c; diff --git a/test/parallel/test-debugger-repeat-last.js b/test/parallel/test-debugger-repeat-last.js new file mode 100644 index 00000000000000..7f0e1e68165019 --- /dev/null +++ b/test/parallel/test-debugger-repeat-last.js @@ -0,0 +1,46 @@ +'use strict'; +const path = require('path'); +const spawn = require('child_process').spawn; +const assert = require('assert'); + +const common = require('../common'); + +const fixture = path.join( + common.fixturesDir, + 'debugger-repeat-last.js' +); + +const args = [ + 'debug', + fixture +]; + +const proc = spawn(process.execPath, args, { stdio: 'pipe' }); +proc.stdout.setEncoding('utf8'); + +var stdout = ''; + +var sentCommand = false; +var sentEmpty = false; +var sentExit = false; + +proc.stdout.on('data', (data) => { + stdout += data; + if (!sentCommand && stdout.includes('> 1')) { + setImmediate(() => {proc.stdin.write('n\n');}); + return sentCommand = true; + } + if (!sentEmpty && stdout.includes('> 3')) { + setImmediate(() => {proc.stdin.write('\n');}); + return sentEmpty = true; + } + if (!sentExit && sentCommand && sentEmpty) { + setTimeout(() => {proc.stdin.write('\n\n\n.exit\n\n\n');}, 1); + return sentExit = true; + } +}); + +process.on('exit', (exitCode) => { + assert.strictEqual(exitCode, 0); + console.log(stdout); +});