@Override
  @RequiresEdt
  public void setCaretsAndSelections(final @NotNull List<? extends CaretState> caretStates, final boolean updateSystemSelection) {
    if (caretStates.isEmpty()) {
      throw new IllegalArgumentException("At least one caret should exist");
    }

    int maxCaretCount = getMaxCaretCount();
    List<? extends CaretState> states;
    if (caretStates.size() <= maxCaretCount) {
      states = caretStates;
    } else {
      states = caretStates.subList(0, maxCaretCount);
      EditorUtil.notifyMaxCarets(myEditor);
    }
    doWithCaretMerging(() -> {
      int index = 0;
      int oldCaretCount = myCarets.size();
      Iterator<CaretImpl> caretIterator = myCarets.iterator();
      IntCollection selectionStartsBefore = null;
      IntCollection selectionStartsAfter = null;
      IntCollection selectionEndsBefore = null;
      IntCollection selectionEndsAfter = null;
      for (CaretState caretState : states) {
        CaretImpl caret;
        if (index++ < oldCaretCount) {
          caret = caretIterator.next();
          if (caretState != null && caretState.getCaretPosition() != null) {
            caret.moveToLogicalPosition(caretState.getCaretPosition());
          }
        }
        else {
          caret = new CaretImpl(myEditor, this);
          if (caretState != null && caretState.getCaretPosition() != null) {
            caret.moveToLogicalPosition(caretState.getCaretPosition(), false, null, false, false);
          }
          synchronized (myCarets) {
            myCarets.add(caret);
            myPrimaryCaret = caret;
          }
          fireCaretAdded(caret);
        }
        if (caretState != null && caretState.getCaretPosition() != null && caretState.getVisualColumnAdjustment() != 0) {
          caret.myVisualColumnAdjustment = caretState.getVisualColumnAdjustment();
          caret.updateVisualPosition();
        }
        if (caretState != null && caretState.getSelectionStart() != null && caretState.getSelectionEnd() != null) {
          if (selectionStartsBefore == null) {
            int capacity = states.size();
            selectionStartsBefore = new IntArrayList(capacity);
            selectionStartsAfter = new IntArrayList(capacity);
            selectionEndsBefore = new IntArrayList(capacity);
            selectionEndsAfter = new IntArrayList(capacity);
          }
          selectionStartsBefore.add(caret.getSelectionStart());
          selectionEndsBefore.add(caret.getSelectionEnd());
          caret.doSetSelection(myEditor.logicalToVisualPosition(caretState.getSelectionStart()),
                               myEditor.logicalPositionToOffset(caretState.getSelectionStart()),
                               myEditor.logicalToVisualPosition(caretState.getSelectionEnd()),
                               myEditor.logicalPositionToOffset(caretState.getSelectionEnd()),
                               true, false, false);
          selectionStartsAfter.add(caret.getSelectionStart());
          selectionEndsAfter.add(caret.getSelectionEnd());
        }
      }
      int caretsToRemove = myCarets.size() - states.size();
      for (int i = 0; i < caretsToRemove; i++) {
        CaretImpl caret;
        synchronized (myCarets) {
          caret = myCarets.removeLast();
          myPrimaryCaret = myCarets.getLast();
        }
        fireCaretRemoved(caret);
        Disposer.dispose(caret);
      }
      if (updateSystemSelection) {
        updateSystemSelection();
      }
      if (selectionStartsBefore != null) {
        SelectionEvent event = new SelectionEvent(myEditor, selectionStartsBefore.toIntArray(), selectionEndsBefore.toIntArray(),
                                                  selectionStartsAfter.toIntArray(), selectionEndsAfter.toIntArray());
        myEditor.getSelectionModel().fireSelectionChanged(event);
      }
    });
  }
@Override
  @RequiresEdt
  public void setCaretsAndSelections(final @NotNull List<? extends CaretState> caretStates, final boolean updateSystemSelection)