// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi.impl.source.codeStyle.lineIndent;

import com.intellij.formatting.FormattingMode;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.FormattingModeAwareIndentAdjuster;
import org.jetbrains.annotations.NotNull;

public class FormatterBasedIndentAdjuster  {

  private final static int MAX_SYNCHRONOUS_ADJUSTMENT_DOC_SIZE = 100000;

  private FormatterBasedIndentAdjuster() {
  }

  public static void scheduleIndentAdjustment(@NotNull Project myProject,
                                              @NotNull Document myDocument,
                                              int myOffset) {
    IndentAdjusterRunnable fixer = new IndentAdjusterRunnable(myProject, myDocument, myOffset);
    PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
    if (isSynchronousAdjustment(myDocument)) {
      documentManager.commitDocument(myDocument);
      fixer.run();
    }
    else {
      documentManager.performLaterWhenAllCommitted(fixer);
    }
  }

  private static boolean isSynchronousAdjustment(@NotNull Document document) {
    return ApplicationManager.getApplication().isUnitTestMode() || document.getTextLength() <= MAX_SYNCHRONOUS_ADJUSTMENT_DOC_SIZE;
  }

  public static class IndentAdjusterRunnable implements Runnable {
    private final Project myProject;
    private final int myLine;
    private final Document myDocument;

    public IndentAdjusterRunnable(Project project, Document document, int offset) {
      myProject = project;
      myDocument = document;
      myLine = myDocument.getLineNumber(offset);
    }

    @Override
    public void run() {
      int lineStart = myDocument.getLineStartOffset(myLine);
      CommandProcessor.getInstance().runUndoTransparentAction(() ->
        ApplicationManager.getApplication().runWriteAction(() -> {
          CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myProject);
          if (codeStyleManager instanceof FormattingModeAwareIndentAdjuster) {
            ((FormattingModeAwareIndentAdjuster)codeStyleManager).adjustLineIndent(myDocument, lineStart, FormattingMode.ADJUST_INDENT_ON_ENTER);
          }
        }));
    }
  }

}

@@ -293,32 +293,139 @@
 icationManager;%0A
+import com.intellij.openapi.application.ModalityState;%0Aimport com.intellij.openapi.application.ReadAction;%0A
 import com.intel
@@ -507,16 +507,64 @@
 cument;%0A
+import com.intellij.openapi.editor.RangeMarker;%0A
 import c
@@ -636,32 +636,65 @@
 ocumentManager;%0A
+import com.intellij.psi.PsiFile;%0A
 import com.intel
@@ -753,55 +753,127 @@
 lij.
-psi.codeStyle.FormattingModeAwareIndentAdjuster
+util.concurrency.AppExecutorUtil;%0Aimport com.intellij.util.text.CharArrayUtil;%0Aimport org.jetbrains.annotations.NotNull
 ;%0Aim
@@ -904,22 +904,23 @@
 ations.N
-otN
 ull
+able
 ;%0A%0Apubli
@@ -1569,24 +1569,28 @@
 ocument);%0A  
+  %7D%0A
     fixer.ru
@@ -1598,90 +1598,8 @@
 ();%0A
-    %7D%0A    else %7B%0A      documentManager.performLaterWhenAllCommitted(fixer);%0A    %7D%0A
   %7D%0A
@@ -2294,461 +2294,1393 @@
     
-CommandProcessor.getInstance().runUndoTransparentAction(() -%3E%0A        ApplicationManager.getApplication().runWriteAction(() -%3E %7B%0A          CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myProject);%0A          if (codeStyleManager instanceof FormattingModeAwareIndentAdjuster) %7B%0A            ((FormattingModeAwareIndentAdjuster)codeStyleManager).adjustLi
+int indentEnd = CharArrayUtil.shiftForward(myDocument.getCharsSequence(), lineStart, %22 %5Ct%22);%0A      PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(myDocument);%0A      if (file != null) %7B%0A        RangeMarker indentMarker = myDocument.createRangeMarker(lineStart, indentEnd);%0A        CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myProject);%0A        if (isSynchronousAdjustment(myDocument)) %7B%0A          updateIndent(indentMarker, codeStyleManager.getLineIndent(file, lineStart, FormattingMode.ADJUST_INDENT_ON_ENTER));%0A        %7D%0A        else %7B%0A          ReadAction.nonBlocking(() -%3E codeStyleManager.getLineIndent(file, lineStart, FormattingMode.ADJUST_INDENT_ON_ENTER))%0A            .withDocumentsCommitted(myProject)%0A            .finishOnUiThread(ModalityState.NON_MODAL, indentString -%3E updateIndent(indentMarker, indentString))%0A            .submit(AppExecutorUtil.getAppExecutorService());%0A        %7D%0A      %7D%0A    %7D%0A%0A    private void updateIndent(@NotNull RangeMarker indentMarker, @Nullable String newIndent) %7B%0A      if (
 ne
+w
 Indent
-(myDocument, lineStart, FormattingMode.ADJUST_INDENT_ON_ENTER);%0A          %7D%0A
+ != null) %7B%0A        CommandProcessor.getInstance().runUndoTransparentAction(%0A          () -%3E%0A            ApplicationManager.getApplication().runWriteAction(() -%3E %7B%0A              myDocument.replaceString(indentMarker.getStartOffset(), indentMarker.getEndOffset(), newIndent);%0A              indentMarker.dispose();%0A    
     
@@ -3692,17 +3692,26 @@
 ));%0A    
-%7D
+  %7D%0A    %7D%0A
 %0A  %7D%0A%0A%7D%0A

Move new line indent calculation out of EDT for large files (IDEA-217840)