@Override protected void collectInformationWithProgress(@NotNull final ProgressIndicator progress) { if (!Registry.is("editor.injected.highlighting.enabled")) return; final Set<HighlightInfo> gotHighlights = new THashSet<HighlightInfo>(100); final List<PsiElement> inside = new ArrayList<PsiElement>(); final List<PsiElement> outside = new ArrayList<PsiElement>(); List<ProperTextRange> insideRanges = new ArrayList<ProperTextRange>(); List<ProperTextRange> outsideRanges = new ArrayList<ProperTextRange>(); // TODO: this thing is just called TWICE with same arguments eating CPU on huge files :( Divider.divideInsideAndOutside( myFile, myRestrictRange.getStartOffset(), myRestrictRange.getEndOffset(), myPriorityRange, inside, insideRanges, outside, outsideRanges, false, SHOULD_HIGHIGHT_FILTER); // all infos for the "injected fragment for the host which is inside" are indeed inside // but some of the infos for the "injected fragment for the host which is outside" can be still // inside Set<HighlightInfo> injectedResult = new THashSet<HighlightInfo>(); Set<PsiFile> injected = getInjectedPsiFiles(inside, outside, progress); setProgressLimit(injected.size()); if (!addInjectedPsiHighlights( injected, progress, Collections.synchronizedSet(injectedResult))) { throw new ProcessCanceledException(); } final List<HighlightInfo> injectionsOutside = new ArrayList<HighlightInfo>(gotHighlights.size()); Set<HighlightInfo> result; synchronized (injectedResult) { // sync here because all writes happened in another thread result = injectedResult; } for (HighlightInfo info : result) { if (myRestrictRange.contains(info)) { gotHighlights.add(info); } else { // nonconditionally apply injected results regardless whether they are in // myStartOffset,myEndOffset injectionsOutside.add(info); } } if (!injectionsOutside.isEmpty()) { final ProperTextRange priorityIntersection = myPriorityRange.intersection(myRestrictRange); if ((!inside.isEmpty() || !gotHighlights.isEmpty()) && priorityIntersection != null) { // do not apply when there were no elements to highlight // clear infos found in visible area to avoid applying them twice final List<HighlightInfo> toApplyInside = new ArrayList<HighlightInfo>(gotHighlights); myHighlights.addAll(toApplyInside); gotHighlights.clear(); myHighlightInfoProcessor.highlightsInsideVisiblePartAreProduced( myHighlightingSession, toApplyInside, myPriorityRange, myRestrictRange, getId()); } List<HighlightInfo> toApply = new ArrayList<HighlightInfo>(); for (HighlightInfo info : gotHighlights) { if (!myRestrictRange.containsRange(info.getStartOffset(), info.getEndOffset())) continue; if (!myPriorityRange.containsRange(info.getStartOffset(), info.getEndOffset())) { toApply.add(info); } } toApply.addAll(injectionsOutside); myHighlightInfoProcessor.highlightsOutsideVisiblePartAreProduced( myHighlightingSession, toApply, myRestrictRange, new ProperTextRange(0, myDocument.getTextLength()), getId()); } else { // else apply only result (by default apply command) and only within inside myHighlights.addAll(gotHighlights); myHighlightInfoProcessor.highlightsInsideVisiblePartAreProduced( myHighlightingSession, myHighlights, myRestrictRange, myRestrictRange, getId()); } }
@Override protected void collectInformationWithProgress(final ProgressIndicator progress) { final Set<HighlightInfo> gotHighlights = new THashSet<HighlightInfo>(100); final Set<HighlightInfo> outsideResult = new THashSet<HighlightInfo>(100); DaemonCodeAnalyzer daemonCodeAnalyzer = DaemonCodeAnalyzer.getInstance(myProject); HighlightVisitor[] highlightVisitors = getHighlightVisitors(); final HighlightVisitor[] filteredVisitors = filterVisitors(highlightVisitors, myFile); final List<PsiElement> inside = new ArrayList<PsiElement>(); final List<PsiElement> outside = new ArrayList<PsiElement>(); try { Divider.divideInsideAndOutside( myFile, myStartOffset, myEndOffset, myPriorityRange, inside, outside, HighlightLevelUtil.AnalysisLevel.HIGHLIGHT, false); setProgressLimit((long) (inside.size() + outside.size())); final boolean forceHighlightParents = forceHighlightParents(); if (!isDumbMode()) { highlightTodos( myFile, myDocument.getCharsSequence(), myStartOffset, myEndOffset, progress, myPriorityRange, gotHighlights, outsideResult); } collectHighlights( inside, new Runnable() { @Override public void run() { // all infos for the "injected fragment for the host which is inside" are indeed // inside // but some of the infos for the "injected fragment for the host which is outside" can // be still inside Set<HighlightInfo> injectedResult = new THashSet<HighlightInfo>(); final Set<PsiFile> injected = new THashSet<PsiFile>(); getInjectedPsiFiles(inside, outside, progress, injected); if (!addInjectedPsiHighlights( injected, progress, Collections.synchronizedSet(injectedResult))) throw new ProcessCanceledException(); final List<HighlightInfo> injectionsOutside = new ArrayList<HighlightInfo>(gotHighlights.size()); Set<HighlightInfo> result; synchronized (injectedResult) { // sync here because all writes happened in another thread result = injectedResult; } for (HighlightInfo info : result) { if (myPriorityRange.containsRange(info.getStartOffset(), info.getEndOffset())) { gotHighlights.add(info); } else { // nonconditionally apply injected results regardless whether they are in // myStartOffset,myEndOffset injectionsOutside.add(info); } } if (outsideResult.isEmpty() && injectionsOutside.isEmpty()) { return; // apply only result (by default apply command) and only within inside } final ProperTextRange priorityIntersection = myPriorityRange.intersection(new TextRange(myStartOffset, myEndOffset)); if ((!inside.isEmpty() || !gotHighlights.isEmpty()) && priorityIntersection != null) { // do not apply when there were no elements to highlight // clear infos found in visible area to avoid applying them twice final List<HighlightInfo> toApplyInside = new ArrayList<HighlightInfo>(gotHighlights); myHighlights.addAll(toApplyInside); gotHighlights.clear(); gotHighlights.addAll(outsideResult); final long modificationStamp = myDocument.getModificationStamp(); UIUtil.invokeLaterIfNeeded( new Runnable() { @Override public void run() { if (myProject.isDisposed() || modificationStamp != myDocument.getModificationStamp()) return; MarkupModel markupModel = DocumentMarkupModel.forDocument(myDocument, myProject, true); UpdateHighlightersUtil.setHighlightersInRange( myProject, myDocument, priorityIntersection, getColorsScheme(), toApplyInside, (MarkupModelEx) markupModel, Pass.UPDATE_ALL); if (myEditor != null) { new ShowAutoImportPass(myProject, myFile, myEditor) .applyInformationToEditor(); } } }); } myApplyCommand = new Runnable() { @Override public void run() { ProperTextRange range = new ProperTextRange(myStartOffset, myEndOffset); List<HighlightInfo> toApply = new ArrayList<HighlightInfo>(); for (HighlightInfo info : gotHighlights) { if (!range.containsRange(info.getStartOffset(), info.getEndOffset())) continue; if (!myPriorityRange.containsRange( info.getStartOffset(), info.getEndOffset())) { toApply.add(info); } } toApply.addAll(injectionsOutside); UpdateHighlightersUtil.setHighlightersOutsideRange( myProject, myDocument, toApply, getColorsScheme(), myStartOffset, myEndOffset, myPriorityRange, Pass.UPDATE_ALL); } }; } }, outside, progress, filteredVisitors, gotHighlights, forceHighlightParents); if (myUpdateAll) { ((DaemonCodeAnalyzerImpl) daemonCodeAnalyzer) .getFileStatusMap() .setErrorFoundFlag(myDocument, myErrorFound); } } finally { incVisitorUsageCount(-1); } myHighlights.addAll(gotHighlights); }