From b7365c15597253e906590045aa6f3f07f6e76b52 Mon Sep 17 00:00:00 2001 From: Xiaowei Li <446240525@qq.com> Date: Mon, 19 Jan 2015 13:42:05 +0800 Subject: [PATCH] repl: make REPL support multiline template literals Let REPL enter multiline mode if user's input contains unterminated template literals. PR-URL: https://github.com/iojs/io.js/pull/333 Reviewed-By: Ben Noordhuis --- lib/repl.js | 27 +++++++++++++++++++++------ test/parallel/test-repl.js | 11 +++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/lib/repl.js b/lib/repl.js index 2d7dc14604..1ecf695efd 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -87,6 +87,8 @@ function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) { self.useGlobal = !!useGlobal; self.ignoreUndefined = !!ignoreUndefined; + self._inTemplateLiteral = false; + // just for backwards compat, see github.com/joyent/node/pull/7127 self.rli = this; @@ -102,7 +104,7 @@ function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) { }); } catch (e) { debug('parse error %j', code, e); - if (isRecoverableError(e)) + if (isRecoverableError(e, self)) err = new Recoverable(e); else err = e; @@ -226,7 +228,13 @@ function REPLServer(prompt, stream, eval_, useGlobal, ignoreUndefined) { debug('line %j', cmd); sawSIGINT = false; var skipCatchall = false; - cmd = trimWhitespace(cmd); + + // leading whitespaces in template literals should not be trimmed. + if (self._inTemplateLiteral) { + self._inTemplateLiteral = false; + } else { + cmd = trimWhitespace(cmd); + } // Check to see if a REPL keyword was used. If it returns true, // display next prompt and return. @@ -928,10 +936,17 @@ REPLServer.prototype.convertToContext = function(cmd) { // If the error is that we've unexpectedly ended the input, // then let the user try to recover by adding more input. -function isRecoverableError(e) { - return e && - e.name === 'SyntaxError' && - /^(Unexpected end of input|Unexpected token :)/.test(e.message); +function isRecoverableError(e, self) { + if (e && e.name === 'SyntaxError') { + var message = e.message; + if (message === 'Unterminated template literal' || + message === 'Missing } in template expression') { + self._inTemplateLiteral = true; + return true; + } + return /^(Unexpected end of input|Unexpected token :)/.test(message); + } + return false; } function Recoverable(err) { diff --git a/test/parallel/test-repl.js b/test/parallel/test-repl.js index 5f775b4094..e1087a2e1d 100644 --- a/test/parallel/test-repl.js +++ b/test/parallel/test-repl.js @@ -104,6 +104,17 @@ function error_test() { // But passing the same string to eval() should throw { client: client_unix, send: 'eval("function test_func() {")', expect: /^SyntaxError: Unexpected end of input/ }, + // Can handle multiline template literals + { client: client_unix, send: '`io.js', + expect: prompt_multiline }, + // Special REPL commands still available + { client: client_unix, send: '.break', + expect: prompt_unix }, + // Template expressions can cross lines + { client: client_unix, send: '`io.js ${"1.0"', + expect: prompt_multiline }, + { client: client_unix, send: '+ ".2"}`', + expect: `'io.js 1.0.2'\n${prompt_unix}` }, // Floating point numbers are not interpreted as REPL commands. { client: client_unix, send: '.1234', expect: '0.1234' },