public boolean execute(boolean drop, boolean disableConfirmation) {
    if (!myUndoableGroup.isUndoable()) {
      reportNonUndoable(myUndoableGroup.getAffectedDocuments());
      return false;
    }

    Set<DocumentReference> clashing = getStacksHolder().collectClashingActions(myUndoableGroup);
    if (!clashing.isEmpty()) {
      reportClashingDocuments(clashing);
      return false;
    }

    Map<DocumentReference, Map<Integer, MutableActionChangeRange>> reference2Ranges = decompose(myUndoableGroup, isRedo());
    SharedUndoRedoStacksHolder sharedStacksHolder = getSharedStacksHolder();
    boolean shouldMove = false;
    for (Map.Entry<DocumentReference, Map<Integer, MutableActionChangeRange>> entry : reference2Ranges.entrySet()) {
      MovementAvailability availability = sharedStacksHolder.canMoveToStackTop(entry.getKey(), entry.getValue());
      if (availability == MovementAvailability.CANNOT_MOVE) {
        reportCannotAdjust(Collections.singleton(entry.getKey()));
        return false;
      }
      if (availability == MovementAvailability.CAN_MOVE) {
        shouldMove = true;
      }
    }

    if (!disableConfirmation && myUndoableGroup.shouldAskConfirmation(isRedo()) && !UndoManagerImpl.ourNeverAskUser) {
      if (!askUser()) return false;
    }
    else {
      if (!shouldMove && restore(getBeforeState(), true)) {
        setBeforeState(new EditorAndState(myEditor, myEditor.getState(FileEditorStateLevel.UNDO)));
        if (!Registry.is("ide.undo.transparent.caret.movement")) return true;
      }
    }

    Collection<VirtualFile> readOnlyFiles = collectReadOnlyAffectedFiles();
    if (!readOnlyFiles.isEmpty()) {
      final Project project = myManager.getProject();
      if (project == null) {
        return false;
      }

      final ReadonlyStatusHandler.OperationStatus operationStatus = ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(readOnlyFiles);
      if (operationStatus.hasReadonlyFiles()) {
        return false;
      }
    }

    Collection<Document> readOnlyDocuments = collectReadOnlyDocuments();
    if (!readOnlyDocuments.isEmpty()) {
      for (Document document : readOnlyDocuments) {
        document.fireReadOnlyModificationAttempt();
      }
      return false;
    }

    if (shouldMove) {
      for (Map.Entry<DocumentReference, Map<Integer, MutableActionChangeRange>> entry : reference2Ranges.entrySet()) {
        var affected = sharedStacksHolder.moveToStackTop(entry.getKey(), entry.getValue());
        if (affected != null) {
          for (ImmutableActionChangeRange range : affected) {
            MutableActionChangeRange mutableRange = entry.getValue().get(range.getId());
            if (mutableRange != null) {
              mutableRange.setState(range);
            }
          }
        }
      }
    }

    getStacksHolder().removeFromStacks(myUndoableGroup);
    if (!drop) {
      getReverseStacksHolder().addToStacks(myUndoableGroup);
    }

    SharedUndoRedoStacksHolder sharedReverseStacksHolder = getSharedReverseStacksHolder();
    for (Map.Entry<DocumentReference, Map<Integer, MutableActionChangeRange>> entry : reference2Ranges.entrySet()) {
      DocumentReference reference = entry.getKey();
      int rangeCount = entry.getValue().size();
      // All related ranges must be on the shared stack's top at this moment
      // so just pick them one by one and move to reverse stack
      for (int i = 0; i < rangeCount; i++) {
        ImmutableActionChangeRange changeRange = sharedStacksHolder.removeLastFromStack(reference);
        ImmutableActionChangeRange inverted = changeRange.asInverted().toImmutable(drop);
        sharedReverseStacksHolder.addToStack(reference, inverted);
      }
    }

    try {
      performAction();
    } catch (UnexpectedUndoException e) {
      reportException(e);
      return false;
    }

    if (!shouldMove) {
      restore(getAfterState(), false);
    }

    return true;
  }
public boolean execute(boolean drop, boolean disableConfirmation)