Fix OC-3040 TODO[ik] implementation: need to be fixed to correctly process indent...
authorAlexey Utkin <alexey.utkin@jetbrains.com>
Mon, 21 Oct 2013 08:57:39 +0000 (12:57 +0400)
committerAlexey Utkin <alexey.utkin@jetbrains.com>
Mon, 21 Oct 2013 09:05:15 +0000 (13:05 +0400)
platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java

index af96331aa30653fa46b6a40c291218043a817b42..1b190245cf5e01d8c349810cfd51043cd7274a8a 100644 (file)
@@ -375,7 +375,6 @@ public class PostprocessReformattingAspect implements PomModelAspect {
       final PostprocessFormattingTask currentTask = iterator.next();
       if (accumulatedTask == null) {
         accumulatedTask = currentTask;
-        iterator.remove();
       }
       else if (accumulatedTask.getStartOffset() > currentTask.getEndOffset() ||
                accumulatedTask.getStartOffset() == currentTask.getEndOffset() &&
@@ -389,7 +388,6 @@ public class PostprocessReformattingAspect implements PomModelAspect {
         }
 
         accumulatedTask = currentTask;
-        iterator.remove();
       }
       else if (accumulatedTask instanceof ReformatTask && currentTask instanceof ReindentTask) {
         // split accumulated reformat range into two
@@ -405,49 +403,93 @@ public class PostprocessReformattingAspect implements PomModelAspect {
         final RangeMarker rangeToProcess = document.createRangeMarker(currentTask.getEndOffset(), accumulatedTask.getEndOffset());
         freeFormattingActions.add(new ReformatWithHeadingWhitespaceTask(rangeToProcess));
         accumulatedTask = currentTask;
-        iterator.remove();
       }
-      else {
-        if (!(accumulatedTask instanceof ReindentTask)) {
-          iterator.remove();
-
-          boolean withLeadingWhitespace = accumulatedTask instanceof ReformatWithHeadingWhitespaceTask;
-          if (accumulatedTask instanceof ReformatTask &&
-              currentTask instanceof ReformatWithHeadingWhitespaceTask &&
-              accumulatedTask.getStartOffset() == currentTask.getStartOffset()) {
-            withLeadingWhitespace = true;
-          }
-          else if (accumulatedTask instanceof ReformatWithHeadingWhitespaceTask &&
-              currentTask instanceof ReformatTask &&
-              accumulatedTask.getStartOffset() < currentTask.getStartOffset()) {
-            withLeadingWhitespace = false;
-          }
-          int newStart = Math.min(accumulatedTask.getStartOffset(), currentTask.getStartOffset());
-          int newEnd = Math.max(accumulatedTask.getEndOffset(), currentTask.getEndOffset());
-          RangeMarker rangeMarker;
+      else if (!(accumulatedTask instanceof ReindentTask)) {
+        boolean withLeadingWhitespace = accumulatedTask instanceof ReformatWithHeadingWhitespaceTask;
+        if (accumulatedTask instanceof ReformatTask &&
+            currentTask instanceof ReformatWithHeadingWhitespaceTask &&
+            accumulatedTask.getStartOffset() == currentTask.getStartOffset()) {
+          withLeadingWhitespace = true;
+        }
+        else if (accumulatedTask instanceof ReformatWithHeadingWhitespaceTask &&
+            currentTask instanceof ReformatTask &&
+            accumulatedTask.getStartOffset() < currentTask.getStartOffset()) {
+          withLeadingWhitespace = false;
+        }
+        int newStart = Math.min(accumulatedTask.getStartOffset(), currentTask.getStartOffset());
+        int newEnd = Math.max(accumulatedTask.getEndOffset(), currentTask.getEndOffset());
+        RangeMarker rangeMarker;
 
-          if (accumulatedTask.getStartOffset() == newStart && accumulatedTask.getEndOffset() == newEnd) {
-            rangeMarker = accumulatedTask.getRange();
-          }
-          else if (currentTask.getStartOffset() == newStart && currentTask.getEndOffset() == newEnd) {
-            rangeMarker = currentTask.getRange();
-          }
-          else {
-            rangeMarker = document.createRangeMarker(newStart, newEnd);
-          }
+        if (accumulatedTask.getStartOffset() == newStart && accumulatedTask.getEndOffset() == newEnd) {
+          rangeMarker = accumulatedTask.getRange();
+        }
+        else if (currentTask.getStartOffset() == newStart && currentTask.getEndOffset() == newEnd) {
+          rangeMarker = currentTask.getRange();
+        }
+        else {
+          rangeMarker = document.createRangeMarker(newStart, newEnd);
+        }
 
-          if (withLeadingWhitespace) {
-            accumulatedTask = new ReformatWithHeadingWhitespaceTask(rangeMarker);
+        if (withLeadingWhitespace) {
+          accumulatedTask = new ReformatWithHeadingWhitespaceTask(rangeMarker);
+        }
+        else {
+          accumulatedTask = new ReformatTask(rangeMarker);
+        }
+      }
+      // accumulatedTask is an instance of ReindentTask
+      else if (currentTask instanceof ReindentTask) {
+        // child indent is different from parent, the child condition
+        //         accumulatedTask.getStartOffset() <= currentTask.getStartOffset()
+        //      && accumulatedTask.getEndOffset() >= currentTask.getEndOffset()
+        // is always true here (ordered-by-end + up "if" in the method):
+
+        final CharSequence charsSequence = document.getCharsSequence();
+        int curEndOffset = currentTask.getEndOffset();
+        int curStartOffset = currentTask.getStartOffset();
+
+        // don't process ranges that have no new lines:
+        // optimization:  the case is covered by formatting task, or does not need the indent (fragment-in-the-middle-of-line).
+        // compatibility: inline blocks have wrong indent due to historical reasons (always for inline function calls).
+        if (charsSequence.subSequence(curStartOffset, curEndOffset).toString().indexOf('\n') != -1) {
+          if (accumulatedTask.getEndOffset() > curEndOffset) {
+            // tail of parent indent (the order is from-end-to-start)
+            // restore "canonical" indent for calibration of the indent
+            freeFormattingActions.add(new ReformatWithHeadingWhitespaceTask(document.createRangeMarker(curEndOffset, curEndOffset)));
+
+            // add the indent,
+            // push indent task directly, that is in correct from-end-to-start order.
+            indentActions.add(new ReindentTask(
+              document.createRangeMarker(curEndOffset, accumulatedTask.getEndOffset()),
+              ((ReindentTask)accumulatedTask).getOldIndent()));
           }
-          else {
-            accumulatedTask = new ReformatTask(rangeMarker);
 
+          if (accumulatedTask.getStartOffset() < curStartOffset) {
+            // head of parent indent (the order is from-end-to-start)
+            // the "canonical" indent for calibration of the indent should be prepared by previous tasks
+            // here don't care about.
+            // cannot push indent task directly, some child range task could be found.
+            rangesToProcess.add(new ReindentTask(
+              document.createRangeMarker(accumulatedTask.getStartOffset(), curStartOffset - 1),
+              ((ReindentTask)accumulatedTask).getOldIndent()));
+
+            //restore position
+            iterator = rangesToProcess.iterator();
+            //noinspection StatementWithEmptyBody
+            while (iterator.next().getRange() != currentTask.getRange()) ;
           }
+
+          //body
+          final RangeMarker rangeToProcess = document.createRangeMarker(curStartOffset, curStartOffset);
+          freeFormattingActions.add(new ReformatWithHeadingWhitespaceTask(rangeToProcess));
+          accumulatedTask = currentTask;
         }
-        else if (currentTask instanceof ReindentTask) {
-          iterator.remove();
-        } // TODO[ik]: need to be fixed to correctly process indent inside indent
+        //else do nothing, just drop unused ReindentTask [currentTask]
+      }
+      else {
+        continue;
       }
+      iterator.remove();
     }
     if (accumulatedTask != null) {
       if (accumulatedTask instanceof ReindentTask) {