private void refreshStateOnEndOffsetDecrease(CharSequence oldText, int newEndOffset, int oldEndOffset, int tabSize) {
    assert newEndOffset < oldEndOffset;
    int lineFeedsNumberAtRemovedText = 0;
    int spacesNumberAtRemovedText = 0;
    int indentSpacesNumberAtRemovedText = 0;
    int column = mySpaces + myIndentSpaces;
    for (int i = oldEndOffset - 1; i >= newEndOffset; i--) {
      switch (oldText.charAt(i)) {
        case LINE_FEED -> {
          ++lineFeedsNumberAtRemovedText;
          column = 0;
        }
        case ' ' -> {
          ++spacesNumberAtRemovedText;
          column--;
        }
        case '\t' -> {
          int change = column % tabSize;
          if (change == 0) {
            change = tabSize;
          }
          indentSpacesNumberAtRemovedText += change;
          column -= change;
        }
      }
    }

    // There are no line feeds at remained text, hence, we can just subtract number of spaces and indent spaces
    // from removed text and finish.
    if (getLineFeeds() - lineFeedsNumberAtRemovedText <= 0) {
      setLineFeeds(0);
      mySpaces -= spacesNumberAtRemovedText;
      myIndentSpaces -= indentSpacesNumberAtRemovedText;
      return;
    }

    // There are white spaces at remained text, hence, we need to calculate number of spaces and indent spaces between
    // last line feed and new end offset.
    int newLineFeedsNumber = getLineFeeds() - lineFeedsNumberAtRemovedText;
    assert newLineFeedsNumber >= 0;
    newLineFeedsNumber = Math.max(newLineFeedsNumber, 0); // Never expect the defense to be triggered.
    setLineFeeds(newLineFeedsNumber);
    int startOffset = CharArrayUtil.shiftForwardUntil(oldText, newEndOffset - 1, "\n") + 1;
    WhiteSpaceInfo info = parse(oldText, startOffset, newEndOffset, 0, tabSize);
    mySpaces = info.spaces;
    myIndentSpaces = info.indentSpaces;
  }
private void refreshStateOnEndOffsetDecrease(CharSequence oldText, int newEndOffset, int oldEndOffset, int tabSize)