package com.intellij.json.psi.impl;

import com.intellij.json.JsonLanguage;
import com.intellij.json.psi.JsonFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.PsiModificationTrackerImpl;
import com.intellij.psi.impl.PsiTreeChangeEventImpl;
import com.intellij.psi.impl.PsiTreeChangePreprocessor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * @author Mikhail Golubev
 */
public class JsonTreeChangePreprocessor implements PsiTreeChangePreprocessor {
  /**
   * @see com.intellij.psi.impl.PsiTreeChangePreprocessorBase#treeChanged(com.intellij.psi.impl.PsiTreeChangeEventImpl)
   */
  @Override
  public void treeChanged(@NotNull PsiTreeChangeEventImpl event) {
    if (!(event.getFile() instanceof JsonFile)) return;

    final PsiElement element = event.getParent();
    if (element == null || !(element.getManager() instanceof PsiManagerImpl)) {
      return;
    }
    final PsiModificationTrackerImpl modificationTracker = (PsiModificationTrackerImpl)element.getManager().getModificationTracker();
    boolean changedInsideCodeBlock = false;

    switch (event.getCode()) {
      case BEFORE_CHILDREN_CHANGE:
        if (event.getParent() instanceof PsiFile) {
          changedInsideCodeBlock = true;
          break;
        }

      case CHILDREN_CHANGED:
        if (event.isGenericChange()) {
          return;
        }
        changedInsideCodeBlock = isInsideCodeBlock(event.getParent());
        break;

      case BEFORE_CHILD_ADDITION:
      case BEFORE_CHILD_REMOVAL:
      case CHILD_ADDED:
      case CHILD_REMOVED:
        changedInsideCodeBlock = isInsideCodeBlock(event.getParent());
        break;

      case BEFORE_PROPERTY_CHANGE:
      case PROPERTY_CHANGED:
        changedInsideCodeBlock = false;
        break;

      case BEFORE_CHILD_REPLACEMENT:
      case CHILD_REPLACED:
        changedInsideCodeBlock = isInsideCodeBlock(event.getParent());
        break;

      case BEFORE_CHILD_MOVEMENT:
      case CHILD_MOVED:
        changedInsideCodeBlock = isInsideCodeBlock(event.getOldParent()) && isInsideCodeBlock(event.getNewParent());
        break;
    }

    if (!changedInsideCodeBlock) {
      modificationTracker.incOutOfCodeBlockModificationCounter();
    }
  }

  private boolean isInsideCodeBlock(@Nullable PsiElement element) {
    if (element instanceof PsiFileSystemItem) {
      return false;
    }
    if (element == null || element.getParent() == null) {
      return true;
    }
    // Consider all elements of JSON PSI as externally visible, i.e. they are out of code block
    return !(element.getLanguage() instanceof JsonLanguage);
  }
}

@@ -1,8 +1,609 @@
+/*%0A * Copyright 2000-2016 JetBrains s.r.o.%0A *%0A * Licensed under the Apache License, Version 2.0 (the %22License%22);%0A * you may not use this file except in compliance with the License.%0A * You may obtain a copy of the License at%0A *%0A * http://www.apache.org/licenses/LICENSE-2.0%0A *%0A * Unless required by applicable law or agreed to in writing, software%0A * distributed under the License is distributed on an %22AS IS%22 BASIS,%0A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.%0A * See the License for the specific language governing permissions and%0A * limitations under the License.%0A */%0A
 package 
@@ -705,24 +705,69 @@
 i.JsonFile;%0A
+import com.intellij.openapi.project.Project;%0A
 import com.i
@@ -794,41 +794,8 @@
 nt;%0A
-import com.intellij.psi.PsiFile;%0A
 impo
@@ -837,110 +837,8 @@
 em;%0A
-import com.intellij.psi.impl.PsiManagerImpl;%0Aimport com.intellij.psi.impl.PsiModificationTrackerImpl;%0A
 impo
@@ -940,16 +940,20 @@
 rocessor
+Base
 ;%0Aimport
@@ -1036,43 +1036,8 @@
 e;%0A%0A
-/**%0A * @author Mikhail Golubev%0A */%0A
 publ
@@ -1076,17 +1076,14 @@
 sor 
-implement
+extend
 s Ps
@@ -1109,142 +1109,103 @@
 ssor
+Base
  %7B%0A  
-/**%0A   * @see com.intellij.psi.impl.PsiTreeChangePreprocessorBase#treeChanged(com.intellij.psi.impl.PsiTreeChangeEventImpl)%0A   */
+public JsonTreeChangePreprocessor(@NotNull Project project) %7B%0A    super(project);%0A  %7D%0A
 %0A  @
@@ -1287,18 +1287,16 @@
 %0A    if 
-(!
 (event.g
@@ -1328,1511 +1328,77 @@
 ile)
-) return;%0A%0A    final PsiElement element = event.getParent();%0A    if (element == null %7C%7C !(element.getManager() instanceof PsiManagerImpl)) %7B%0A      return;%0A    %7D%0A    final PsiModificationTrackerImpl modificationTracker = (PsiModificationTrackerImpl)element.getManager().getModificationTracker();%0A    boolean changedInsideCodeBlock = false;%0A%0A    switch (event.getCode()) %7B%0A      case BEFORE_CHILDREN_CHANGE:%0A        if (event.getParent() instanceof PsiFile) %7B%0A          changedInsideCodeBlock = true;%0A          break;%0A        %7D%0A%0A      case CHILDREN_CHANGED:%0A        if (event.isGenericChange()) %7B%0A          return;%0A        %7D%0A        changedInsideCodeBlock = isInsideCodeBlock(event.getParent());%0A        break;%0A%0A      case BEFORE_CHILD_ADDITION:%0A      case BEFORE_CHILD_REMOVAL:%0A      case CHILD_ADDED:%0A      case CHILD_REMOVED:%0A        changedInsideCodeBlock = isInsideCodeBlock(event.getParent());%0A        break;%0A%0A      case BEFORE_PROPERTY_CHANGE:%0A      case PROPERTY_CHANGED:%0A        changedInsideCodeBlock = false;%0A        break;%0A%0A      case BEFORE_CHILD_REPLACEMENT:%0A      case CHILD_REPLACED:%0A        changedInsideCodeBlock = isInsideCodeBlock(event.getParent());%0A        break;%0A%0A      case BEFORE_CHILD_MOVEMENT:%0A      case CHILD_MOVED:%0A        changedInsideCodeBlock = isInsideCodeBlock(event.getOldParent()) && isInsideCodeBlock(event.getNewParent());%0A        break;%0A    %7D%0A%0A    if (!changedInsideCodeBlock) %7B%0A      modificationTracker.incOutOfCodeBlockModificationCounter();%0A    %7D%0A  %7D%0A%0A  private
+ %7B%0A      super.treeChanged(event);%0A    %7D%0A  %7D%0A%0A  @Override%0A  protected
  boo
@@ -1613,104 +1613,8 @@
   %7D%0A
-    // Consider all elements of JSON PSI as externally visible, i.e. they are out of code block%0A
     
@@ -1675,9 +1675,8 @@
 );%0A  %7D%0A%7D
-%0A

Reimplement json tree change preprocessor with PsiTreeChangePreprocessorBase