// Copyright (c) 2004-2008 by Leif Frenzel - see http://leiffrenzel.de // This code is made available under the terms of the Eclipse Public License, // version 1.0 (EPL). See http://www.eclipse.org/legal/epl-v10.html package net.sf.eclipsefp.haskell.ui.internal.editors.haskell.text; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import net.sf.eclipsefp.haskell.ui.internal.editors.haskell.HaskellEditor; import org.eclipse.jface.text.AbstractDocument; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentPartitioner; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.reconciler.DirtyRegion; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.texteditor.spelling.SpellingAnnotation; import org.eclipse.ui.texteditor.spelling.SpellingReconcileStrategy; /** Helper class that defines the model reconciling for the Haskell * editor. * * @author Leif Frenzel */ public class HaskellReconcilingStrategy extends SpellingReconcileStrategy { /** The associated Haskell editor */ private final HaskellEditor editor; private final boolean doSpell; public HaskellReconcilingStrategy( final HaskellEditor editor,final ISourceViewer sourceViewer,final boolean doSpell ) { super(sourceViewer,EditorsUI.getSpellingService()); this.editor = editor; this.doSpell=doSpell; } // interface methods of IReconcilingStrategy // ////////////////////////////////////////// @Override public void reconcile( final DirtyRegion dirtyRegion, final IRegion subRegion ) { if (doSpell){ super.reconcile( dirtyRegion, subRegion ); } reconcile(); } // @Override // public void reconcile( final IRegion partition ) { // if (doSpell){ // super.reconcile( partition ); // } // reconcile(); // } @Override public void reconcile(final IRegion region) { if (doSpell){ AbstractDocument document = (AbstractDocument) getDocument(); IDocumentPartitioner docPartitioner = document.getDocumentPartitioner(); IAnnotationModel model = getAnnotationModel(); if (region.getOffset() == 0 && region.getLength() == document.getLength()) { //reconciling whole document super.reconcile(region); deleteUnwantedAnnotations(); } else { //partial reconciliation //preserve spelling annotations first @SuppressWarnings("unchecked") Iterator<Annotation> iter = model.getAnnotationIterator(); Map<Annotation,Position> spellingErrors = new HashMap<>(); while (iter.hasNext()) { Annotation annotation = iter.next(); if (annotation instanceof SpellingAnnotation) { SpellingAnnotation spellingAnnotation = (SpellingAnnotation) annotation; Position position = model.getPosition(spellingAnnotation); String contentType = docPartitioner.getContentType(position.getOffset()); if (!position.overlapsWith( region.getOffset(), region.getLength() ) && HaskellEditor.TEXT_CONTENTTYPE.equalsIgnoreCase(contentType)) { spellingErrors.put(spellingAnnotation, position); } } } //reconcile super.reconcile(region); //restore annotations model = getAnnotationModel(); iter = spellingErrors.keySet().iterator(); while (iter.hasNext()) { Annotation annotation = iter.next(); model.addAnnotation(annotation, spellingErrors.get(annotation)); } deleteUnwantedAnnotations(); } } reconcile(); } /** * Deletes the spelling annotations marked for not supported content types */ private void deleteUnwantedAnnotations() { org.eclipse.jface.text.AbstractDocument document = (org.eclipse.jface.text.AbstractDocument) getDocument(); IDocumentPartitioner docPartitioner = document.getDocumentPartitioner(); IAnnotationModel model = getAnnotationModel(); Iterator<?> iter = model.getAnnotationIterator(); while (iter.hasNext()) { Annotation annotation = (Annotation)iter.next(); if (annotation instanceof SpellingAnnotation) { SpellingAnnotation spellingAnnotation = (SpellingAnnotation) annotation; Position position = model.getPosition(spellingAnnotation); String contentType = docPartitioner.getContentType(position.getOffset()); if (!HaskellEditor.TEXT_CONTENTTYPE.equalsIgnoreCase(contentType)) { model.removeAnnotation(spellingAnnotation); } } } } @Override public void setDocument( final IDocument document ) { if (doSpell){ super.setDocument( document ); } } // interface methods of IReconcilingStrategyExtension // /////////////////////////////////////////////////// @Override public void initialReconcile() { if (doSpell){ super.initialReconcile(); } } // helping methods // //////////////// private void reconcile() { // on save we do typecheck and synchronize outline, so only use reconciler when dirty if (editor!=null && editor.isDirty()) { editor.synchronize(); } } }