add DumbService.filterByDumbAwareness(T[])
[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 = DumbService.getInstance(project).filterByDumbAwareness(providers);
69       for (DefaultHighlightingSettingProvider p : filtered) {
70         FileHighlightingSetting setting = p.getDefaultSetting(project, virtualFile);
71         if (setting != null) {
72           return setting;
73         }
74       }
75     }
76     return FileHighlightingSetting.FORCE_HIGHLIGHTING;
77   }
78
79   @NotNull
80   private static FileHighlightingSetting[] getDefaults(@NotNull PsiFile file){
81     final int rootsCount = file.getViewProvider().getLanguages().size();
82     final FileHighlightingSetting[] fileHighlightingSettings = new FileHighlightingSetting[rootsCount];
83     for (int i = 0; i < fileHighlightingSettings.length; i++) {
84       fileHighlightingSettings[i] = FileHighlightingSetting.FORCE_HIGHLIGHTING;
85     }
86     return fileHighlightingSettings;
87   }
88
89   public void setHighlightingSettingForRoot(@NotNull PsiElement root, @NotNull FileHighlightingSetting setting) {
90     final PsiFile containingFile = root.getContainingFile();
91     final VirtualFile virtualFile = containingFile.getVirtualFile();
92     if (virtualFile == null) return;
93     FileHighlightingSetting[] defaults = myHighlightSettings.get(virtualFile);
94     int rootIndex = PsiUtilBase.getRootIndex(root);
95     if (defaults != null && rootIndex >= defaults.length) defaults = null;
96     if (defaults == null) defaults = getDefaults(containingFile);
97     defaults[rootIndex] = setting;
98     boolean toRemove = true;
99     for (FileHighlightingSetting aDefault : defaults) {
100       if (aDefault != FileHighlightingSetting.NONE) toRemove = false;
101     }
102     if (toRemove) {
103       myHighlightSettings.remove(virtualFile);
104     }
105     else {
106       myHighlightSettings.put(virtualFile, defaults);
107     }
108   }
109
110   @Override
111   public void loadState(Element element) {
112     List children = element.getChildren(SETTING_TAG);
113     for (final Object aChildren : children) {
114       final Element child = (Element)aChildren;
115       final String url = child.getAttributeValue(FILE_ATT);
116       if (url == null) continue;
117       final VirtualFile fileByUrl = VirtualFileManager.getInstance().findFileByUrl(url);
118       if (fileByUrl != null) {
119         final List<FileHighlightingSetting> settings = new ArrayList<FileHighlightingSetting>();
120         int index = 0;
121         while (child.getAttributeValue(ROOT_ATT_PREFIX + index) != null) {
122           final String attributeValue = child.getAttributeValue(ROOT_ATT_PREFIX + index++);
123           settings.add(Enum.valueOf(FileHighlightingSetting.class, attributeValue));
124         }
125         myHighlightSettings.put(fileByUrl, settings.toArray(new FileHighlightingSetting[settings.size()]));
126       }
127     }
128   }
129
130   @Override
131   public Element getState() {
132     final Element element = new Element("state");
133     for (Map.Entry<VirtualFile, FileHighlightingSetting[]> entry : myHighlightSettings.entrySet()) {
134       final Element child = new Element(SETTING_TAG);
135
136       final VirtualFile vFile = entry.getKey();
137       if (!vFile.isValid()) continue;
138       child.setAttribute(FILE_ATT, vFile.getUrl());
139       for (int i = 0; i < entry.getValue().length; i++) {
140         final FileHighlightingSetting fileHighlightingSetting = entry.getValue()[i];
141         child.setAttribute(ROOT_ATT_PREFIX + i, fileHighlightingSetting.toString());
142       }
143       element.addContent(child);
144     }
145     return element;
146   }
147
148   @Override
149   public boolean shouldHighlight(@NotNull PsiElement psiRoot) {
150     final FileHighlightingSetting settingForRoot = getHighlightingSettingForRoot(psiRoot);
151     return settingForRoot != FileHighlightingSetting.SKIP_HIGHLIGHTING;
152   }
153
154   @Override
155   public boolean shouldInspect(@NotNull PsiElement psiRoot) {
156     if (ApplicationManager.getApplication().isUnitTestMode()) return true;
157
158     final FileHighlightingSetting settingForRoot = getHighlightingSettingForRoot(psiRoot);
159     if (settingForRoot == FileHighlightingSetting.SKIP_HIGHLIGHTING ||
160         settingForRoot == FileHighlightingSetting.SKIP_INSPECTION) {
161       return false;
162     }
163     final Project project = psiRoot.getProject();
164     final VirtualFile virtualFile = psiRoot.getContainingFile().getVirtualFile();
165     if (virtualFile == null || !virtualFile.isValid()) return false;
166
167     if (ProjectCoreUtil.isProjectOrWorkspaceFile(virtualFile)) return false;
168
169     final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
170     if (ProjectScope.getLibrariesScope(project).contains(virtualFile) && !fileIndex.isInContent(virtualFile)) return false;
171
172     return !SingleRootFileViewProvider.isTooLargeForIntelligence(virtualFile);
173   }
174 }