Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions lib/internal/readline/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -1322,18 +1322,22 @@ class Interface extends InterfaceConstructor {
// falls through
default:
if (typeof s === 'string' && s) {
// Erase state of previous searches.
lineEnding.lastIndex = 0;
let nextMatch = RegExpPrototypeExec(lineEnding, s);
if (nextMatch !== null) {
this[kInsertString](StringPrototypeSlice(s, 0, nextMatch.index));
let { lastIndex } = lineEnding;
while ((nextMatch = RegExpPrototypeExec(lineEnding, s)) !== null) {
this[kLine]();
// If no line endings are found, just insert the string as is.
if (nextMatch === null) {
this[kInsertString](s);
} else {
// Keep track of the end of the last match.
let lastIndex = 0;
do {
this[kInsertString](StringPrototypeSlice(s, lastIndex, nextMatch.index));
({ lastIndex } = lineEnding);
}
if (lastIndex === s.length) this[kLine]();
} else {
this[kInsertString](s);
this[kLine]();
// Restore lastIndex as the call to kLine could have mutated it.
lineEnding.lastIndex = lastIndex;
} while ((nextMatch = RegExpPrototypeExec(lineEnding, s)) !== null);
}
}
}
Expand Down
33 changes: 33 additions & 0 deletions test/parallel/test-readline-interface-recursive-writes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict';
const common = require('../common');
const ArrayStream = require('../common/arraystream');
const assert = require('assert');

common.skipIfDumbTerminal();

const readline = require('readline');
const rli = new readline.Interface({
terminal: true,
input: new ArrayStream(),
});

let recursionDepth = 0;

// Minimal reproduction for #46731
const testInput = ' \n}\n';
const numberOfExpectedLines = testInput.match(/\n/g).length;

rli.on('line', () => {
// Abort in case of infinite loop
if (recursionDepth > numberOfExpectedLines) {
return;
}
recursionDepth++;
// Write something recursively to readline
rli.write('foo');
});


rli.write(testInput);

assert.strictEqual(recursionDepth, numberOfExpectedLines);