public UnifiedEditorRangeHighlighter(@Nullable Project project, @NotNull Document document) { ApplicationManager.getApplication().assertReadAccessAllowed(); MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, false); if (model == null) return; model.processRangeHighlightersOverlappingWith(0, document.getTextLength(), new Processor<RangeHighlighterEx>() { @Override public boolean process(RangeHighlighterEx marker) { int newStart = marker.getStartOffset(); int newEnd = marker.getEndOffset(); myPieces.add(new Element(marker, newStart, newEnd)); return true; } }); }
private void processRange(@NotNull MarkupModelEx model, @NotNull HighlightRange range) { final TextRange base = range.getBase(); final TextRange changed = range.getChanged(); final int changedLength = changed.getEndOffset() - changed.getStartOffset(); model.processRangeHighlightersOverlappingWith(changed.getStartOffset(), changed.getEndOffset(), new Processor<RangeHighlighterEx>() { @Override public boolean process(RangeHighlighterEx marker) { int relativeStart = Math.max(marker.getStartOffset() - changed.getStartOffset(), 0); int relativeEnd = Math.min(marker.getEndOffset() - changed.getStartOffset(), changedLength); int newStart = base.getStartOffset() + relativeStart; int newEnd = base.getStartOffset() + relativeEnd; if (newEnd - newStart <= 0) return true; myPieces.add(new Element(marker, newStart, newEnd)); return true; } }); }
public void apply(@Nullable Project project, @NotNull Document document) { MarkupModel model = DocumentMarkupModel.forDocument(document, project, true); for (Element piece : myPieces) { RangeHighlighterEx delegate = piece.getDelegate(); if (!delegate.isValid()) continue; RangeHighlighter highlighter = model .addRangeHighlighter(piece.getStart(), piece.getEnd(), delegate.getLayer(), delegate.getTextAttributes(), delegate.getTargetArea()); highlighter.setEditorFilter(delegate.getEditorFilter()); highlighter.setCustomRenderer(delegate.getCustomRenderer()); highlighter.setErrorStripeMarkColor(delegate.getErrorStripeMarkColor()); highlighter.setErrorStripeTooltip(delegate.getErrorStripeTooltip()); highlighter.setGutterIconRenderer(delegate.getGutterIconRenderer()); highlighter.setLineMarkerRenderer(delegate.getLineMarkerRenderer()); highlighter.setLineSeparatorColor(delegate.getLineSeparatorColor()); highlighter.setThinErrorStripeMark(delegate.isThinErrorStripeMark()); highlighter.setLineSeparatorPlacement(delegate.getLineSeparatorPlacement()); highlighter.setLineSeparatorRenderer(delegate.getLineSeparatorRenderer()); } }
@NotNull ChangeResult changeAttributesNoEvents(@NotNull Consumer<RangeHighlighterEx> change) { assert !isFlagSet(IN_BATCH_CHANGE_MASK); assert !isFlagSet(CHANGED_MASK); setFlag(IN_BATCH_CHANGE_MASK, true); setFlag(RENDERERS_CHANGED_MASK, false); ChangeResult result; try { change.consume(this); } finally { setFlag(IN_BATCH_CHANGE_MASK, false); boolean changed = isFlagSet(CHANGED_MASK); boolean renderersChanged = isFlagSet(RENDERERS_CHANGED_MASK); result = changed ? renderersChanged ? ChangeResult.RENDERERS_CHANGED : ChangeResult.MINOR_CHANGE : ChangeResult.NOT_CHANGED; setFlag(CHANGED_MASK, false); setFlag(RENDERERS_CHANGED_MASK, false); } return result; }
public static boolean processHighlights(@NotNull Document document, @NotNull Project project, @Nullable("null means all") final HighlightSeverity minSeverity, final int startOffset, final int endOffset, @NotNull final Processor<HighlightInfo> processor) { LOG.assertTrue(ApplicationManager.getApplication().isReadAccessAllowed()); final SeverityRegistrar severityRegistrar = SeverityRegistrar.getSeverityRegistrar(project); MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); return model.processRangeHighlightersOverlappingWith(startOffset, endOffset, new Processor<RangeHighlighterEx>() { @Override public boolean process(@NotNull RangeHighlighterEx marker) { Object tt = marker.getErrorStripeTooltip(); if (!(tt instanceof HighlightInfo)) return true; HighlightInfo info = (HighlightInfo)tt; return minSeverity != null && severityRegistrar.compare(info.getSeverity(), minSeverity) < 0 || info.highlighter == null || processor.process(info); } }); }
static boolean processHighlightsOverlappingOutside(@NotNull Document document, @NotNull Project project, @Nullable("null means all") final HighlightSeverity minSeverity, final int startOffset, final int endOffset, @NotNull final Processor<HighlightInfo> processor) { LOG.assertTrue(ApplicationManager.getApplication().isReadAccessAllowed()); final SeverityRegistrar severityRegistrar = SeverityRegistrar.getSeverityRegistrar(project); MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); return model.processRangeHighlightersOutside(startOffset, endOffset, new Processor<RangeHighlighterEx>() { @Override public boolean process(@NotNull RangeHighlighterEx marker) { Object tt = marker.getErrorStripeTooltip(); if (!(tt instanceof HighlightInfo)) return true; HighlightInfo info = (HighlightInfo)tt; return minSeverity != null && severityRegistrar.compare(info.getSeverity(), minSeverity) < 0 || info.highlighter == null || processor.process(info); } }); }
private void paintHighlighterAfterEndOfLine(Graphics2D g, RangeHighlighterEx highlighter) { if (!highlighter.isAfterEndOfLine()) { return; } int startOffset = highlighter.getStartOffset(); int lineEndOffset = myDocument.getLineEndOffset(myDocument.getLineNumber(startOffset)); if (myEditor.getFoldingModel().isOffsetCollapsed(lineEndOffset)) return; Point lineEnd = myView.offsetToXY(lineEndOffset, true, false); int x = lineEnd.x; int y = lineEnd.y; TextAttributes attributes = highlighter.getTextAttributes(); paintBackground(g, attributes, x, y, myView.getPlainSpaceWidth()); if (attributes != null && hasTextEffect(attributes.getEffectColor(), attributes.getEffectType())) { paintTextEffect(g, x, x + myView.getPlainSpaceWidth() - 1, y + myView.getAscent(), attributes.getEffectColor(), attributes.getEffectType()); } }
private void paintBorderEffect(final Graphics2D g, final ClipDetector clipDetector, MarkupModelEx markupModel, int clipStartOffset, int clipEndOffset) { markupModel.processRangeHighlightersOverlappingWith(clipStartOffset, clipEndOffset, new Processor<RangeHighlighterEx>() { @Override public boolean process(RangeHighlighterEx rangeHighlighter) { if (rangeHighlighter.getEditorFilter().avaliableIn(myEditor)) { TextAttributes attributes = rangeHighlighter.getTextAttributes(); if (isBorder(attributes)) { paintBorderEffect(g, clipDetector, rangeHighlighter.getAffectedAreaStartOffset(), rangeHighlighter.getAffectedAreaEndOffset(), attributes); } } return true; } }); }
public static List<RangeHighlighter> getHyperlinks(int startOffset, int endOffset, final Editor editor) { final MarkupModelEx markupModel = (MarkupModelEx)editor.getMarkupModel(); final CommonProcessors.CollectProcessor<RangeHighlighterEx> processor = new CommonProcessors.CollectProcessor<RangeHighlighterEx>(); markupModel.processRangeHighlightersOverlappingWith(startOffset, endOffset, new FilteringProcessor<RangeHighlighterEx>(new Condition<RangeHighlighterEx>() { @Override public boolean value(RangeHighlighterEx rangeHighlighterEx) { return rangeHighlighterEx.getEditorFilter().avaliableIn(editor) && HYPERLINK_LAYER == rangeHighlighterEx.getLayer() && rangeHighlighterEx.isValid() && getHyperlinkInfo(rangeHighlighterEx) != null; } }, processor) ); return new ArrayList<RangeHighlighter>(processor.getResults()); }
public void testRangeHighlighterLinesInRangeForLongLinePerformance() throws Exception { final int N = 50000; Document document = EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol('x', 2 * N)); final MarkupModelEx markupModel = (MarkupModelEx)DocumentMarkupModel.forDocument(document, ourProject, true); for (int i=0; i<N-1;i++) { markupModel.addRangeHighlighter(2*i, 2*i+1, 0, null, HighlighterTargetArea.EXACT_RANGE); } markupModel.addRangeHighlighter(N / 2, N / 2 + 1, 0, null, HighlighterTargetArea.LINES_IN_RANGE); PlatformTestUtil.startPerformanceTest("slow highlighters lookup", (int)(N*Math.log(N)/1000), new ThrowableRunnable() { @Override public void run() { List<RangeHighlighterEx> list = new ArrayList<RangeHighlighterEx>(); CommonProcessors.CollectProcessor<RangeHighlighterEx> coll = new CommonProcessors.CollectProcessor<RangeHighlighterEx>(list); for (int i=0; i<N-1;i++) { list.clear(); markupModel.processRangeHighlightersOverlappingWith(2*i, 2*i+1, coll); assertEquals(2, list.size()); // 1 line plus one exact range marker } } }).assertTiming(); }
private static boolean isOffsetInsideHighlightInfo(int offset, @NotNull HighlightInfo info, boolean includeFixRange) { RangeHighlighterEx highlighter = info.highlighter; if (highlighter == null || !highlighter.isValid()) return false; int startOffset = highlighter.getStartOffset(); int endOffset = highlighter.getEndOffset(); if (startOffset <= offset && offset <= endOffset) { return true; } if (!includeFixRange) return false; RangeMarker fixMarker = info.fixMarker; if (fixMarker != null) { // null means its range is the same as highlighter if (!fixMarker.isValid()) return false; startOffset = fixMarker.getStartOffset(); endOffset = fixMarker.getEndOffset(); return startOffset <= offset && offset <= endOffset; } return false; }
/** * Gets highlighted information from test console. Some parts of output (like file links) may be highlighted, and you need to check them. * * @return pair of [[ranges], [texts]] where range is [from,to] in doc. for each region, and "text" is text extracted from this region. * For example assume that in document "spam eggs ham" words "ham" and "spam" are highlighted. * You should have 2 ranges (0, 4) and (10, 13) and 2 strings (spam and ham) */ @NotNull public Pair<List<Pair<Integer, Integer>>, List<String>> getHighlightedStringsInConsole() { final List<String> resultStrings = new ArrayList<String>(); final List<Pair<Integer, Integer>> resultRanges = new ArrayList<Pair<Integer, Integer>>(); ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { myConsole.flushDeferredText(); final Editor editor = myConsole.getEditor(); for (final RangeHighlighter highlighter : editor.getMarkupModel().getAllHighlighters()) { if (highlighter instanceof RangeHighlighterEx) { final int start = ((RangeHighlighterEx)highlighter).getAffectedAreaStartOffset(); final int end = ((RangeHighlighterEx)highlighter).getAffectedAreaEndOffset(); resultRanges.add(Pair.create(start, end)); resultStrings.add(editor.getDocument().getText().substring(start, end)); } } } }, ModalityState.NON_MODAL); return Pair.create(resultRanges, resultStrings); }
RangeHighlighterImpl(@NotNull MarkupModel model, int start, int end, int layer, @NotNull HighlighterTargetArea target, TextAttributes textAttributes, boolean greedyToLeft, boolean greedyToRight) { super((DocumentEx)model.getDocument(), start, end,false); data = new RangeHighlighterData(model, target, textAttributes) { @NotNull @Override public RangeHighlighterEx getRangeHighlighter() { return RangeHighlighterImpl.this; } }; registerInTree(start, end, greedyToLeft, greedyToRight, layer); }
@Override public RangeHighlighterEx addRangeHighlighterAndChangeAttributes(int startOffset, int endOffset, int layer, TextAttributes textAttributes, @NotNull HighlighterTargetArea targetArea, boolean isPersistent, @Nullable Consumer<RangeHighlighterEx> changeAttributesAction) { ApplicationManager.getApplication().assertIsDispatchThread(); RangeHighlighterEx highlighter = isPersistent ? new PersistentRangeHighlighterImpl(this, startOffset, layer, targetArea, textAttributes) : new RangeHighlighterImpl(this, startOffset, endOffset, layer, targetArea, textAttributes, false, false); myCachedHighlighters = null; if (changeAttributesAction != null) { ((RangeHighlighterImpl)highlighter).changeAttributesNoEvents(changeAttributesAction); } fireAfterAdded(highlighter); return highlighter; }
public static boolean processHighlights(@NotNull Document document, @NotNull Project project, @Nullable("null means all") final HighlightSeverity minSeverity, final int startOffset, final int endOffset, @NotNull final Processor<HighlightInfo> processor) { LOG.assertTrue(ApplicationManager.getApplication().isReadAccessAllowed()); final SeverityRegistrar severityRegistrar = SeverityUtil.getSeverityRegistrar(project); MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); return model.processRangeHighlightersOverlappingWith(startOffset, endOffset, new Processor<RangeHighlighterEx>() { @Override public boolean process(@NotNull RangeHighlighterEx marker) { Object tt = marker.getErrorStripeTooltip(); if (!(tt instanceof HighlightInfo)) return true; HighlightInfo info = (HighlightInfo)tt; return minSeverity != null && severityRegistrar.compare(info.getSeverity(), minSeverity) < 0 || info.highlighter == null || processor.process(info); } }); }
static boolean processHighlightsOverlappingOutside(@NotNull Document document, @NotNull Project project, @Nullable("null means all") final HighlightSeverity minSeverity, final int startOffset, final int endOffset, @NotNull final Processor<HighlightInfo> processor) { LOG.assertTrue(ApplicationManager.getApplication().isReadAccessAllowed()); final SeverityRegistrar severityRegistrar = SeverityUtil.getSeverityRegistrar(project); MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); return model.processRangeHighlightersOutside(startOffset, endOffset, new Processor<RangeHighlighterEx>() { @Override public boolean process(@NotNull RangeHighlighterEx marker) { Object tt = marker.getErrorStripeTooltip(); if (!(tt instanceof HighlightInfo)) return true; HighlightInfo info = (HighlightInfo)tt; return minSeverity != null && severityRegistrar.compare(info.getSeverity(), minSeverity) < 0 || info.highlighter == null || processor.process(info); } }); }
private static void duplicateHighlighters(MarkupModel to, MarkupModel from, int offset, TextRange textRange) { for (RangeHighlighter rangeHighlighter : from.getAllHighlighters()) { if (!rangeHighlighter.isValid()) continue; Object tooltip = rangeHighlighter.getErrorStripeTooltip(); HighlightInfo highlightInfo = tooltip instanceof HighlightInfo? (HighlightInfo)tooltip : null; if (highlightInfo != null) { if (highlightInfo.getSeverity() != HighlightSeverity.INFORMATION) continue; if (highlightInfo.type.getAttributesKey() == EditorColors.IDENTIFIER_UNDER_CARET_ATTRIBUTES) continue; } final int localOffset = textRange.getStartOffset(); final int start = Math.max(rangeHighlighter.getStartOffset(), localOffset) - localOffset; final int end = Math.min(rangeHighlighter.getEndOffset(), textRange.getEndOffset()) - localOffset; if (start > end) continue; final RangeHighlighter h = to.addRangeHighlighter( start + offset, end + offset, rangeHighlighter.getLayer(), rangeHighlighter.getTextAttributes(), rangeHighlighter.getTargetArea()); ((RangeHighlighterEx)h).setAfterEndOfLine(((RangeHighlighterEx)rangeHighlighter).isAfterEndOfLine()); } }
public UnifiedEditorRangeHighlighter(@Nullable Project project, @Nonnull Document document) { ApplicationManager.getApplication().assertReadAccessAllowed(); MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, false); if (model == null) return; model.processRangeHighlightersOverlappingWith(0, document.getTextLength(), new Processor<RangeHighlighterEx>() { @Override public boolean process(RangeHighlighterEx marker) { int newStart = marker.getStartOffset(); int newEnd = marker.getEndOffset(); myPieces.add(new Element(marker, newStart, newEnd)); return true; } }); }
private void processRange(@Nonnull MarkupModelEx model, @Nonnull HighlightRange range) { final TextRange base = range.getBase(); final TextRange changed = range.getChanged(); final int changedLength = changed.getEndOffset() - changed.getStartOffset(); model.processRangeHighlightersOverlappingWith(changed.getStartOffset(), changed.getEndOffset(), new Processor<RangeHighlighterEx>() { @Override public boolean process(RangeHighlighterEx marker) { int relativeStart = Math.max(marker.getStartOffset() - changed.getStartOffset(), 0); int relativeEnd = Math.min(marker.getEndOffset() - changed.getStartOffset(), changedLength); int newStart = base.getStartOffset() + relativeStart; int newEnd = base.getStartOffset() + relativeEnd; if (newEnd - newStart <= 0) return true; myPieces.add(new Element(marker, newStart, newEnd)); return true; } }); }
public void apply(@Nullable Project project, @Nonnull Document document) { MarkupModel model = DocumentMarkupModel.forDocument(document, project, true); for (Element piece : myPieces) { RangeHighlighterEx delegate = piece.getDelegate(); if (!delegate.isValid()) continue; RangeHighlighter highlighter = model .addRangeHighlighter(piece.getStart(), piece.getEnd(), delegate.getLayer(), delegate.getTextAttributes(), delegate.getTargetArea()); highlighter.setEditorFilter(delegate.getEditorFilter()); highlighter.setCustomRenderer(delegate.getCustomRenderer()); highlighter.setErrorStripeMarkColor(delegate.getErrorStripeMarkColor()); highlighter.setErrorStripeTooltip(delegate.getErrorStripeTooltip()); highlighter.setGutterIconRenderer(delegate.getGutterIconRenderer()); highlighter.setLineMarkerRenderer(delegate.getLineMarkerRenderer()); highlighter.setLineSeparatorColor(delegate.getLineSeparatorColor()); highlighter.setThinErrorStripeMark(delegate.isThinErrorStripeMark()); highlighter.setLineSeparatorPlacement(delegate.getLineSeparatorPlacement()); highlighter.setLineSeparatorRenderer(delegate.getLineSeparatorRenderer()); } }
@ChangeStatus byte changeAttributesNoEvents(@Nonnull Consumer<RangeHighlighterEx> change) { assert !isFlagSet(IN_BATCH_CHANGE_MASK); assert !isFlagSet(CHANGED_MASK); setFlag(IN_BATCH_CHANGE_MASK, true); setFlag(RENDERERS_CHANGED_MASK, false); setFlag(FONT_STYLE_OR_COLOR_CHANGED_MASK, false); byte result = 0; try { change.consume(this); } finally { setFlag(IN_BATCH_CHANGE_MASK, false); if (isFlagSet(CHANGED_MASK)) { result |= CHANGED_MASK; if (isFlagSet(RENDERERS_CHANGED_MASK)) result |= RENDERERS_CHANGED_MASK; if (isFlagSet(FONT_STYLE_OR_COLOR_CHANGED_MASK)) result |= FONT_STYLE_OR_COLOR_CHANGED_MASK; } setFlag(CHANGED_MASK, false); setFlag(RENDERERS_CHANGED_MASK, false); setFlag(FONT_STYLE_OR_COLOR_CHANGED_MASK, false); } return result; }
private void paintHighlighterAfterEndOfLine(Graphics2D g, RangeHighlighterEx highlighter) { if (!highlighter.isAfterEndOfLine()) { return; } int startOffset = highlighter.getStartOffset(); int lineEndOffset = myDocument.getLineEndOffset(myDocument.getLineNumber(startOffset)); if (myEditor.getFoldingModel().isOffsetCollapsed(lineEndOffset)) return; Point2D lineEnd = myView.offsetToXY(lineEndOffset, true, false); float x = (float)lineEnd.getX(); int y = (int)lineEnd.getY(); TextAttributes attributes = highlighter.getTextAttributes(); paintBackground(g, attributes, x, y, myView.getPlainSpaceWidth()); if (attributes != null && hasTextEffect(attributes.getEffectColor(), attributes.getEffectType(), false)) { paintTextEffect(g, x, x + myView.getPlainSpaceWidth() - 1, y + myView.getAscent(), attributes.getEffectColor(), attributes.getEffectType(), false); } }
private static boolean isOffsetInsideHighlightInfo(int offset, @Nonnull HighlightInfo info, boolean includeFixRange) { RangeHighlighterEx highlighter = info.getHighlighter(); if (highlighter == null || !highlighter.isValid()) return false; int startOffset = highlighter.getStartOffset(); int endOffset = highlighter.getEndOffset(); if (startOffset <= offset && offset <= endOffset) { return true; } if (!includeFixRange) return false; RangeMarker fixMarker = info.fixMarker; if (fixMarker != null) { // null means its range is the same as highlighter if (!fixMarker.isValid()) return false; startOffset = fixMarker.getStartOffset(); endOffset = fixMarker.getEndOffset(); return startOffset <= offset && offset <= endOffset; } return false; }
private static void addActions(@Nonnull Project project, @Nonnull RangeHighlighterEx info, @Nonnull List<HighlightInfo.IntentionActionDescriptor> descriptors, @Nonnull AnActionEvent event) { final GutterIconRenderer r = info.getGutterIconRenderer(); if (r == null || DumbService.isDumb(project) && !DumbService.isDumbAware(r)) { return; } List<HighlightInfo.IntentionActionDescriptor> list = new ArrayList<>(); for (AnAction action : ar(r.getClickAction(), r.getMiddleButtonClickAction(), r.getRightButtonClickAction(), r.getPopupMenuActions())) { if (action != null) { addActions(action, list, r, 0, event); } } if (list.isEmpty()) return; if (list.size() == 1) { descriptors.addAll(list); } else { HighlightInfo.IntentionActionDescriptor first = list.get(0); List<IntentionAction> options = ContainerUtil.map(list.subList(1, list.size()), HighlightInfo.IntentionActionDescriptor::getAction); descriptors.add(new HighlightInfo.IntentionActionDescriptor(first.getAction(), options, null, first.getIcon())); } }
@NotNull @Override public RangeHighlighterEx addRangeHighlighterAndChangeAttributes(int startOffset, int endOffset, int layer, TextAttributes textAttributes, @NotNull HighlighterTargetArea targetArea, boolean isPersistent, Consumer<RangeHighlighterEx> changeAttributesAction) { throw new ProcessCanceledException(); }
@Override @Nullable public RangeHighlighterEx addPersistentLineHighlighter(int lineNumber, int layer, TextAttributes textAttributes) { if (isNotValidLine(lineNumber)) { return null; } int offset = DocumentUtil.getFirstNonSpaceCharOffset(getDocument(), lineNumber); return addRangeHighlighter(PersistentRangeHighlighterImpl.create(this, offset, layer, HighlighterTargetArea.LINES_IN_RANGE, textAttributes, false), null); }
@Override @NotNull public RangeHighlighter[] getAllHighlighters() { ApplicationManager.getApplication().assertIsDispatchThread(); if (myCachedHighlighters == null) { int size = myHighlighterTree.size() + myHighlighterTreeForLines.size(); if (size == 0) return RangeHighlighter.EMPTY_ARRAY; List<RangeHighlighterEx> list = new ArrayList<RangeHighlighterEx>(size); CommonProcessors.CollectProcessor<RangeHighlighterEx> collectProcessor = new CommonProcessors.CollectProcessor<RangeHighlighterEx>(list); myHighlighterTree.process(collectProcessor); myHighlighterTreeForLines.process(collectProcessor); myCachedHighlighters = list.toArray(new RangeHighlighter[list.size()]); } return myCachedHighlighters; }
@NotNull @Override public RangeHighlighterEx addRangeHighlighterAndChangeAttributes(int startOffset, int endOffset, int layer, TextAttributes textAttributes, @NotNull HighlighterTargetArea targetArea, boolean isPersistent, @Nullable Consumer<RangeHighlighterEx> changeAttributesAction) { return addRangeHighlighter(isPersistent ? PersistentRangeHighlighterImpl.create(this, startOffset, layer, targetArea, textAttributes, true) : new RangeHighlighterImpl(this, startOffset, endOffset, layer, targetArea, textAttributes, false, false), changeAttributesAction); }
@NotNull private RangeHighlighterEx addRangeHighlighter(@NotNull RangeHighlighterImpl highlighter, @Nullable Consumer<RangeHighlighterEx> changeAttributesAction) { ApplicationManager.getApplication().assertIsDispatchThread(); myCachedHighlighters = null; if (changeAttributesAction != null) { highlighter.changeAttributesNoEvents(changeAttributesAction); } fireAfterAdded(highlighter); return highlighter; }
@Override public void changeAttributesInBatch(@NotNull RangeHighlighterEx highlighter, @NotNull Consumer<RangeHighlighterEx> changeAttributesAction) { ApplicationManager.getApplication().assertIsDispatchThread(); RangeHighlighterImpl.ChangeResult changed = ((RangeHighlighterImpl)highlighter).changeAttributesNoEvents(changeAttributesAction); if (changed != RangeHighlighterImpl.ChangeResult.NOT_CHANGED) { fireAttributesChanged(highlighter, changed == RangeHighlighterImpl.ChangeResult.RENDERERS_CHANGED); } }
@Override public void addRangeHighlighter(@NotNull RangeHighlighterEx marker, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { ApplicationManager.getApplication().assertIsDispatchThread(); treeFor(marker).addInterval(marker, start, end, greedyToLeft, greedyToRight, layer); }
@Override public void removeHighlighter(@NotNull RangeHighlighter segmentHighlighter) { ApplicationManager.getApplication().assertIsDispatchThread(); myCachedHighlighters = null; if (!segmentHighlighter.isValid()) return; boolean removed = treeFor(segmentHighlighter).removeInterval((RangeHighlighterEx)segmentHighlighter); LOG.assertTrue(removed); }
@Override public boolean containsHighlighter(@NotNull final RangeHighlighter highlighter) { ApplicationManager.getApplication().assertIsDispatchThread(); Processor<RangeHighlighterEx> equalId = new Processor<RangeHighlighterEx>() { @Override public boolean process(RangeHighlighterEx h) { return h.getId() != ((RangeHighlighterEx)highlighter).getId(); } }; return !treeFor(highlighter).processOverlappingWith(highlighter.getStartOffset(), highlighter.getEndOffset(), equalId); }
@Override public boolean processRangeHighlightersOverlappingWith(int start, int end, @NotNull Processor<? super RangeHighlighterEx> processor) { DisposableIterator<RangeHighlighterEx> iterator = overlappingIterator(start, end); try { while (iterator.hasNext()) { if (!processor.process(iterator.next())) { return false; } } return true; } finally { iterator.dispose(); } }
@Override @NotNull public IntervalTreeImpl.PeekableIterator<RangeHighlighterEx> overlappingIterator(int startOffset, int endOffset) { startOffset = Math.max(0,startOffset); endOffset = Math.max(startOffset, endOffset); return IntervalTreeImpl .mergingOverlappingIterator(myHighlighterTree, new TextRangeInterval(startOffset, endOffset), myHighlighterTreeForLines, roundToLineBoundaries(startOffset, endOffset), RangeHighlighterEx.BY_AFFECTED_START_OFFSET); }
@Override protected int compareEqualStartIntervals(@NotNull IntervalNode<RangeHighlighterEx> i1, @NotNull IntervalNode<RangeHighlighterEx> i2) { RHNode o1 = (RHNode)i1; RHNode o2 = (RHNode)i2; int d = o2.myLayer - o1.myLayer; if (d != 0) { return d; } return super.compareEqualStartIntervals(i1, i2); }
public RHNode(@NotNull RangeHighlighterTree rangeMarkerTree, @NotNull final RangeHighlighterEx key, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { super(rangeMarkerTree, key, start, end, greedyToLeft, greedyToRight); myLayer = layer; }
@NotNull @Override public RangeHighlighterEx addRangeHighlighterAndChangeAttributes(int startOffset, int endOffset, int layer, TextAttributes textAttributes, @NotNull HighlighterTargetArea targetArea, boolean isPersistent, Consumer<RangeHighlighterEx> changeAttributesAction) { TextRange hostRange = myDocument.injectedToHost(new ProperTextRange(startOffset, endOffset)); return myHostModel.addRangeHighlighterAndChangeAttributes(hostRange.getStartOffset(), hostRange.getEndOffset(), layer, textAttributes, targetArea, isPersistent, changeAttributesAction); }