private boolean isInsideSoftWrap(@NotNull VisualPosition visual, boolean countBeforeSoftWrap) {
    if (!isSoftWrappingEnabled()) {
      return false;
    }
    SoftWrapModel model = myEditor.getSoftWrapModel();
    if (!model.isSoftWrappingEnabled()) {
      return false;
    }
    LogicalPosition logical = myEditor.visualToLogicalPosition(visual);
    int offset = myEditor.logicalPositionToOffset(logical);
    if (offset <= 0) {
      // Never expect to be here, just a defensive programming.
      return false;
    }

    SoftWrap softWrap = model.getSoftWrap(offset);
    if (softWrap == null) {
      return false;
    }

    // We consider visual positions that point after the last symbol before soft wrap and the first
    // symbol after soft wrap to not
    // belong to soft wrap-introduced virtual space.
    VisualPosition visualAfterSoftWrap = myEditor.offsetToVisualPosition(offset);
    if (visualAfterSoftWrap.line == visual.line && visualAfterSoftWrap.column <= visual.column) {
      return false;
    }

    if (myEditor.myUseNewRendering) {
      VisualPosition beforeSoftWrap = myEditor.offsetToVisualPosition(offset, true, true);
      return visual.line > beforeSoftWrap.line
          || visual.column > beforeSoftWrap.column
          || visual.column == beforeSoftWrap.column && countBeforeSoftWrap;
    } else {
      VisualPosition visualBeforeSoftWrap = myEditor.offsetToVisualPosition(offset - 1);
      int x = 0;
      LogicalPosition logLineStart =
          myEditor.visualToLogicalPosition(new VisualPosition(visualBeforeSoftWrap.line, 0));
      if (logLineStart.softWrapLinesOnCurrentLogicalLine > 0) {
        int offsetLineStart = myEditor.logicalPositionToOffset(logLineStart);
        softWrap = model.getSoftWrap(offsetLineStart);
        if (softWrap != null) {
          x = softWrap.getIndentInPixels();
        }
      }
      int width =
          EditorUtil.textWidthInColumns(
              myEditor, myEditor.getDocument().getCharsSequence(), offset - 1, offset, x);
      int softWrapStartColumn = visualBeforeSoftWrap.column + width;
      if (visual.line > visualBeforeSoftWrap.line) {
        return true;
      }
      return countBeforeSoftWrap
          ? visual.column >= softWrapStartColumn
          : visual.column > softWrapStartColumn;
    }
  }
 /** @return total number of soft wrap-introduced new visual lines */
 public int getSoftWrapsIntroducedLinesNumber() {
   if (!isSoftWrappingEnabled()) {
     return 0;
   }
   int result = 0;
   FoldingModel foldingModel = myEditor.getFoldingModel();
   for (SoftWrap softWrap : myStorage.getSoftWraps()) {
     if (!foldingModel.isOffsetCollapsed(softWrap.getStart())) {
       result++; // Assuming that soft wrap has single line feed all the time
     }
   }
   return result;
 }
  @Override
  public void beforeDocumentChangeAtCaret() {
    CaretModel caretModel = myEditor.getCaretModel();
    VisualPosition visualCaretPosition = caretModel.getVisualPosition();
    if (!isInsideSoftWrap(visualCaretPosition)) {
      return;
    }

    SoftWrap softWrap = myStorage.getSoftWrap(caretModel.getOffset());
    if (softWrap == null) {
      return;
    }

    myEditor
        .getDocument()
        .replaceString(softWrap.getStart(), softWrap.getEnd(), softWrap.getText());
    caretModel.moveToVisualPosition(visualCaretPosition);
  }
  @Override
  public boolean isVisible(SoftWrap softWrap) {
    FoldingModel foldingModel = myEditor.getFoldingModel();
    int start = softWrap.getStart();
    if (foldingModel.isOffsetCollapsed(start)) {
      return false;
    }

    // There is a possible case that soft wrap and collapsed folding region share the same offset,
    // i.e. soft wrap is represented
    // before the folding. We need to return 'true' in such situation. Hence, we check if offset
    // just before the soft wrap
    // is collapsed as well.
    return start <= 0 || !foldingModel.isOffsetCollapsed(start - 1);
  }