From 0afb18ceb5ac2c4f081b0a2ad6cb522c6c83dfa0 Mon Sep 17 00:00:00 2001 From: Tobias Melcher Date: Mon, 6 Apr 2026 22:31:29 +0200 Subject: [PATCH] Add SourceViewer#computeStyleRanges() to highlight external documents Introduces computeStyleRanges(IDocument, IRegion) on SourceViewer, which applies the viewer's own presentation reconciler and partitioner to an external document, returning the resulting SWT StyleRanges for the given region without affecting the viewer's current document. --- .../META-INF/MANIFEST.MF | 2 +- .../jface/text/source/SourceViewer.java | 81 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF b/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF index fe46a55bb3ce..653c7b05d9d0 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.30.100.qualifier +Bundle-Version: 3.31.0.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Export-Package: diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/SourceViewer.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/SourceViewer.java index c8965f3f66f0..386a8515ea1f 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/SourceViewer.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/SourceViewer.java @@ -24,6 +24,7 @@ import java.util.Stack; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; @@ -46,7 +47,9 @@ import org.eclipse.jface.text.IAutoEditStrategy; import org.eclipse.jface.text.IBlockTextSelection; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IDocumentExtension3; import org.eclipse.jface.text.IDocumentExtension4; +import org.eclipse.jface.text.IDocumentPartitioner; import org.eclipse.jface.text.IPositionUpdater; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.IRewriteTarget; @@ -56,8 +59,11 @@ import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewerExtension2; import org.eclipse.jface.text.ITextViewerLifecycle; +import org.eclipse.jface.text.ITypedRegion; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.jface.text.TextUtilities; import org.eclipse.jface.text.TextViewer; import org.eclipse.jface.text.codemining.ICodeMiningProvider; import org.eclipse.jface.text.contentassist.IContentAssistant; @@ -71,6 +77,8 @@ import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; import org.eclipse.jface.text.information.IInformationPresenter; import org.eclipse.jface.text.presentation.IPresentationReconciler; +import org.eclipse.jface.text.presentation.IPresentationReconcilerExtension; +import org.eclipse.jface.text.presentation.IPresentationRepairer; import org.eclipse.jface.text.projection.ChildDocument; import org.eclipse.jface.text.quickassist.IQuickAssistAssistant; import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext; @@ -1393,4 +1401,77 @@ private void uninstallTextViewer() { lifecycles.clear(); } + /** + * Computes syntax-highlighting style ranges for a region of an external document using this + * viewer's configured presentation reconciler and partitioner. + *

+ * This is useful when you want to syntax-color content that is not the document + * currently displayed in the viewer — for example, to preview or render a snippet with the same + * language rules that are active in this viewer. + *

+ *

+ * The viewer's partitioner is temporarily connected to the given document so that its + * presentation repairers can compute the correct highlighting. The viewer's own document is not + * affected. + *

+ * + * @param document the external document whose content should be highlighted; must not be + * {@code null} and must use the same language/content type as this viewer + * @param damage the region within {@code document} for which style ranges are computed; must + * not be {@code null} + * @return the list of {@link org.eclipse.swt.custom.StyleRange}s covering the given region, as + * produced by this viewer's presentation reconciler; never {@code null}, may be empty + * if no repairer is registered for the content type + * @throws BadLocationException if {@code damage} is outside the bounds of {@code document} + * @since 3.31 + */ + public List computeStyleRanges(IDocument document, IRegion damage) throws BadLocationException { + String partition= IDocumentExtension3.DEFAULT_PARTITIONING; + IPresentationReconciler reconciler= fPresentationReconciler; + if (reconciler instanceof IPresentationReconcilerExtension ext) { + String extPartition= ext.getDocumentPartitioning(); + if (extPartition != null && !extPartition.isEmpty()) { + partition= extPartition; + } + } + IDocument originalDocument= getDocument(); + IDocumentPartitioner partitioner= originalDocument.getDocumentPartitioner(); + document.setDocumentPartitioner(partitioner); + IDocumentPartitioner originalDocumentPartitioner= null; + if (document instanceof IDocumentExtension3 ext + && originalDocument instanceof IDocumentExtension3 originalExt) { + originalDocumentPartitioner= originalExt.getDocumentPartitioner(partition); + if (originalDocumentPartitioner != null) { + // set temporarily another document in partitioner so that presentation can be + // created for given source + originalDocumentPartitioner.disconnect(); + try { + originalDocumentPartitioner.connect(document); + } finally { + ext.setDocumentPartitioner(partition, originalDocumentPartitioner); + } + } + } + TextPresentation presentation= new TextPresentation(damage, 1000); + ITypedRegion[] partitioning= TextUtilities.computePartitioning(document, partition, damage.getOffset(), + damage.getLength(), false); + for (ITypedRegion r : partitioning) { + IPresentationRepairer repairer= reconciler.getRepairer(r.getType()); + if (repairer != null) { + repairer.setDocument(document); + repairer.createPresentation(presentation, r); + repairer.setDocument(originalDocument); + } + } + if (originalDocumentPartitioner != null) { + originalDocumentPartitioner.connect(originalDocument); + } + List result= new ArrayList<>(); + var it= presentation.getAllStyleRangeIterator(); + while (it.hasNext()) { + StyleRange next= it.next(); + result.add(next); + } + return result; + } }