852b33c5e99a6e3918dcc0327c93ed65b604a28e
[idea/community.git] / platform / lang-impl / src / com / intellij / codeInsight / daemon / impl / analysis / HighlightingSettingsPerFile.java
1 /*
2  * Copyright 2000-2012 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.intellij.codeInsight.daemon.impl.analysis;
18
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.components.*;
21 import com.intellij.openapi.project.DumbService;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.project.ProjectCoreUtil;
24 import com.intellij.openapi.roots.ProjectFileIndex;
25 import com.intellij.openapi.roots.ProjectRootManager;
26 import com.intellij.openapi.vfs.VirtualFile;
27 import com.intellij.openapi.vfs.VirtualFileManager;
28 import com.intellij.psi.PsiElement;
29 import com.intellij.psi.PsiFile;
30 import com.intellij.psi.SingleRootFileViewProvider;
31 import com.intellij.psi.search.ProjectScope;
32 import com.intellij.psi.util.PsiUtilBase;
33 import org.jdom.Element;
34 import org.jetbrains.annotations.NonNls;
35 import org.jetbrains.annotations.NotNull;
36
37 import java.util.*;
38
39 @State(name="HighlightingSettingsPerFile", storages = @Storage(file = StoragePathMacros.WORKSPACE_FILE))
40 public class HighlightingSettingsPerFile extends HighlightingLevelManager implements PersistentStateComponent<Element> {
41   @NonNls private static final String SETTING_TAG = "setting";
42   @NonNls private static final String ROOT_ATT_PREFIX = "root";
43   @NonNls private static final String FILE_ATT = "file";
44
45   public static HighlightingSettingsPerFile getInstance(Project project){
46     return (HighlightingSettingsPerFile)ServiceManager.getService(project, HighlightingLevelManager.class);
47   }
48
49   private final Map<VirtualFile, FileHighlightingSetting[]> myHighlightSettings = new HashMap<VirtualFile, FileHighlightingSetting[]>();
50
51   @NotNull
52   public FileHighlightingSetting getHighlightingSettingForRoot(@NotNull PsiElement root){
53     final PsiFile containingFile = root.getContainingFile();
54     final VirtualFile virtualFile = containingFile.getVirtualFile();
55     FileHighlightingSetting[] fileHighlightingSettings = myHighlightSettings.get(virtualFile);
56     final int index = PsiUtilBase.getRootIndex(root);
57
58     if(fileHighlightingSettings == null || fileHighlightingSettings.length <= index) {
59       return getDefaultHighlightingSetting(root.getProject(), virtualFile);
60     }
61     return fileHighlightingSettings[index];
62   }
63
64   @NotNull
65   private static FileHighlightingSetting getDefaultHighlightingSetting(@NotNull Project project, final VirtualFile virtualFile) {
66     if (virtualFile != null) {
67       DefaultHighlightingSettingProvider[] providers = DefaultHighlightingSettingProvider.EP_NAME.getExtensions();
68       List<DefaultHighlightingSettingProvider> filtered =
69         DumbService.getInstance(project).filterByDumbAwareness(Arrays.asList(providers));
70       for (DefaultHighlightingSettingProvider p : filtered) {
71         FileHighlightingSetting setting = p.getDefaultSetting(project, virtualFile);
72         if (setting != null) {
73           return setting;
74         }
75       }
76     }
77     return FileHighlightingSetting.FORCE_HIGHLIGHTING;
78   }
79
80   @NotNull
81   private static FileHighlightingSetting[] getDefaults(@NotNull PsiFile file){
82     final int rootsCount = file.getViewProvider().getLanguages().size();
83     final FileHighlightingSetting[] fileHighlightingSettings = new FileHighlightingSetting[rootsCount];
84     for (int i = 0; i < fileHighlightingSettings.length; i++) {
85       fileHighlightingSettings[i] = FileHighlightingSetting.FORCE_HIGHLIGHTING;
86     }
87     return fileHighlightingSettings;
88   }
89
90   public void setHighlightingSettingForRoot(@NotNull PsiElement root, @NotNull FileHighlightingSetting setting) {
91     final PsiFile containingFile = root.getContainingFile();
92     final VirtualFile virtualFile = containingFile.getVirtualFile();
93     if (virtualFile == null) return;
94     FileHighlightingSetting[] defaults = myHighlightSettings.get(virtualFile);
95     int rootIndex = PsiUtilBase.getRootIndex(root);
96     if (defaults != null && rootIndex >= defaults.length) defaults = null;
97     if (defaults == null) defaults = getDefaults(containingFile);
98     defaults[rootIndex] = setting;
99     boolean toRemove = true;
100     for (FileHighlightingSetting aDefault : defaults) {
101       if (aDefault != FileHighlightingSetting.NONE) toRemove = false;
102     }
103     if (toRemove) {
104       myHighlightSettings.remove(virtualFile);
105     }
106     else {
107       myHighlightSettings.put(virtualFile, defaults);
108     }
109   }
110
111   @Override
112   public void loadState(Element element) {
113     List children = element.getChildren(SETTING_TAG);
114     for (final Object aChildren : children) {
115       final Element child = (Element)aChildren;
116       final String url = child.getAttributeValue(FILE_ATT);
117       if (url == null) continue;
118       final VirtualFile fileByUrl = VirtualFileManager.getInstance().findFileByUrl(url);
119       if (fileByUrl != null) {
120         final List<FileHighlightingSetting> settings = new ArrayList<FileHighlightingSetting>();
121         int index = 0;
122         while (child.getAttributeValue(ROOT_ATT_PREFIX + index) != null) {
123           final String attributeValue = child.getAttributeValue(ROOT_ATT_PREFIX + index++);
124           settings.add(Enum.valueOf(FileHighlightingSetting.class, attributeValue));
125         }
126         myHighlightSettings.put(fileByUrl, settings.toArray(new FileHighlightingSetting[settings.size()]));
127       }
128     }
129   }
130
131   @Override
132   public Element getState() {
133     final Element element = new Element("state");
134     for (Map.Entry<VirtualFile, FileHighlightingSetting[]> entry : myHighlightSettings.entrySet()) {
135       final Element child = new Element(SETTING_TAG);
136
137       final VirtualFile vFile = entry.getKey();
138       if (!vFile.isValid()) continue;
139       child.setAttribute(FILE_ATT, vFile.getUrl());
140       for (int i = 0; i < entry.getValue().length; i++) {
141         final FileHighlightingSetting fileHighlightingSetting = entry.getValue()[i];
142         child.setAttribute(ROOT_ATT_PREFIX + i, fileHighlightingSetting.toString());
143       }
144       element.addContent(child);
145     }
146     return element;
147   }
148
149   @Override
150   public boolean shouldHighlight(@NotNull PsiElement psiRoot) {
151     final FileHighlightingSetting settingForRoot = getHighlightingSettingForRoot(psiRoot);
152     return settingForRoot != FileHighlightingSetting.SKIP_HIGHLIGHTING;
153   }
154
155   @Override
156   public boolean shouldInspect(@NotNull PsiElement psiRoot) {
157     if (ApplicationManager.getApplication().isUnitTestMode()) return true;
158
159     final FileHighlightingSetting settingForRoot = getHighlightingSettingForRoot(psiRoot);
160     if (settingForRoot == FileHighlightingSetting.SKIP_HIGHLIGHTING ||
161         settingForRoot == FileHighlightingSetting.SKIP_INSPECTION) {
162       return false;
163     }
164     final Project project = psiRoot.getProject();
165     final VirtualFile virtualFile = psiRoot.getContainingFile().getVirtualFile();
166     if (virtualFile == null || !virtualFile.isValid()) return false;
167
168     if (ProjectCoreUtil.isProjectOrWorkspaceFile(virtualFile)) return false;
169
170     final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
171     if (ProjectScope.getLibrariesScope(project).contains(virtualFile) && !fileIndex.isInContent(virtualFile)) return false;
172
173     return !SingleRootFileViewProvider.isTooLargeForIntelligence(virtualFile);
174   }
175 }