Menu

#2511 Some doubtful use of `LineLayout::maxLineLength`

Bug
open
5
9 hours ago
2026-06-05
Zufu Liu
No

The last character, style and position for LineLayout is at numCharsInLine index, for lineLength = model.pdoc->LineStart(lineNumber + 1) - model.pdoc->LineStart(lineNumber), maxLineLength >= lineLength >= numCharsInLine >= numCharsBeforeEOL.

maxLineLength is growth only (by LineLayout::Resize() method), it's tight to capacity for chars, styles and positions, so it may extremely larger than lineLength (line length with EOL), some code seems to treat it as lineLength.

  1. Inside EditView::StartEndDisplayLine(), the check if (posInLine <= ll->maxLineLength) can (?) be changed into osInLine <= ll->numCharsInLine.

  2. Inside LineLayout::PointFromPosition():

// In case of very long line put x at arbitrary large position
if (posInLine > maxLineLength) {
    pt.x = positions[maxLineLength] - positions[LineStart(lines)];
}

when posInLine > numCharsInLine, the result will be negative (positions beyond numCharsInLine are cleared and never write into), the code can be changed to use numCharsInLine:

// In case of very long line put x at arbitrary large position
if (posInLine > numCharsInLine) {
    pt.x = positions[numCharsInLine] - positions[LineStart(lines)];
}
  1. Inside LineLayout::ClearPositions(), change maxLineLength to numCharsInLine could speedup word wrap on slow system, note that chars and styles beyond numCharsInLine are not cleared.

LineLayoutCache::Retrieve() can be changed to use ReSet() to reset the layout:

if (cache[pos] && !cache[pos]->CanHold(lineNumber, maxChars)) {
    //cache[pos].reset();
    cache[pos].ReSet(lineNumber, maxChars);
}

Discussion

  • Zufu Liu

    Zufu Liu - 2026-06-05

    I'm find these when try to align up maxLineLength to reduce resizing (similar to LineLayoutCache), and check whether it will makes word wrap faster ([feature-requests:#1481]), the gain is tiny (line wraps in random order and resizing count is small).

     

    Related

    Feature Requests: #1481

  • Neil Hodgson

    Neil Hodgson - 1 day ago

    (Edit: Posting this renumbered all the items, so the pieces here match the above in order (2,1,3,4). )

    1. "// In case of very long line". The comment doesn't really match the code. Its like that because LineLayout::maxLineLength used to be a hard coded constant =4000. Longer lines were just truncated.

    Bounding to numCharsInLine seems OK.

    1. No side effect (change to posRet can occur unless posInLine <= ll->numCharsBeforeEOL (3rd clause of if) so the change appears OK. Drop the redundant clause too.

    2. "ClearPositions(), change maxLineLength to numCharsInLine". Leaving dead values is less stable than clearing to 0 and could lead to more subtle bugs that are dependent on history.

    3. "Retrieve() can be changed to use ReSet()". That appears to save a LineLayout allocation so might be worthwhile.

     

    Last edit: Neil Hodgson 1 day ago
  • Zufu Liu

    Zufu Liu - 23 hours ago

    Bounding to nnumCharsInLine seems OK.

    will 1 be added like LineLayout::XInLine() ?

    XYPOSITION LineLayout::XInLine(Sci::Position index) const noexcept {
        // For positions inside line return value from positions
        // For positions after line return last position + 1.0
        if (index <= numCharsInLine) {
            return positions[index];
        }
        return positions[numCharsInLine] + 1.0;
    }
    

    "Retrieve() can be changed to use ReSet()". That appears to save a LineLayout allocation so might be worthwhile.

    EditView::FormatRange() can move LineLayout ll out from the loop, and reset it in the loop.

     
  • Neil Hodgson

    Neil Hodgson - 9 hours ago

    The +1 is about drawing some indicators more visibly and is only ever called from DrawIndicator.

    EditView::FormatRange() ... ll out from the loop

    It is cleaner to minimize the lifetime of variables and its unlikely avoiding some allocations will be significant here.

     

Log in to post a comment.

Auth0 Logo