void (@NotNull Project project, @NotNull Document document, @NotNull TextRange bounds, @NotNull Collection<? extends LineMarkerInfo<?>> newMarkers, int group, @NotNull HighlightingSession highlightingSession) { ApplicationManager.getApplication().assertIsNonDispatchThread(); ApplicationManager.getApplication().assertReadAccessAllowed(); MarkupModelEx markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); HighlightersRecycler toReuse = new HighlightersRecycler(); synchronized (LOCK) { try { markupModel.processRangeHighlightersOverlappingWith(bounds.getStartOffset(), bounds.getEndOffset(), highlighter -> { LineMarkerInfo<?> info = getLineMarkerInfo(highlighter); if ( // (recycle) zombie line marker immediately because similar-looking line markers don't merge, unlike regular HighlightInfos HighlightingMarkupGrave.isZombieMarkup(highlighter) && highlighter.getGutterIconRenderer() != null || group == -1 || info != null && info.updatePass == group) { toReuse.recycleHighlighter(highlighter); } return true; } ); for (LineMarkerInfo<?> info : newMarkers) { PsiElement element = info.getElement(); if (element == null) { continue; } TextRange textRange = element.getTextRange(); if (textRange == null) continue; TextRange elementRange = InjectedLanguageManager.getInstance(project).injectedToHost(element, textRange); if (bounds.contains(elementRange)) { createOrReuseLineMarker(info, markupModel, toReuse); } } if (LOG.isDebugEnabled()) { LOG.debug("LineMarkersUtil.setLineMarkersToEditor(" +bounds+ "; newMarkers: " + newMarkers + ", group: " + group + "); reused: " + toReuse.forAllInGarbageBin().size()); } UpdateHighlightersUtil.incinerateObsoleteHighlighters(toReuse, highlightingSession); } finally { toReuse.releaseHighlighters(); } } }