Skip to content

Commit b63e4de

Browse files
authored
Fix rawLine: and offsetOfRawLine: ignoring bufferStartOffset after line drops (#589)
Both methods hardcoded linenum == 0 → start = 0 instead of checking linenum == _firstEntry → start = bufferStartOffset. After dropLines advances _firstEntry and sets bufferStartOffset to a non-zero value, they returned a pointer/offset that started too early in the buffer, reading dropped data and missing the tail of live data. The fix mirrors the existing correct logic in _lineRawOffset: and lengthOfRawLine:. Co-authored-by: chall37 <chall37@users.noreply.github.com>
1 parent 8be41ad commit b63e4de

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

ModernTests/LineBlockTests.swift

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,53 @@ class LineBlockTests: XCTestCase {
966966
"rawLine(2) should return the third appended string")
967967
}
968968

969+
func testRawLineAndOffsetAfterPartialDrop() {
970+
// Regression test: rawLine: and offsetOfRawLine: must use _firstEntry/bufferStartOffset,
971+
// not hardcode linenum==0 → start=0.
972+
//
973+
// Setup: 3 raw lines appended at width 80, then drop 4 wrapped lines at width 3.
974+
// This advances _firstEntry to 2 and sets bufferStartOffset to 9,
975+
// which differs from cumulative_line_lengths[1] = 6.
976+
// The buggy code would return 6 (CLL boundary) instead of 9 (actual start).
977+
978+
let block = LineBlock(rawBufferSize: 100, absoluteBlockNumber: 1)
979+
let appendWidth: Int32 = 80
980+
981+
// Append three raw lines: "AB" (2), "CDEF" (4), "GHIJKLMN" (8)
982+
// cumulative_line_lengths will be [2, 6, 14]
983+
XCTAssertTrue(block.appendLineString(makeLineString("AB", eol: EOL_HARD), width: appendWidth))
984+
XCTAssertTrue(block.appendLineString(makeLineString("CDEF", eol: EOL_HARD), width: appendWidth))
985+
XCTAssertTrue(block.appendLineString(makeLineString("GHIJKLMN", eol: EOL_HARD), width: appendWidth))
986+
987+
// Drop 4 wrapped lines at width 3:
988+
// Raw 0 ("AB", len 2): spans=0 → 1 wrapped line consumed, n: 4→3
989+
// Raw 1 ("CDEF", len 4): spans=1 → 2 wrapped lines consumed, n: 3→1
990+
// Raw 2 ("GHIJKLMN", len 8): spans=2, n=1 ≤ 2 → partial drop of 3 chars.
991+
// bufferStartOffset = 6 + 3 = 9, _firstEntry = 2
992+
var charsDropped: Int32 = 0
993+
let dropped = block.dropLines(4, withWidth: 3, chars: &charsDropped)
994+
XCTAssertEqual(dropped, 4, "Should drop exactly 4 wrapped lines")
995+
996+
// Verify post-drop state
997+
XCTAssertEqual(block.firstEntry, 2,
998+
"firstEntry should be 2 after consuming raw lines 0 and 1")
999+
XCTAssertEqual(block.startOffset(), 9,
1000+
"bufferStartOffset should be 9 (CLL[1]=6 + 3 partial), not 6 or 0")
1001+
1002+
// offsetOfRawLine: must return bufferStartOffset for _firstEntry
1003+
XCTAssertEqual(block.offset(ofRawLine: 2), 9,
1004+
"offsetOfRawLine(2) should return bufferStartOffset=9, not CLL[1]=6")
1005+
1006+
// lengthOfRawLine: is already correct (uses _firstEntry) — sanity check
1007+
XCTAssertEqual(block.length(ofRawLine: 2), 5,
1008+
"Remaining portion of raw line 2 should be 5 chars (14 - 9)")
1009+
1010+
// rawLine:/screenCharArrayForRawLine: must return content starting at bufferStartOffset
1011+
let remaining = block.screenCharArray(forRawLine: 2)
1012+
XCTAssertEqual(remaining.stringValue, "JKLMN",
1013+
"rawLine(2) should return the 5 surviving chars, not start 3 chars too early")
1014+
}
1015+
9691016
// MARK: - Serialization
9701017

9711018
func testDictionaryRoundTripPreservesContents() {

sources/LineBlock.mm

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1749,8 +1749,8 @@ - (int)lengthOfRawLine:(int)linenum {
17491749
}
17501750

17511751
- (int)offsetOfRawLine:(int)linenum {
1752-
if (linenum == 0) {
1753-
return 0;
1752+
if (linenum == _firstEntry) {
1753+
return self.bufferStartOffset;
17541754
} else {
17551755
return cumulative_line_lengths[linenum - 1];
17561756
}
@@ -1766,8 +1766,8 @@ - (ScreenCharArray *)screenCharArrayForRawLine:(int)linenum {
17661766

17671767
- (const screen_char_t*)rawLine:(int)linenum {
17681768
int start;
1769-
if (linenum == 0) {
1770-
start = 0;
1769+
if (linenum == _firstEntry) {
1770+
start = self.bufferStartOffset;
17711771
} else {
17721772
start = cumulative_line_lengths[linenum - 1];
17731773
}

0 commit comments

Comments
 (0)