@@ -22,13 +22,10 @@ const { |
22 | 22 | NumberIsNaN, |
23 | 23 | ObjectSetPrototypeOf, |
24 | 24 | RegExpPrototypeExec, |
25 | | - RegExpPrototypeSymbolReplace, |
26 | | - RegExpPrototypeSymbolSplit, |
27 | 25 | StringPrototypeCodePointAt, |
28 | 26 | StringPrototypeEndsWith, |
29 | 27 | StringPrototypeRepeat, |
30 | 28 | StringPrototypeSlice, |
31 | | - StringPrototypeSplit, |
32 | 29 | StringPrototypeStartsWith, |
33 | 30 | StringPrototypeTrim, |
34 | 31 | Symbol, |
@@ -77,7 +74,7 @@ const kHistorySize = 30; |
77 | 74 | const kMaxUndoRedoStackSize = 2048; |
78 | 75 | const kMincrlfDelay = 100; |
79 | 76 | // \r\n, \n, or \r followed by something other than \n |
80 | | -const lineEnding = /\r?\n|\r(?!\n)/; |
| 77 | +const lineEnding = /\r?\n|\r(?!\n)/g; |
81 | 78 |
|
82 | 79 | const kLineObjectStream = Symbol('line object stream'); |
83 | 80 | const kQuestionCancel = Symbol('kQuestionCancel'); |
@@ -590,31 +587,40 @@ class Interface extends InterfaceConstructor { |
590 | 587 | this[kSawReturnAt] && |
591 | 588 | DateNow() - this[kSawReturnAt] <= this.crlfDelay |
592 | 589 | ) { |
593 | | - string = RegExpPrototypeSymbolReplace(/^\n/, string, ''); |
| 590 | + if (StringPrototypeCodePointAt(string) === 10) string = StringPrototypeSlice(string, 1); |
594 | 591 | this[kSawReturnAt] = 0; |
595 | 592 | } |
596 | 593 |
|
597 | 594 | // Run test() on the new string chunk, not on the entire line buffer. |
598 | | - const newPartContainsEnding = RegExpPrototypeExec(lineEnding, string) !== null; |
599 | | - |
600 | | - if (this[kLine_buffer]) { |
601 | | - string = this[kLine_buffer] + string; |
602 | | - this[kLine_buffer] = null; |
603 | | - } |
604 | | - if (newPartContainsEnding) { |
| 595 | + let newPartContainsEnding = RegExpPrototypeExec(lineEnding, string); |
| 596 | + if (newPartContainsEnding !== null) { |
| 597 | + if (this[kLine_buffer]) { |
| 598 | + string = this[kLine_buffer] + string; |
| 599 | + this[kLine_buffer] = null; |
| 600 | + newPartContainsEnding = RegExpPrototypeExec(lineEnding, string); |
| 601 | + } |
605 | 602 | this[kSawReturnAt] = StringPrototypeEndsWith(string, '\r') ? |
606 | 603 | DateNow() : |
607 | 604 | 0; |
608 | 605 |
|
609 | | - // Got one or more newlines; process into "line" events |
610 | | - const lines = StringPrototypeSplit(string, lineEnding); |
| 606 | + const indexes = [0, newPartContainsEnding.index, lineEnding.lastIndex]; |
| 607 | + let nextMatch; |
| 608 | + while ((nextMatch = RegExpPrototypeExec(lineEnding, string)) !== null) { |
| 609 | + ArrayPrototypePush(indexes, nextMatch.index, lineEnding.lastIndex); |
| 610 | + } |
| 611 | + const lastIndex = indexes.length - 1; |
611 | 612 | // Either '' or (conceivably) the unfinished portion of the next line |
612 | | - string = ArrayPrototypePop(lines); |
613 | | - this[kLine_buffer] = string; |
614 | | - for (let n = 0; n < lines.length; n++) this[kOnLine](lines[n]); |
| 613 | + this[kLine_buffer] = StringPrototypeSlice(string, indexes[lastIndex]); |
| 614 | + for (let i = 1; i < lastIndex; i += 2) { |
| 615 | + this[kOnLine](StringPrototypeSlice(string, indexes[i - 1], indexes[i])); |
| 616 | + } |
615 | 617 | } else if (string) { |
616 | 618 | // No newlines this time, save what we have for next time |
617 | | - this[kLine_buffer] = string; |
| 619 | + if (this[kLine_buffer]) { |
| 620 | + this[kLine_buffer] += string; |
| 621 | + } else { |
| 622 | + this[kLine_buffer] = string; |
| 623 | + } |
618 | 624 | } |
619 | 625 | } |
620 | 626 |
|
@@ -1322,12 +1328,18 @@ class Interface extends InterfaceConstructor { |
1322 | 1328 | // falls through |
1323 | 1329 | default: |
1324 | 1330 | if (typeof s === 'string' && s) { |
1325 | | - const lines = RegExpPrototypeSymbolSplit(/\r\n|\n|\r/, s); |
1326 | | - for (let i = 0, len = lines.length; i < len; i++) { |
1327 | | - if (i > 0) { |
| 1331 | + let nextMatch = RegExpPrototypeExec(lineEnding, s); |
| 1332 | + if (nextMatch !== null) { |
| 1333 | + this[kInsertString](StringPrototypeSlice(s, 0, nextMatch.index)); |
| 1334 | + let { lastIndex } = lineEnding; |
| 1335 | + while ((nextMatch = RegExpPrototypeExec(lineEnding, s)) !== null) { |
1328 | 1336 | this[kLine](); |
| 1337 | + this[kInsertString](StringPrototypeSlice(s, lastIndex, nextMatch.index)); |
| 1338 | + ({ lastIndex } = lineEnding); |
1329 | 1339 | } |
1330 | | - this[kInsertString](lines[i]); |
| 1340 | + if (lastIndex === s.length) this[kLine](); |
| 1341 | + } else { |
| 1342 | + this[kInsertString](s); |
1331 | 1343 | } |
1332 | 1344 | } |
1333 | 1345 | } |
|