resize method

void resize(
  1. int oldWidth,
  2. int oldHeight,
  3. int newWidth,
  4. int newHeight,
)

Implementation

void resize(int oldWidth, int oldHeight, int newWidth, int newHeight) {
  if (newHeight > lines.maxLength) {
    lines.maxLength = newHeight;
  }

  // 1. Adjust the height.
  if (newHeight > oldHeight) {
    // Grow larger
    for (var i = 0; i < newHeight - oldHeight; i++) {
      if (newHeight > lines.length) {
        lines.push(_newEmptyLine(newWidth));
      } else {
        _cursorY++;
        _savedCursorY++;
      }
    }
  } else {
    // Shrink smaller
    for (var i = 0; i < oldHeight - newHeight; i++) {
      if (_cursorY > newHeight - 1) {
        _cursorY--;
      } else {
        lines.pop();
      }
    }
  }

  // Ensure cursor row is within the screen. The column is clamped after
  // width handling so reflow can preserve its logical offset.
  _cursorY = _cursorY.clamp(0, newHeight - 1);
  _savedCursorY = _savedCursorY.clamp(0, newHeight - 1);

  // 2. Adjust the width.
  if (newWidth != oldWidth) {
    if (terminal.reflowEnabled && !isAltBuffer) {
      final cursorScrollBack = max(lines.length - newHeight, 0);
      final cursorLine = _cursorY + cursorScrollBack;
      final cursorPendingWrap = _cursorX >= _rightLimit;
      final cursorAnchorX = switch (cursorPendingWrap) {
        true => max(0, _cursorX - 1),
        false => _cursorX,
      };
      final cursorAnchor = lines[cursorLine].createAnchor(cursorAnchorX);
      final savedCursorLine = _savedCursorY + cursorScrollBack;
      final savedCursorAnchorX = switch (_savedPendingWrap) {
        true => max(0, _savedCursorX - 1),
        false => _savedCursorX,
      };
      final savedCursorAnchor =
          lines[savedCursorLine].createAnchor(savedCursorAnchorX);
      final reflowResult = reflow(lines, oldWidth, newWidth);

      while (reflowResult.length < newHeight) {
        reflowResult.add(_newEmptyLine(newWidth));
      }

      lines.replaceWith(reflowResult);
      if (cursorAnchor.attached) {
        final newScrollBack = max(lines.length - newHeight, 0);
        _cursorX = _reflowedCursorX(
          cursorAnchor,
          pendingWrap: cursorPendingWrap,
          newWidth: newWidth,
        );
        _cursorY = (cursorAnchor.y - newScrollBack).clamp(0, newHeight - 1);
      }
      if (savedCursorAnchor.attached) {
        final newScrollBack = max(lines.length - newHeight, 0);
        final savedCursorAtRightEdge = savedCursorAnchor.x == newWidth - 1;
        _savedCursorX = _reflowedCursorX(
          savedCursorAnchor,
          pendingWrap: _savedPendingWrap,
          newWidth: newWidth,
        );
        _savedCursorY =
            (savedCursorAnchor.y - newScrollBack).clamp(0, newHeight - 1);
        _savedPendingWrap = _savedPendingWrap && savedCursorAtRightEdge;
      } else {
        _savedCursorX = _savedCursorX.clamp(0, newWidth - 1);
        _savedPendingWrap = false;
      }
      cursorAnchor.dispose();
      savedCursorAnchor.dispose();
    } else {
      lines.forEach((item) {
        // BufferLine.resize intentionally preserves cell data beyond the
        // new length so it can reappear if the line is grown back later
        // (see the "preserves hidden cells" resize tests) - it does not
        // enforce the width-2/placeholder pairing invariant. If this line
        // was shrunk smaller than newWidth in the past and is now being
        // grown, the newly exposed last cell may be a stale wide-char
        // lead with no room left for its placeholder, so clear it (same
        // guard applied by reflow() for the reflow-enabled path).
        item.resize(newWidth);
        if (newWidth > 0 && item.getWidth(newWidth - 1) == 2) {
          item.resetCell(newWidth - 1);
        }
      });
      _cursorX = _cursorX.clamp(0, newWidth - 1);
      _savedCursorX = _savedCursorX.clamp(0, newWidth - 1);
      _savedPendingWrap = false;
    }
  }

  _cursorX = _cursorX.clamp(0, newWidth);
  _marginLeft = 0;
  _marginRight = newWidth - 1;
}