public static @NotNull Pair<@NotNull Interval, @Nullable Interval> logicalLineToYRange(@NotNull Editor editor, int logicalLine) {
    if (logicalLine < 0) throw new IllegalArgumentException("Logical line is negative: " + logicalLine);
    return ReadAction.compute(() -> {
      Document document = editor.getDocument();
      int startVisualLine;
      int endVisualLine;
      boolean topOverlapped;
      boolean bottomOverlapped;
      if (logicalLine >= document.getLineCount()) {
        startVisualLine = endVisualLine = logicalToVisualLine(editor, logicalLine);
        topOverlapped = bottomOverlapped = false;
      }
      else {
        int lineStartOffset = document.getLineStartOffset(logicalLine);
        int lineEndOffset = document.getLineEndOffset(logicalLine);
        FoldRegion foldRegion = editor.getFoldingModel().getCollapsedRegionAtOffset(lineStartOffset);
        if (foldRegion instanceof CustomFoldRegion) {
          int startY = editor.visualLineToY(editor.offsetToVisualLine(foldRegion.getStartOffset(), false));
          Interval interval = new TextRangeInterval(startY, startY + ((CustomFoldRegion)foldRegion).getHeightInPixels());
          return Pair.create(interval, foldRegion.getStartOffset() == document.getLineStartOffset(logicalLine) &&
                                       foldRegion.getEndOffset() == document.getLineEndOffset(logicalLine) ? interval : null);
        }
        startVisualLine = editor.offsetToVisualLine(lineStartOffset, false);
        endVisualLine = startVisualLine + editor.getSoftWrapModel().getSoftWrapsForRange(lineStartOffset + 1, lineEndOffset - 1).size();
        topOverlapped = editor.getFoldingModel().isOffsetCollapsed(lineStartOffset - 1);
        bottomOverlapped = logicalLine + 1 < document.getLineCount() &&
                           editor.getFoldingModel().isOffsetCollapsed(document.getLineStartOffset(logicalLine + 1) - 1);
      }
      int lineHeight = editor.getLineHeight();
      int startY = editor.visualLineToY(startVisualLine);
      int endY = (endVisualLine == startVisualLine ? startY : editor.visualLineToY(endVisualLine)) + lineHeight;
      int startYEx = topOverlapped ? startY + lineHeight : startY;
      int endYEx = bottomOverlapped ? endY - lineHeight : endY;
      return Pair.create(new TextRangeInterval(startY, endY), startYEx < endYEx ? new TextRangeInterval(startYEx, endYEx) : null);
    });
  }
public static @NotNull Pair<@NotNull Interval, @Nullable Interval> logicalLineToYRange(@NotNull Editor editor, int logicalLine)