/* * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeHighlighting.Pass; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.ex.MarkupModelEx; import com.intellij.openapi.editor.impl.DocumentMarkupModel; import com.intellij.openapi.editor.impl.EditorMarkupModelImpl; import com.intellij.openapi.editor.markup.MarkupModel; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.ProperTextRange; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiUtilBase; import com.intellij.util.Alarm; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; public class DefaultHighlightInfoProcessor extends HighlightInfoProcessor { @Override public void highlightsInsideVisiblePartAreProduced(@NotNull final HighlightingSession session, @NotNull final List<HighlightInfo> infos, @NotNull TextRange priorityRange, @NotNull TextRange restrictRange, final int groupId) { final PsiFile psiFile = session.getPsiFile(); final Project project = psiFile.getProject(); final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); if (document == null) return; final long modificationStamp = document.getModificationStamp(); final TextRange priorityIntersection = priorityRange.intersection(restrictRange); final Editor editor = session.getEditor(); ((HighlightingSessionImpl)session).applyInEDT(() -> { if (modificationStamp != document.getModificationStamp()) return; if (priorityIntersection != null) { MarkupModel markupModel = DocumentMarkupModel.forDocument(document, project, true); EditorColorsScheme scheme = session.getColorsScheme(); UpdateHighlightersUtil.setHighlightersInRange(project, document, priorityIntersection, scheme, infos, (MarkupModelEx)markupModel, groupId); } if (editor != null && !editor.isDisposed()) { // usability: show auto import popup as soon as possible if (!DumbService.isDumb(project)) { new ShowAutoImportPass(project, psiFile, editor).doApplyInformationToEditor(); } DaemonListeners.repaintErrorStripeRenderer(editor, project); } }); } @Override public void highlightsOutsideVisiblePartAreProduced(@NotNull final HighlightingSession session, @NotNull final List<HighlightInfo> infos, @NotNull final TextRange priorityRange, @NotNull final TextRange restrictedRange, final int groupId) { final PsiFile psiFile = session.getPsiFile(); final Project project = psiFile.getProject(); final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); if (document == null) return; final long modificationStamp = document.getModificationStamp(); ((HighlightingSessionImpl)session).applyInEDT(() -> { if (project.isDisposed() || modificationStamp != document.getModificationStamp()) return; EditorColorsScheme scheme = session.getColorsScheme(); UpdateHighlightersUtil.setHighlightersOutsideRange(project, document, psiFile, infos, scheme, restrictedRange.getStartOffset(), restrictedRange.getEndOffset(), ProperTextRange.create(priorityRange), groupId); Editor editor = session.getEditor(); if (editor != null) { DaemonListeners.repaintErrorStripeRenderer(editor, project); } }); } @Override public void allHighlightsForRangeAreProduced(@NotNull HighlightingSession session, @NotNull TextRange elementRange, @Nullable List<HighlightInfo> infos) { PsiFile psiFile = session.getPsiFile(); killAbandonedHighlightsUnder(psiFile, elementRange, infos, session); } private static void killAbandonedHighlightsUnder(@NotNull PsiFile psiFile, @NotNull final TextRange range, @Nullable final List<HighlightInfo> infos, @NotNull final HighlightingSession highlightingSession) { final Project project = psiFile.getProject(); final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); if (document == null) return; DaemonCodeAnalyzerEx.processHighlights(document, project, null, range.getStartOffset(), range.getEndOffset(), existing -> { if (existing.isBijective() && existing.getGroup() == Pass.UPDATE_ALL && range.equalsToRange(existing.getActualStartOffset(), existing.getActualEndOffset())) { if (infos != null) { for (HighlightInfo created : infos) { if (existing.equalsByActualOffset(created)) return true; } } // seems that highlight info "existing" is going to disappear // remove it earlier ((HighlightingSessionImpl)highlightingSession).queueDisposeHighlighterFor(existing); } return true; }); } @Override public void infoIsAvailable(@NotNull HighlightingSession session, @NotNull HighlightInfo info, @NotNull TextRange priorityRange, @NotNull TextRange restrictedRange, int groupId) { HighlightingSessionImpl impl = (HighlightingSessionImpl)session; impl.queueHighlightInfo(info, restrictedRange, groupId); } @Override public void progressIsAdvanced(@NotNull HighlightingSession highlightingSession, double progress) { PsiFile file = highlightingSession.getPsiFile(); Editor editor = highlightingSession.getEditor(); repaintTrafficIcon(file, editor, progress); } private final Alarm repaintIconAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); private void repaintTrafficIcon(@NotNull final PsiFile file, final Editor editor, double progress) { if (ApplicationManager.getApplication().isCommandLine()) return; if (repaintIconAlarm.isEmpty() || progress >= 1) { repaintIconAlarm.addRequest(() -> { Project myProject = file.getProject(); if (myProject.isDisposed()) return; Editor myeditor = editor; if (myeditor == null) { myeditor = PsiUtilBase.findEditor(file); } if (myeditor == null || myeditor.isDisposed()) return; EditorMarkupModelImpl markup = (EditorMarkupModelImpl)myeditor.getMarkupModel(); markup.repaintTrafficLightIcon(); DaemonListeners.repaintErrorStripeRenderer(myeditor, myProject); }, 50, null); } } }