From fc3d22c318bc63f3d77980c4430f11e49f402f1d Mon Sep 17 00:00:00 2001 From: Tobias Melcher Date: Sun, 14 Dec 2025 17:04:06 +0100 Subject: [PATCH] CodeMining: reuse existing inlined annotations when minings are unchanged Add getMinings() accessor methods to CodeMiningLineContentAnnotation and CodeMiningLineHeaderAnnotation to expose their mining lists. Enhance findExistingAnnotation() in InlinedAnnotationSupport to accept an optional minings parameter and compare existing annotations' minings with new ones. This allows reusing existing annotation instances when the mining content hasn't changed, avoiding unnecessary annotation recreation and improving performance. The change prevents flickering and reduces overhead by preserving annotation objects when only their position is being updated during reconciliation, but their actual mining data remains identical. https://github.com/eclipse-platform/eclipse.platform.ui/issues/2786#issuecomment-3642875815 --- .../META-INF/MANIFEST.MF | 2 +- .../CodeMiningLineContentAnnotation.java | 4 +++ .../CodeMiningLineHeaderAnnotation.java | 4 +++ .../text/codemining/CodeMiningManager.java | 2 +- .../inlined/InlinedAnnotationSupport.java | 27 ++++++++++++++++++- 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF b/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF index 9e048a6a000..06bae9b0bf8 100644 --- a/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jface.text -Bundle-Version: 3.29.100.qualifier +Bundle-Version: 3.30.0.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Export-Package: diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineContentAnnotation.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineContentAnnotation.java index e01fab82a32..08bad8517cd 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineContentAnnotation.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineContentAnnotation.java @@ -216,4 +216,8 @@ public boolean isInVisibleLines() { public final boolean isAfterPosition() { return afterPosition; } + + public List getMinings() { + return fMinings; + } } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineHeaderAnnotation.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineHeaderAnnotation.java index 908850275d8..9df652ed88a 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineHeaderAnnotation.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineHeaderAnnotation.java @@ -290,4 +290,8 @@ public Consumer getAction(MouseEvent e) { public boolean isInVisibleLines() { return super.isInVisibleLines(); } + + public List getMinings() { + return fMinings; + } } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningManager.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningManager.java index 1de7ce01dca..a37022b13ca 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningManager.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningManager.java @@ -297,7 +297,7 @@ private void renderCodeMinings(Map> groups, ISourceV CodeMiningMode mode= CodeMiningMode.createFor(minings); // Try to find existing annotation - AbstractInlinedAnnotation ann= fInlinedAnnotationSupport.findExistingAnnotation(pos); + AbstractInlinedAnnotation ann= fInlinedAnnotationSupport.findExistingAnnotation(pos, minings); if (ann == null || !mode.annotationType.isInstance(ann)) { // The annotation doesn't exists or has wrong type => create a new one. boolean afterPosition= false; diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationSupport.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationSupport.java index 71abab71e9a..0dec68667ea 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationSupport.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationSupport.java @@ -43,6 +43,7 @@ import org.eclipse.core.runtime.Assert; import org.eclipse.jface.internal.text.codemining.CodeMiningLineContentAnnotation; +import org.eclipse.jface.internal.text.codemining.CodeMiningLineHeaderAnnotation; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DocumentEvent; @@ -58,6 +59,7 @@ import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextPresentation; +import org.eclipse.jface.text.codemining.ICodeMining; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.AnnotationPainter; import org.eclipse.jface.text.source.IAnnotationModel; @@ -483,8 +485,15 @@ public void updateAnnotations(Set annotations) { * @return the existing codemining annotation with the given position information and null * otherwise. */ - @SuppressWarnings("unchecked") public T findExistingAnnotation(Position pos) { + return findExistingAnnotation(pos, null); + } + + /** + * @since 3.30 + */ + @SuppressWarnings("unchecked") + public T findExistingAnnotation(Position pos, List minings) { if (fInlinedAnnotations == null) { return null; } @@ -496,6 +505,22 @@ public T findExistingAnnotation(Position p // Do nothing } } + if (minings == null) { + continue; + } + List existingMinings= null; + if (ann instanceof CodeMiningLineHeaderAnnotation lineHeader) { + existingMinings= lineHeader.getMinings(); + } else if (ann instanceof CodeMiningLineContentAnnotation lineContent) { + existingMinings= lineContent.getMinings(); + } + if (existingMinings != null && existingMinings.equals(minings) && ann.getPosition() != null && !ann.getPosition().isDeleted()) { + try { + return (T) ann; + } catch (ClassCastException e) { + // Do nothing + } + } } return null; }