|
1 | 1 | 'use strict'; |
2 | 2 |
|
3 | | -const { Interface } = require('readline'); |
4 | 3 | const REPL = require('repl'); |
5 | | -const path = require('path'); |
6 | | -const fs = require('fs'); |
7 | | -const os = require('os'); |
8 | | -const util = require('util'); |
9 | | -const debug = util.debuglog('repl'); |
| 4 | + |
10 | 5 | module.exports = Object.create(REPL); |
11 | 6 | module.exports.createInternalRepl = createRepl; |
12 | 7 |
|
13 | | -// XXX(chrisdickinson): The 15ms debounce value is somewhat arbitrary. |
14 | | -// The debounce is to guard against code pasted into the REPL. |
15 | | -const kDebounceHistoryMS = 15; |
16 | | - |
17 | | -function _writeToOutput(repl, message) { |
18 | | - repl._writeToOutput(message); |
19 | | - repl._refreshLine(); |
20 | | -} |
21 | | - |
22 | 8 | function createRepl(env, opts, cb) { |
23 | 9 | if (typeof opts === 'function') { |
24 | 10 | cb = opts; |
@@ -55,151 +41,9 @@ function createRepl(env, opts, cb) { |
55 | 41 | if (!Number.isNaN(historySize) && historySize > 0) { |
56 | 42 | opts.historySize = historySize; |
57 | 43 | } else { |
58 | | - // XXX(chrisdickinson): set here to avoid affecting existing applications |
59 | | - // using repl instances. |
60 | 44 | opts.historySize = 1000; |
61 | 45 | } |
62 | 46 |
|
63 | 47 | const repl = REPL.start(opts); |
64 | | - if (opts.terminal) { |
65 | | - return setupHistory(repl, env.NODE_REPL_HISTORY, cb); |
66 | | - } |
67 | | - |
68 | | - repl._historyPrev = _replHistoryMessage; |
69 | | - cb(null, repl); |
70 | | -} |
71 | | - |
72 | | -function setupHistory(repl, historyPath, ready) { |
73 | | - // Empty string disables persistent history |
74 | | - if (typeof historyPath === 'string') |
75 | | - historyPath = historyPath.trim(); |
76 | | - |
77 | | - if (historyPath === '') { |
78 | | - repl._historyPrev = _replHistoryMessage; |
79 | | - return ready(null, repl); |
80 | | - } |
81 | | - |
82 | | - if (!historyPath) { |
83 | | - try { |
84 | | - historyPath = path.join(os.homedir(), '.node_repl_history'); |
85 | | - } catch (err) { |
86 | | - _writeToOutput(repl, '\nError: Could not get the home directory.\n' + |
87 | | - 'REPL session history will not be persisted.\n'); |
88 | | - |
89 | | - debug(err.stack); |
90 | | - repl._historyPrev = _replHistoryMessage; |
91 | | - return ready(null, repl); |
92 | | - } |
93 | | - } |
94 | | - |
95 | | - var timer = null; |
96 | | - var writing = false; |
97 | | - var pending = false; |
98 | | - repl.pause(); |
99 | | - // History files are conventionally not readable by others: |
100 | | - // https://github.com/nodejs/node/issues/3392 |
101 | | - // https://github.com/nodejs/node/pull/3394 |
102 | | - fs.open(historyPath, 'a+', 0o0600, oninit); |
103 | | - |
104 | | - function oninit(err, hnd) { |
105 | | - if (err) { |
106 | | - // Cannot open history file. |
107 | | - // Don't crash, just don't persist history. |
108 | | - _writeToOutput(repl, '\nError: Could not open history file.\n' + |
109 | | - 'REPL session history will not be persisted.\n'); |
110 | | - debug(err.stack); |
111 | | - |
112 | | - repl._historyPrev = _replHistoryMessage; |
113 | | - repl.resume(); |
114 | | - return ready(null, repl); |
115 | | - } |
116 | | - fs.close(hnd, onclose); |
117 | | - } |
118 | | - |
119 | | - function onclose(err) { |
120 | | - if (err) { |
121 | | - return ready(err); |
122 | | - } |
123 | | - fs.readFile(historyPath, 'utf8', onread); |
124 | | - } |
125 | | - |
126 | | - function onread(err, data) { |
127 | | - if (err) { |
128 | | - return ready(err); |
129 | | - } |
130 | | - |
131 | | - if (data) { |
132 | | - repl.history = data.split(/[\n\r]+/, repl.historySize); |
133 | | - } else { |
134 | | - repl.history = []; |
135 | | - } |
136 | | - |
137 | | - fs.open(historyPath, 'r+', onhandle); |
138 | | - } |
139 | | - |
140 | | - function onhandle(err, hnd) { |
141 | | - if (err) { |
142 | | - return ready(err); |
143 | | - } |
144 | | - fs.ftruncate(hnd, 0, (err) => { |
145 | | - repl._historyHandle = hnd; |
146 | | - repl.on('line', online); |
147 | | - |
148 | | - // Reading the file data out erases it |
149 | | - repl.once('flushHistory', function() { |
150 | | - repl.resume(); |
151 | | - ready(null, repl); |
152 | | - }); |
153 | | - flushHistory(); |
154 | | - }); |
155 | | - } |
156 | | - |
157 | | - // ------ history listeners ------ |
158 | | - function online() { |
159 | | - repl._flushing = true; |
160 | | - |
161 | | - if (timer) { |
162 | | - clearTimeout(timer); |
163 | | - } |
164 | | - |
165 | | - timer = setTimeout(flushHistory, kDebounceHistoryMS); |
166 | | - } |
167 | | - |
168 | | - function flushHistory() { |
169 | | - timer = null; |
170 | | - if (writing) { |
171 | | - pending = true; |
172 | | - return; |
173 | | - } |
174 | | - writing = true; |
175 | | - const historyData = repl.history.join(os.EOL); |
176 | | - fs.write(repl._historyHandle, historyData, 0, 'utf8', onwritten); |
177 | | - } |
178 | | - |
179 | | - function onwritten(err, data) { |
180 | | - writing = false; |
181 | | - if (pending) { |
182 | | - pending = false; |
183 | | - online(); |
184 | | - } else { |
185 | | - repl._flushing = Boolean(timer); |
186 | | - if (!repl._flushing) { |
187 | | - repl.emit('flushHistory'); |
188 | | - } |
189 | | - } |
190 | | - } |
191 | | -} |
192 | | - |
193 | | - |
194 | | -function _replHistoryMessage() { |
195 | | - if (this.history.length === 0) { |
196 | | - _writeToOutput( |
197 | | - this, |
198 | | - '\nPersistent history support disabled. ' + |
199 | | - 'Set the NODE_REPL_HISTORY environment\nvariable to ' + |
200 | | - 'a valid, user-writable path to enable.\n' |
201 | | - ); |
202 | | - } |
203 | | - this._historyPrev = Interface.prototype._historyPrev; |
204 | | - return this._historyPrev(); |
| 48 | + repl.setupHistory(opts.terminal ? env.NODE_REPL_HISTORY : '', cb); |
205 | 49 | } |
0 commit comments