private static void handleReformatMarkers(
     final FileViewProvider key, final TreeSet<PostprocessFormattingTask> rangesToProcess) {
   final Document document = key.getDocument();
   if (document == null) {
     return;
   }
   for (final FileElement fileElement : ((SingleRootFileViewProvider) key).getKnownTreeRoots()) {
     fileElement.acceptTree(
         new RecursiveTreeElementWalkingVisitor() {
           protected void visitNode(TreeElement element) {
             if (CodeEditUtil.isMarkedToReformatBefore(element)) {
               CodeEditUtil.markToReformatBefore(element, false);
               rangesToProcess.add(
                   new ReformatWithHeadingWhitespaceTask(
                       document.createRangeMarker(
                           element.getStartOffset(), element.getStartOffset())));
             } else if (CodeEditUtil.isMarkedToReformat(element)) {
               CodeEditUtil.markToReformat(element, false);
               rangesToProcess.add(
                   new ReformatWithHeadingWhitespaceTask(
                       document.createRangeMarker(
                           element.getStartOffset(),
                           element.getStartOffset() + element.getTextLength())));
             }
             super.visitNode(element);
           }
         });
   }
 }
  private void doPostponedFormattingInner(final FileViewProvider key) {

    final List<ASTNode> astNodes = myReformatElements.remove(key);
    final Document document = key.getDocument();
    // Sort ranges by end offsets so that we won't need any offset adjustment after reformat or
    // reindent
    if (document == null) return;

    final VirtualFile virtualFile = key.getVirtualFile();
    if (!virtualFile.isValid()) return;

    final TreeSet<PostprocessFormattingTask> postProcessTasks =
        new TreeSet<PostprocessFormattingTask>();
    Collection<Disposable> toDispose = ContainerUtilRt.newArrayList();
    try {
      // process all roots in viewProvider to find marked for reformat before elements and create
      // appropriate range markers
      handleReformatMarkers(key, postProcessTasks);
      toDispose.addAll(postProcessTasks);

      // then we create ranges by changed nodes. One per node. There ranges can intersect. Ranges
      // are sorted by end offset.
      if (astNodes != null) createActionsMap(astNodes, key, postProcessTasks);

      if ("true".equals(System.getProperty("check.psi.is.valid"))
          && ApplicationManager.getApplication().isUnitTestMode()) {
        checkPsiIsCorrect(key);
      }

      while (!postProcessTasks.isEmpty()) {
        // now we have to normalize actions so that they not intersect and ordered in most
        // appropriate way
        // (free reformatting -> reindent -> formatting under reindent)
        final List<PostponedAction> normalizedActions =
            normalizeAndReorderPostponedActions(postProcessTasks, document);
        toDispose.addAll(normalizedActions);

        // only in following loop real changes in document are made
        for (final PostponedAction normalizedAction : normalizedActions) {
          CodeStyleSettings settings =
              CodeStyleSettingsManager.getSettings(myPsiManager.getProject());
          boolean old = settings.ENABLE_JAVADOC_FORMATTING;
          settings.ENABLE_JAVADOC_FORMATTING = false;
          try {
            normalizedAction.execute(key);
          } finally {
            settings.ENABLE_JAVADOC_FORMATTING = old;
          }
        }
      }
    } finally {
      for (Disposable disposable : toDispose) {
        //noinspection SSBasedInspection
        disposable.dispose();
      }
    }
  }
  private CodeFormatterFacade getFormatterFacade(final FileViewProvider viewProvider) {
    final CodeStyleSettings styleSettings =
        CodeStyleSettingsManager.getSettings(myPsiManager.getProject());
    final PsiDocumentManager documentManager =
        PsiDocumentManager.getInstance(myPsiManager.getProject());
    final Document document = viewProvider.getDocument();
    final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(styleSettings);

    documentManager.commitDocument(document);
    return codeFormatter;
  }
 public void execute(FileViewProvider viewProvider) {
   final Document document = viewProvider.getDocument();
   final PsiFile psiFile = viewProvider.getPsi(viewProvider.getBaseLanguage());
   for (Pair<Integer, RangeMarker> integerRangeMarkerPair : myRangesToReindent) {
     RangeMarker marker = integerRangeMarkerPair.second;
     final CharSequence charsSequence =
         document.getCharsSequence().subSequence(marker.getStartOffset(), marker.getEndOffset());
     final int oldIndent = integerRangeMarkerPair.first;
     final TextRange[] whitespaces =
         CharArrayUtil.getIndents(charsSequence, marker.getStartOffset());
     final int indentAdjustment = getNewIndent(psiFile, marker.getStartOffset()) - oldIndent;
     if (indentAdjustment != 0)
       adjustIndentationInRange(psiFile, document, whitespaces, indentAdjustment);
   }
 }
  private static void createActionsMap(
      final List<ASTNode> astNodes,
      final FileViewProvider provider,
      final TreeSet<PostprocessFormattingTask> rangesToProcess) {
    final Set<ASTNode> nodesToProcess = new HashSet<ASTNode>(astNodes);
    final Document document = provider.getDocument();
    for (final ASTNode node : astNodes) {
      nodesToProcess.remove(node);
      final FileElement fileElement = TreeUtil.getFileElement((TreeElement) node);
      if (fileElement == null || ((PsiFile) fileElement.getPsi()).getViewProvider() != provider)
        continue;
      final boolean isGenerated = CodeEditUtil.isNodeGenerated(node);

      ((TreeElement) node)
          .acceptTree(
              new RecursiveTreeElementVisitor() {
                boolean inGeneratedContext = !isGenerated;

                protected boolean visitNode(TreeElement element) {
                  if (nodesToProcess.contains(element)) return false;
                  if (CodeEditUtil.isPostponedFormattingDisabled(element)) return false;

                  final boolean currentNodeGenerated = CodeEditUtil.isNodeGenerated(element);
                  CodeEditUtil.setNodeGenerated(element, false);
                  if (currentNodeGenerated && !inGeneratedContext) {
                    rangesToProcess.add(
                        new ReformatTask(document.createRangeMarker(element.getTextRange())));
                    inGeneratedContext = true;
                  }
                  if (!currentNodeGenerated && inGeneratedContext) {
                    if (element.getElementType() == TokenType.WHITE_SPACE) return false;
                    final int oldIndent = CodeEditUtil.getOldIndentation(element);
                    LOG.assertTrue(
                        oldIndent >= 0,
                        "for not generated items old indentation must be defined: element "
                            + element);
                    rangesToProcess.add(
                        new ReindentTask(
                            document.createRangeMarker(element.getTextRange()), oldIndent));
                    inGeneratedContext = false;
                  }
                  return true;
                }

                @Override
                public void visitComposite(CompositeElement composite) {
                  boolean oldGeneratedContext = inGeneratedContext;
                  super.visitComposite(composite);
                  inGeneratedContext = oldGeneratedContext;
                }

                @Override
                public void visitLeaf(LeafElement leaf) {
                  boolean oldGeneratedContext = inGeneratedContext;
                  super.visitLeaf(leaf);
                  inGeneratedContext = oldGeneratedContext;
                }
              });

      CodeEditUtil.enablePostponedFormattingInTree(node);
    }
  }
  private static void createActionsMap(
      @NotNull List<ASTNode> astNodes,
      @NotNull FileViewProvider provider,
      @NotNull final TreeSet<PostprocessFormattingTask> rangesToProcess) {
    final Set<ASTNode> nodesToProcess = new HashSet<ASTNode>(astNodes);
    final Document document = provider.getDocument();
    if (document == null) {
      return;
    }
    for (final ASTNode node : astNodes) {
      nodesToProcess.remove(node);
      final FileElement fileElement = TreeUtil.getFileElement((TreeElement) node);
      if (fileElement == null || ((PsiFile) fileElement.getPsi()).getViewProvider() != provider)
        continue;
      final boolean isGenerated = CodeEditUtil.isNodeGenerated(node);

      ((TreeElement) node)
          .acceptTree(
              new RecursiveTreeElementVisitor() {
                boolean inGeneratedContext = !isGenerated;

                @Override
                protected boolean visitNode(TreeElement element) {
                  if (nodesToProcess.contains(element)) return false;

                  final boolean currentNodeGenerated = CodeEditUtil.isNodeGenerated(element);
                  CodeEditUtil.setNodeGenerated(element, false);
                  if (currentNodeGenerated && !inGeneratedContext) {
                    rangesToProcess.add(
                        new ReformatTask(document.createRangeMarker(element.getTextRange())));
                    inGeneratedContext = true;
                  }
                  if (!currentNodeGenerated && inGeneratedContext) {
                    if (element.getElementType() == TokenType.WHITE_SPACE) return false;
                    final int oldIndent = CodeEditUtil.getOldIndentation(element);
                    CodeEditUtil.setOldIndentation(element, -1);
                    LOG.assertTrue(
                        oldIndent >= 0,
                        "for not generated items old indentation must be defined: element "
                            + element);
                    for (TextRange indentRange : getEnabledRanges(element.getPsi())) {
                      rangesToProcess.add(
                          new ReindentTask(document.createRangeMarker(indentRange), oldIndent));
                    }
                    inGeneratedContext = false;
                  }
                  return true;
                }

                private Iterable<TextRange> getEnabledRanges(@NotNull PsiElement element) {
                  List<TextRange> disabledRanges = new ArrayList<TextRange>();
                  for (DisabledIndentRangesProvider rangesProvider :
                      DisabledIndentRangesProvider.EP_NAME.getExtensions()) {
                    Collection<TextRange> providedDisabledRanges =
                        rangesProvider.getDisabledIndentRanges(element);
                    if (providedDisabledRanges != null) {
                      disabledRanges.addAll(providedDisabledRanges);
                    }
                  }
                  return TextRangeUtil.excludeRanges(element.getTextRange(), disabledRanges);
                }

                @Override
                public void visitComposite(CompositeElement composite) {
                  boolean oldGeneratedContext = inGeneratedContext;
                  super.visitComposite(composite);
                  inGeneratedContext = oldGeneratedContext;
                }

                @Override
                public void visitLeaf(LeafElement leaf) {
                  boolean oldGeneratedContext = inGeneratedContext;
                  super.visitLeaf(leaf);
                  inGeneratedContext = oldGeneratedContext;
                }
              });
    }
  }