From 83119db45ef3e91926d74e82a505700f6ce84934 Mon Sep 17 00:00:00 2001 From: monkingxue Date: Wed, 9 May 2018 10:34:57 +0800 Subject: [PATCH] repl: add friendly tips about how to exit repl Imitate python repl, when the user enters 'exit' or 'quit', no longer prompt 'Reference Error', but prompts 'To exit, press ^D or type .exit'. If the user defines variables named 'exit' or 'quit' , only the value of the variables are output PR-URL: https://github.com/nodejs/node/pull/20617 Fixes: https://github.com/nodejs/node/issues/19021 Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater --- lib/repl.js | 18 ++++++++++++++---- test/parallel/test-repl.js | 24 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/lib/repl.js b/lib/repl.js index 600816a6058fbc..928e7c6d69cfae 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -215,9 +215,15 @@ function REPLServer(prompt, function defaultEval(code, context, file, cb) { var err, result, script, wrappedErr; + var isExitCommand = false; var wrappedCmd = false; var awaitPromise = false; var input = code; + var trimmedCommand = code.trim(); + + if (trimmedCommand === 'exit' || trimmedCommand === 'quit') { + isExitCommand = true; + } if (/^\s*\{/.test(code) && /\}\s*$/.test(code)) { // It's confusing for `{ a : 1 }` to be interpreted as a block @@ -313,10 +319,16 @@ function REPLServer(prompt, breakOnSigint: self.breakEvalOnSigint }; + const localContext = self.useGlobal ? global : self.context; + if (isExitCommand && !localContext.hasOwnProperty(trimmedCommand)) { + self.outputStream.write('(To exit, press ^D or type .exit)\n'); + return self.displayPrompt(); + } + if (self.useGlobal) { result = script.runInThisContext(scriptOptions); } else { - result = script.runInContext(context, scriptOptions); + result = script.runInContext(localContext, scriptOptions); } } finally { if (self.breakEvalOnSigint) { @@ -332,12 +344,10 @@ function REPLServer(prompt, } } catch (e) { err = e; - if (err && err.code === 'ERR_SCRIPT_EXECUTION_INTERRUPTED') { - // The stack trace for this case is not very useful anyway. + // The stack trace for this case is not very useful anyway. Object.defineProperty(err, 'stack', { value: '' }); } - if (process.domain) { debug('not recoverable, send to domain'); process.domain.emit('error', err); diff --git a/test/parallel/test-repl.js b/test/parallel/test-repl.js index e14398541dd8de..b9c92c3cd63bc0 100644 --- a/test/parallel/test-repl.js +++ b/test/parallel/test-repl.js @@ -132,6 +132,29 @@ const strictModeTests = [ } ]; +const friendlyExitTests = [ + { + send: 'exit', + expect: '(To exit, press ^D or type .exit)' + }, + { + send: 'quit', + expect: '(To exit, press ^D or type .exit)' + }, + { + send: 'quit = 1', + expect: '1' + }, + { + send: 'quit', + expect: '1' + }, + { + send: 'exit', + expect: '(To exit, press ^D or type .exit)' + }, +]; + const errorTests = [ // Uncaught error throws and prints out { @@ -742,6 +765,7 @@ const tcpTests = [ const [ socket, replServer ] = await startUnixRepl(); await runReplTests(socket, prompt_unix, unixTests); + await runReplTests(socket, prompt_unix, friendlyExitTests); await runReplTests(socket, prompt_unix, errorTests); replServer.replMode = repl.REPL_MODE_STRICT; await runReplTests(socket, prompt_unix, strictModeTests);