@Override
  public TextRange @Nullable [] pasteTransferable(final @NotNull Editor editor, @NotNull Transferable content) throws TooLargeContentException {
    String text = EditorModificationUtil.getStringContent(content);
    if (text == null) return null;

    int textLength = text.length();
    if (BasePasteHandler.isContentTooLarge(textLength)) throw new TooLargeContentException(textLength);

    CopyPasteOptions copyPasteOptions = CopyPasteOptionsTransferableData.valueFromTransferable(content);
    CopiedFromEmptySelectionPasteMode pasteMode = copyPasteOptions.isCopiedFromEmptySelection()
                                                  ? getCopiedFromEmptySelectionPasteMode() : AT_CARET;

    CaretModel caretModel = editor.getCaretModel();
    if (caretModel.supportsMultipleCarets()) {
      CaretStateTransferableData caretData = null;
      int caretCount = caretModel.getCaretCount();
      if (caretCount == 1 && editor.isColumnMode()) {
        int pastedLineCount = LineTokenizer.calcLineCount(text, true);
        if (pastedLineCount <= caretModel.getMaxCaretCount()) {
          EditorModificationUtilEx.deleteSelectedText(editor);
          Caret caret = caretModel.getPrimaryCaret();
          for (int i = 0; i < pastedLineCount - 1; i++) {
            caret = caret.clone(false);
            if (caret == null) {
              break;
            }
          }
          caretCount = caretModel.getCaretCount();
        }
      }
      else {
        caretData = CaretStateTransferableData.getFrom(content);
      }
      boolean isInsertingEntireLineAboveCaret = pasteMode == ENTIRE_LINE_ABOVE_CARET &&
                                                !editor.getSelectionModel().hasSelection(true);

      final TextRange[] ranges = new TextRange[caretCount];
      final Iterator<String> segments = new ClipboardTextPerCaretSplitter().split(text, caretData, caretCount).iterator();
      final int[] index = {0};
      if (isInsertingEntireLineAboveCaret) {
        caretModel.runBatchCaretOperation(() -> {
          List<CaretLineState> caretLineStateList = ContainerUtil.map(caretModel.getAllCarets(), CaretLineState::create);
          List<List<CaretLineState>> caretsGroupedByLine = groupSublistRuns(caretLineStateList, CaretLineState::isOnSameLine);
          int shift = 0;
          for (List<CaretLineState> caretsOnSameLine : caretsGroupedByLine) {
            int lineStartOffset = caretsOnSameLine.get(0).lineStartOffset + shift;
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < caretsOnSameLine.size(); i++) {
              String normalizedText = normalizeText(editor, segments.next());
              ranges[index[0]++] = appendEntireLine(sb, normalizedText).shiftRight(lineStartOffset);
            }
            editor.getDocument().insertString(lineStartOffset, sb);
            for (CaretLineState caretLineState : caretsOnSameLine) {
              caretLineState.moveCaretAfterInsertionIfNeeded(lineStartOffset, sb.length());
            }
            shift += sb.length();
          }
        });
        EditorModificationUtilEx.scrollToCaret(editor);
      }
      else {
        caretModel.runForEachCaret(caret -> {
          String normalizedText = normalizeText(editor, segments.next());
          ranges[index[0]++] = insertStringAtCaret(editor, normalizedText, pasteMode == TRIM_IF_MIDDLE_LINE);
        });
      }
      return ranges;
    }
    else {
      String normalizedText = normalizeText(editor, text);
      TextRange textRange = insertStringAtCaret(editor, normalizedText, pasteMode == TRIM_IF_MIDDLE_LINE);
      return new TextRange[]{textRange};
    }
  }
@Override
  public TextRange @Nullable [] pasteTransferable(final @NotNull Editor editor, @NotNull Transferable content)