diff options
author | Lucas Bullen | 2017-10-04 16:04:38 +0000 |
---|---|---|
committer | Lucas Bullen | 2017-11-07 13:43:48 +0000 |
commit | aaab23b17c73ac1bdd89b5c499e158b9c3275fec (patch) | |
tree | f49e5be7ca53b0d507d79700e551c4c64a766eed /org.eclipse.ui.genericeditor.examples | |
parent | a0ab17a0ec67369d0762d905ae9f170594b41f07 (diff) | |
download | eclipse.platform.text-aaab23b17c73ac1bdd89b5c499e158b9c3275fec.tar.gz eclipse.platform.text-aaab23b17c73ac1bdd89b5c499e158b9c3275fec.tar.xz eclipse.platform.text-aaab23b17c73ac1bdd89b5c499e158b9c3275fec.zip |
Bug 521382 - [generic editor] Default highlighter for generic editorI20171107-2000
Added extension point for highlight reconcilers, when one is added the
default is turned off
Change-Id: Ibbe8d3df69ba5d364c027bd8c8f07aa7b4e71902
Signed-off-by: Lucas Bullen <lbullen@redhat.com>
Diffstat (limited to 'org.eclipse.ui.genericeditor.examples')
3 files changed, 254 insertions, 0 deletions
diff --git a/org.eclipse.ui.genericeditor.examples/plugin.xml b/org.eclipse.ui.genericeditor.examples/plugin.xml index a4fd6f752d5..97238a81750 100644 --- a/org.eclipse.ui.genericeditor.examples/plugin.xml +++ b/org.eclipse.ui.genericeditor.examples/plugin.xml @@ -10,6 +10,7 @@ <!-- Contributors: --> <!-- Sopot Cela & Mickael Istria (Red Hat Inc). -initial implementation --> <!-- Lucas Bullen (Red Hat Inc.) - Bug 508829 custom reconciler support --> +<!-- - Bug 521382 default highlighter --> <!-- ====================================================================== --> <plugin> <extension @@ -76,4 +77,11 @@ contentType="org.eclipse.ui.genericeditor.examples.dotproject"> </autoEditStrategy> </extension> + <extension + point="org.eclipse.ui.genericeditor.highlightReconcilers"> + <highlightReconciler + class="org.eclipse.ui.genericeditor.examples.dotproject.HighlightReconciler" + contentType="org.eclipse.ui.genericeditor.examples.dotproject"> + </highlightReconciler> + </extension> </plugin> diff --git a/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/HighlightReconciler.java b/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/HighlightReconciler.java new file mode 100644 index 00000000000..dd520c273a6 --- /dev/null +++ b/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/HighlightReconciler.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2017 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * - Lucas Bullen (Red Hat Inc.) + *******************************************************************************/ +package org.eclipse.ui.genericeditor.examples.dotproject; + +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.reconciler.Reconciler; + +public class HighlightReconciler extends Reconciler { + + private HighlightStrategy fStrategy; + + public HighlightReconciler() { + fStrategy = new HighlightStrategy(); + this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE); + } + + @Override + public void install(ITextViewer textViewer) { + super.install(textViewer); + fStrategy.install(textViewer); + } + + @Override + public void uninstall() { + super.uninstall(); + fStrategy.uninstall(); + } +}
\ No newline at end of file diff --git a/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/HighlightStrategy.java b/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/HighlightStrategy.java new file mode 100644 index 00000000000..58d1b9060a2 --- /dev/null +++ b/org.eclipse.ui.genericeditor.examples/src/org/eclipse/ui/genericeditor/examples/dotproject/HighlightStrategy.java @@ -0,0 +1,209 @@ +/******************************************************************************* + * Copyright (c) 2017 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * - Lucas Bullen (Red Hat Inc.) + *******************************************************************************/ +package org.eclipse.ui.genericeditor.examples.dotproject; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ISynchronizable; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerExtension5; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.reconciler.DirtyRegion; +import org.eclipse.jface.text.reconciler.IReconcilingStrategy; +import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.IAnnotationModelExtension; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.swt.custom.CaretEvent; +import org.eclipse.swt.custom.CaretListener; + +/** +* +* This Reconciler Strategy is an example for how to override the default highlight strategy. +* It will highlight closing and opening tag names that match the current word the user is on. +* +*/ +public class HighlightStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension, CaretListener, IPreferenceChangeListener { + + private static final String ANNOTATION_TYPE = "org.eclipse.ui.genericeditor.text"; //$NON-NLS-1$ + public static final String TOGGLE_HIGHLIGHT_PREFERENCE = "org.eclipse.ui.genericeditor.togglehighlight"; //$NON-NLS-1$ + public static final String GENERIC_EDITOR_BUNDLE_ID = "org.eclipse.ui.genericeditor"; //$NON-NLS-1$ + + private boolean enabled; + private ISourceViewer sourceViewer; + private IDocument document; + + private static final String TAG_NAME_REGEX = "<\\/?\\s*([a-zA-Z]+)"; //$NON-NLS-1$ + private static final Pattern TAG_NAME_PATTERN = Pattern.compile(TAG_NAME_REGEX); + + private Annotation[] fOccurrenceAnnotations = null; + + private void applyHighlights(int offset) { + if (sourceViewer == null || !enabled) { + return; + } + String text = document.get(); + offset = ((ITextViewerExtension5)sourceViewer).widgetOffset2ModelOffset(offset); + + int wordStartOffset = Math.max(text.lastIndexOf('/',offset),text.lastIndexOf('<',offset))+1; + int wordEndOffset = findEndingOffset(text, offset); + if(wordEndOffset <= wordStartOffset || wordEndOffset == -1 || wordStartOffset == -1) + return; + String word = text.substring(wordStartOffset, wordEndOffset); + if(word.indexOf('>') != -1 || word.indexOf('<') != -1) { + removeOccurrenceAnnotations(); + return; + } + + Matcher m = TAG_NAME_PATTERN.matcher(text); + Map<Annotation, Position> annotationMap = new HashMap<>(); + while(m.find()) { + if(m.group(1).equals(word)) { + annotationMap.put(new Annotation(ANNOTATION_TYPE, false, null), + new Position(m.start(1), m.end(1) - m.start(1))); + } + } + + if(annotationMap.size() < 2) { + removeOccurrenceAnnotations(); + return; + } + + IAnnotationModel annotationModel = sourceViewer.getAnnotationModel(); + synchronized (getLockObject(annotationModel)) { + if (annotationModel instanceof IAnnotationModelExtension) { + ((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations, annotationMap); + } else { + removeOccurrenceAnnotations(); + Iterator<Entry<Annotation, Position>> iter = annotationMap.entrySet().iterator(); + while (iter.hasNext()) { + Entry<Annotation, Position> mapEntry = iter.next(); + annotationModel.addAnnotation(mapEntry.getKey(), mapEntry.getValue()); + } + } + fOccurrenceAnnotations = annotationMap.keySet().toArray(new Annotation[annotationMap.keySet().size()]); + } + } + + private static int findEndingOffset(String text, int offset) { + String substring = text.substring(offset); + String[] split = substring.split("[^a-zA-Z0-9]+");//$NON-NLS-1$ + if(split.length == 0) { + return -1; + } + return offset + split[0].length(); + } + + public void install(ITextViewer viewer) { + if (!(viewer instanceof ISourceViewer)) { + return; + } + IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(GENERIC_EDITOR_BUNDLE_ID); + preferences.addPreferenceChangeListener(this); + this.enabled = preferences.getBoolean(TOGGLE_HIGHLIGHT_PREFERENCE, true); + this.sourceViewer = (ISourceViewer) viewer; + this.sourceViewer.getTextWidget().addCaretListener(this); + } + + public void uninstall() { + if (sourceViewer != null) { + sourceViewer.getTextWidget().removeCaretListener(this); + } + IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(GENERIC_EDITOR_BUNDLE_ID); + preferences.removePreferenceChangeListener(this); + } + + @Override + public void preferenceChange(PreferenceChangeEvent event) { + if (event.getKey().equals(TOGGLE_HIGHLIGHT_PREFERENCE)) { + this.enabled = Boolean.parseBoolean(event.getNewValue().toString()); + if (enabled) { + initialReconcile(); + } else { + removeOccurrenceAnnotations(); + } + } + } + + @Override + public void caretMoved(CaretEvent event) { + applyHighlights(event.caretOffset); + } + + @Override + public void initialReconcile() { + if (sourceViewer != null) { + sourceViewer.getTextWidget().getDisplay().asyncExec(() -> { + if (sourceViewer != null) { + applyHighlights(sourceViewer.getTextWidget().getCaretOffset()); + } + }); + } + } + + void removeOccurrenceAnnotations() { + IAnnotationModel annotationModel = sourceViewer.getAnnotationModel(); + if (annotationModel == null || fOccurrenceAnnotations == null) + return; + + synchronized (getLockObject(annotationModel)) { + if (annotationModel instanceof IAnnotationModelExtension) { + ((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations, null); + } else { + for (Annotation fOccurrenceAnnotation : fOccurrenceAnnotations) + annotationModel.removeAnnotation(fOccurrenceAnnotation); + } + fOccurrenceAnnotations = null; + } + } + + private static Object getLockObject(IAnnotationModel annotationModel) { + if (annotationModel instanceof ISynchronizable) { + Object lock = ((ISynchronizable) annotationModel).getLockObject(); + if (lock != null) + return lock; + } + return annotationModel; + } + + @Override + public void setDocument(IDocument document) { + this.document = document; + } + + @Override + public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) { + // Do nothing + } + + @Override + public void reconcile(IRegion partition) { + // Do nothing + } + + @Override + public void setProgressMonitor(IProgressMonitor monitor) { + // Not used + } +} |