Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 08e6eee

Browse filesBrowse files
JungMinucjihrig
authored andcommitted
repl,util: insert carriage returns in output
`\n` is not enough for Linux with some custom stream add carriage returns to ensure that the output is displayed correctly using `\r\n` should not be a problem, even on non-Windows platforms. Fixes: #7954 PR-URL: #8028 Reviewed-By: Brian White <mscdex@mscdex.net> Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent 2db26cb commit 08e6eee
Copy full SHA for 08e6eee
Expand file treeCollapse file tree

19 files changed

+201
-191
lines changed
Open diff view settings
Collapse file

‎lib/repl.js‎

Copy file name to clipboardExpand all lines: lib/repl.js
+28-26Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ function REPLServer(prompt,
242242
var err, result, retry = false, input = code, wrappedErr;
243243
// first, create the Script object to check the syntax
244244

245-
if (code === '\n')
245+
if (code === '\n' || code === '\r\n')
246246
return cb(null);
247247

248248
while (true) {
@@ -251,7 +251,7 @@ function REPLServer(prompt,
251251
(self.replMode === exports.REPL_MODE_STRICT || retry)) {
252252
// "void 0" keeps the repl from returning "use strict" as the
253253
// result value for let/const statements.
254-
code = `'use strict'; void 0;\n${code}`;
254+
code = `'use strict'; void 0;\r\n${code}`;
255255
}
256256
var script = vm.createScript(code, {
257257
filename: file,
@@ -265,7 +265,7 @@ function REPLServer(prompt,
265265
if (self.wrappedCmd) {
266266
self.wrappedCmd = false;
267267
// unwrap and try again
268-
code = `${input.substring(1, input.length - 2)}\n`;
268+
code = `${input.substring(1, input.length - 2)}\r\n`;
269269
wrappedErr = e;
270270
} else {
271271
retry = true;
@@ -367,7 +367,7 @@ function REPLServer(prompt,
367367
e.stack = e.stack.replace(/(\s+at\s+repl:)(\d+)/,
368368
(_, pre, line) => pre + (line - 1));
369369
}
370-
top.outputStream.write((e.stack || e) + '\n');
370+
top.outputStream.write((e.stack || e) + '\r\n');
371371
top.lineParser.reset();
372372
top.bufferedCommand = '';
373373
top.lines.level = [];
@@ -453,7 +453,7 @@ function REPLServer(prompt,
453453
sawSIGINT = false;
454454
return;
455455
}
456-
self.output.write('(To exit, press ^C again or type .exit)\n');
456+
self.output.write('(To exit, press ^C again or type .exit)\r\n');
457457
sawSIGINT = true;
458458
} else {
459459
sawSIGINT = false;
@@ -470,7 +470,7 @@ function REPLServer(prompt,
470470
sawSIGINT = false;
471471

472472
if (self.editorMode) {
473-
self.bufferedCommand += cmd + '\n';
473+
self.bufferedCommand += cmd + '\r\n';
474474
return;
475475
}
476476

@@ -490,7 +490,7 @@ function REPLServer(prompt,
490490
if (self.parseREPLKeyword(keyword, rest) === true) {
491491
return;
492492
} else if (!self.bufferedCommand) {
493-
self.outputStream.write('Invalid REPL keyword\n');
493+
self.outputStream.write('Invalid REPL keyword\r\n');
494494
finish(null);
495495
return;
496496
}
@@ -509,8 +509,8 @@ function REPLServer(prompt,
509509
self.wrappedCmd = false;
510510
if (e && !self.bufferedCommand && cmd.trim().startsWith('npm ')) {
511511
self.outputStream.write('npm should be run outside of the ' +
512-
'node repl, in your normal shell.\n' +
513-
'(Press Control-D to exit.)\n');
512+
'node repl, in your normal shell.\r\n' +
513+
'(Press Control-D to exit.)\r\n');
514514
self.lineParser.reset();
515515
self.bufferedCommand = '';
516516
self.displayPrompt();
@@ -525,7 +525,7 @@ function REPLServer(prompt,
525525
// {
526526
// ... x: 1
527527
// ... }
528-
self.bufferedCommand += cmd + '\n';
528+
self.bufferedCommand += cmd + '\r\n';
529529
self.displayPrompt();
530530
return;
531531
} else {
@@ -548,7 +548,7 @@ function REPLServer(prompt,
548548
if (!self.underscoreAssigned) {
549549
self.last = ret;
550550
}
551-
self.outputStream.write(self.writer(ret) + '\n');
551+
self.outputStream.write(self.writer(ret) + '\r\n');
552552
}
553553

554554
// Display prompt again
@@ -578,10 +578,10 @@ function REPLServer(prompt,
578578

579579
self.on('SIGCONT', function() {
580580
if (self.editorMode) {
581-
self.outputStream.write(`${self._initialPrompt}.editor\n`);
581+
self.outputStream.write(`${self._initialPrompt}.editor\r\n`);
582582
self.outputStream.write(
583-
'// Entering editor mode (^D to finish, ^C to cancel)\n');
584-
self.outputStream.write(`${self.bufferedCommand}\n`);
583+
'// Entering editor mode (^D to finish, ^C to cancel)\r\n');
584+
self.outputStream.write(`${self.bufferedCommand}\r\n`);
585585
self.prompt(true);
586586
} else {
587587
self.displayPrompt(true);
@@ -713,7 +713,7 @@ REPLServer.prototype.createContext = function() {
713713
this.last = value;
714714
if (!this.underscoreAssigned) {
715715
this.underscoreAssigned = true;
716-
this.outputStream.write('Expression assignment to _ now disabled.\n');
716+
this.outputStream.write('Expression assignment to _ now disabled.\r\n');
717717
}
718718
}
719719
});
@@ -762,7 +762,7 @@ function ArrayStream() {
762762
this.run = function(data) {
763763
var self = this;
764764
data.forEach(function(line) {
765-
self.emit('data', line + '\n');
765+
self.emit('data', line + '\r\n');
766766
});
767767
};
768768
}
@@ -1232,7 +1232,7 @@ function defineDefaultCommands(repl) {
12321232
this.lineParser.reset();
12331233
this.bufferedCommand = '';
12341234
if (!this.useGlobal) {
1235-
this.outputStream.write('Clearing context...\n');
1235+
this.outputStream.write('Clearing context...\r\n');
12361236
this.resetContext();
12371237
}
12381238
this.displayPrompt();
@@ -1252,7 +1252,7 @@ function defineDefaultCommands(repl) {
12521252
var self = this;
12531253
Object.keys(this.commands).sort().forEach(function(name) {
12541254
var cmd = self.commands[name];
1255-
self.outputStream.write(name + '\t' + (cmd.help || '') + '\n');
1255+
self.outputStream.write(name + '\t' + (cmd.help || '') + '\r\n');
12561256
});
12571257
this.displayPrompt();
12581258
}
@@ -1262,10 +1262,10 @@ function defineDefaultCommands(repl) {
12621262
help: 'Save all evaluated commands in this REPL session to a file',
12631263
action: function(file) {
12641264
try {
1265-
fs.writeFileSync(file, this.lines.join('\n') + '\n');
1266-
this.outputStream.write('Session saved to:' + file + '\n');
1265+
fs.writeFileSync(file, this.lines.join('\r\n') + '\r\n');
1266+
this.outputStream.write('Session saved to:' + file + '\r\n');
12671267
} catch (e) {
1268-
this.outputStream.write('Failed to save:' + file + '\n');
1268+
this.outputStream.write('Failed to save:' + file + '\r\n');
12691269
}
12701270
this.displayPrompt();
12711271
}
@@ -1279,19 +1279,21 @@ function defineDefaultCommands(repl) {
12791279
if (stats && stats.isFile()) {
12801280
var self = this;
12811281
var data = fs.readFileSync(file, 'utf8');
1282-
var lines = data.split('\n');
1282+
// \r\n, \n, or \r followed by something other than \n
1283+
const lineEnding = /\r?\n|\r(?!\n)/;
1284+
var lines = data.split(lineEnding);
12831285
this.displayPrompt();
12841286
lines.forEach(function(line) {
12851287
if (line) {
1286-
self.write(line + '\n');
1288+
self.write(line + '\r\n');
12871289
}
12881290
});
12891291
} else {
12901292
this.outputStream.write('Failed to load:' + file +
1291-
' is not a valid file\n');
1293+
' is not a valid file\r\n');
12921294
}
12931295
} catch (e) {
1294-
this.outputStream.write('Failed to load:' + file + '\n');
1296+
this.outputStream.write('Failed to load:' + file + '\r\n');
12951297
}
12961298
this.displayPrompt();
12971299
}
@@ -1304,7 +1306,7 @@ function defineDefaultCommands(repl) {
13041306
this.editorMode = true;
13051307
REPLServer.super_.prototype.setPrompt.call(this, '');
13061308
this.outputStream.write(
1307-
'// Entering editor mode (^D to finish, ^C to cancel)\n');
1309+
'// Entering editor mode (^D to finish, ^C to cancel)\r\n');
13081310
}
13091311
});
13101312
}
Collapse file

‎lib/util.js‎

Copy file name to clipboardExpand all lines: lib/util.js
+5-5Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -836,9 +836,9 @@ function reduceToSingleString(output, base, braces, breakLength) {
836836
// If the opening "brace" is too large, like in the case of "Set {",
837837
// we need to force the first item to be on the next line or the
838838
// items will not line up correctly.
839-
(base === '' && braces[0].length === 1 ? '' : base + '\n ') +
839+
(base === '' && braces[0].length === 1 ? '' : base + '\r\n ') +
840840
' ' +
841-
output.join(',\n ') +
841+
output.join(',\r\n ') +
842842
' ' +
843843
braces[1];
844844
}
@@ -1001,19 +1001,19 @@ exports.print = internalUtil.deprecate(function() {
10011001

10021002
exports.puts = internalUtil.deprecate(function() {
10031003
for (var i = 0, len = arguments.length; i < len; ++i) {
1004-
process.stdout.write(arguments[i] + '\n');
1004+
process.stdout.write(arguments[i] + '\r\n');
10051005
}
10061006
}, 'util.puts is deprecated. Use console.log instead.');
10071007

10081008

10091009
exports.debug = internalUtil.deprecate(function(x) {
1010-
process.stderr.write('DEBUG: ' + x + '\n');
1010+
process.stderr.write('DEBUG: ' + x + '\r\n');
10111011
}, 'util.debug is deprecated. Use console.error instead.');
10121012

10131013

10141014
exports.error = internalUtil.deprecate(function(x) {
10151015
for (var i = 0, len = arguments.length; i < len; ++i) {
1016-
process.stderr.write(arguments[i] + '\n');
1016+
process.stderr.write(arguments[i] + '\r\n');
10171017
}
10181018
}, 'util.error is deprecated. Use console.error instead.');
10191019

Collapse file

‎test/parallel/test-preload.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-preload.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ const interactive = childProcess.exec(nodeBinary + ' '
123123
+ '-i',
124124
common.mustCall(function(err, stdout, stderr) {
125125
assert.ifError(err);
126-
assert.strictEqual(stdout, `> 'test'\n> `);
126+
assert.strictEqual(stdout, `> 'test'\r\n> `);
127127
}));
128128

129129
interactive.stdin.write('a\n');
Collapse file

‎test/parallel/test-repl-.save.load.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-repl-.save.load.js
+5-4Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ putIn.run(testFile);
2727
putIn.run(['.save ' + saveFileName]);
2828

2929
// the file should have what I wrote
30-
assert.equal(fs.readFileSync(saveFileName, 'utf8'), testFile.join('\n') + '\n');
30+
assert.equal(fs.readFileSync(saveFileName, 'utf8'), testFile.join('\r\n')
31+
+ '\r\n');
3132

3233
// make sure that the REPL data is "correct"
3334
// so when I load it back I know I'm good
@@ -54,7 +55,7 @@ var loadFile = join(common.tmpDir, 'file.does.not.exist');
5455
// should not break
5556
putIn.write = function(data) {
5657
// make sure I get a failed to load message and not some crazy error
57-
assert.equal(data, 'Failed to load:' + loadFile + '\n');
58+
assert.equal(data, 'Failed to load:' + loadFile + '\r\n');
5859
// eat me to avoid work
5960
putIn.write = function() {};
6061
};
@@ -63,7 +64,7 @@ putIn.run(['.load ' + loadFile]);
6364
// throw error on loading directory
6465
loadFile = common.tmpDir;
6566
putIn.write = function(data) {
66-
assert.equal(data, 'Failed to load:' + loadFile + ' is not a valid file\n');
67+
assert.equal(data, 'Failed to load:' + loadFile + ' is not a valid file\r\n');
6768
putIn.write = function() {};
6869
};
6970
putIn.run(['.load ' + loadFile]);
@@ -78,7 +79,7 @@ const invalidFileName = join(common.tmpDir, '\0\0\0\0\0');
7879
// should not break
7980
putIn.write = function(data) {
8081
// make sure I get a failed to save message and not some other error
81-
assert.equal(data, 'Failed to save:' + invalidFileName + '\n');
82+
assert.equal(data, 'Failed to save:' + invalidFileName + '\r\n');
8283
// reset to no-op
8384
putIn.write = function() {};
8485
};
Collapse file

‎test/parallel/test-repl-autolibs.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-repl-autolibs.js
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function test1() {
1919
if (data.length) {
2020

2121
// inspect output matches repl output
22-
assert.equal(data, util.inspect(require('fs'), null, 2, false) + '\n');
22+
assert.equal(data, util.inspect(require('fs'), null, 2, false) + '\r\n');
2323
// globally added lib matches required lib
2424
assert.equal(global.fs, require('fs'));
2525
test2();
@@ -36,7 +36,7 @@ function test2() {
3636
gotWrite = true;
3737
if (data.length) {
3838
// repl response error message
39-
assert.equal(data, '{}\n');
39+
assert.equal(data, '{}\r\n');
4040
// original value wasn't overwritten
4141
assert.equal(val, global.url);
4242
}
Collapse file

‎test/parallel/test-repl-definecommand.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-repl-definecommand.js
+5-5Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ r.defineCommand('say2', function() {
3434
this.displayPrompt();
3535
});
3636

37-
inputStream.write('.help\n');
38-
assert(/\nsay1\thelp for say1\n/.test(output), 'help for say1 not present');
39-
assert(/\nsay2\t\n/.test(output), 'help for say2 not present');
40-
inputStream.write('.say1 node developer\n');
37+
inputStream.write('.help\r\n');
38+
assert(/\r\nsay1\thelp for say1\r\n/.test(output), 'help for say1 not present');
39+
assert(/\r\nsay2\t\r\n/.test(output), 'help for say2 not present');
40+
inputStream.write('.say1 node developer\r\n');
4141
assert(/> hello node developer/.test(output), 'say1 outputted incorrectly');
42-
inputStream.write('.say2 node developer\n');
42+
inputStream.write('.say2 node developer\r\n');
4343
assert(/> hello from say2/.test(output), 'say2 outputted incorrectly');
Collapse file

‎test/parallel/test-repl-mode.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-repl-mode.js
+11-11Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,45 +21,45 @@ function testSloppyMode() {
2121

2222
cli.input.emit('data', `
2323
x = 3
24-
`.trim() + '\n');
25-
assert.equal(cli.output.accumulator.join(''), '> 3\n> ');
24+
`.trim() + '\r\n');
25+
assert.equal(cli.output.accumulator.join(''), '> 3\r\n> ');
2626
cli.output.accumulator.length = 0;
2727

2828
cli.input.emit('data', `
2929
let y = 3
30-
`.trim() + '\n');
31-
assert.equal(cli.output.accumulator.join(''), 'undefined\n> ');
30+
`.trim() + '\r\n');
31+
assert.equal(cli.output.accumulator.join(''), 'undefined\r\n> ');
3232
}
3333

3434
function testStrictMode() {
3535
var cli = initRepl(repl.REPL_MODE_STRICT);
3636

3737
cli.input.emit('data', `
3838
x = 3
39-
`.trim() + '\n');
39+
`.trim() + '\r\n');
4040
assert.ok(/ReferenceError: x is not defined/.test(
4141
cli.output.accumulator.join('')));
4242
cli.output.accumulator.length = 0;
4343

4444
cli.input.emit('data', `
4545
let y = 3
46-
`.trim() + '\n');
47-
assert.equal(cli.output.accumulator.join(''), 'undefined\n> ');
46+
`.trim() + '\r\n');
47+
assert.equal(cli.output.accumulator.join(''), 'undefined\r\n> ');
4848
}
4949

5050
function testAutoMode() {
5151
var cli = initRepl(repl.REPL_MODE_MAGIC);
5252

5353
cli.input.emit('data', `
5454
x = 3
55-
`.trim() + '\n');
56-
assert.equal(cli.output.accumulator.join(''), '> 3\n> ');
55+
`.trim() + '\r\n');
56+
assert.equal(cli.output.accumulator.join(''), '> 3\r\n> ');
5757
cli.output.accumulator.length = 0;
5858

5959
cli.input.emit('data', `
6060
let y = 3
61-
`.trim() + '\n');
62-
assert.equal(cli.output.accumulator.join(''), 'undefined\n> ');
61+
`.trim() + '\r\n');
62+
assert.equal(cli.output.accumulator.join(''), 'undefined\r\n> ');
6363
}
6464

6565
function initRepl(mode) {
Collapse file

‎test/parallel/test-repl-persistent-history.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-repl-persistent-history.js
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class ActionStream extends stream.Stream {
3737
if (typeof action === 'object') {
3838
self.emit('keypress', '', action);
3939
} else {
40-
self.emit('data', action + '\n');
40+
self.emit('data', action + '\r\n');
4141
}
4242
setImmediate(doAction);
4343
}
@@ -138,7 +138,7 @@ const tests = [
138138
env: { NODE_REPL_HISTORY_FILE: oldHistoryPath },
139139
test: [UP, CLEAR, '\'42\'', ENTER],
140140
expected: [prompt, convertMsg, prompt, prompt + '\'=^.^=\'', prompt, '\'',
141-
'4', '2', '\'', '\'42\'\n', prompt, prompt],
141+
'4', '2', '\'', '\'42\'\r\n', prompt, prompt],
142142
after: function ensureHistoryFixture() {
143143
// XXX(Fishrock123) Make sure nothing weird happened to our fixture
144144
// or it's temporary copy.
@@ -154,7 +154,7 @@ const tests = [
154154
{ // Requires the above testcase
155155
env: {},
156156
test: [UP, UP, ENTER],
157-
expected: [prompt, prompt + '\'42\'', prompt + '\'=^.^=\'', '\'=^.^=\'\n',
157+
expected: [prompt, prompt + '\'42\'', prompt + '\'=^.^=\'', '\'=^.^=\'\r\n',
158158
prompt]
159159
},
160160
{

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.