// Copyright (c) 2003-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;
import net.sf.eclipsefp.haskell.ui.HaskellUIPlugin;
import net.sf.eclipsefp.haskell.ui.internal.editors.haskell.codeassist.HaskellContentAssistProcessor;
import net.sf.eclipsefp.haskell.ui.internal.editors.haskell.text.AnnotationHover;
import net.sf.eclipsefp.haskell.ui.internal.editors.haskell.text.HaskellAutoIndentStrategy;
import net.sf.eclipsefp.haskell.ui.internal.editors.haskell.text.HaskellDocumentPartitioner;
import net.sf.eclipsefp.haskell.ui.internal.editors.haskell.text.HaskellReconcilingStrategy;
import net.sf.eclipsefp.haskell.ui.internal.editors.haskell.text.ScannerManager;
import net.sf.eclipsefp.haskell.ui.internal.editors.haskell.text.ScionTokenScanner;
import net.sf.eclipsefp.haskell.ui.internal.preferences.editor.IEditorPreferenceNames;
import net.sf.eclipsefp.haskell.ui.internal.preferences.editor.SyntaxPreviewer;
import net.sf.eclipsefp.haskell.ui.internal.resolve.QuickAssistProcessor;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.DefaultLineTracker;
import org.eclipse.jface.text.IAutoEditStrategy;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.ITextHover;
import org.eclipse.jface.text.TabsToSpacesConverter;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.jface.text.hyperlink.URLHyperlinkDetector;
import org.eclipse.jface.text.presentation.IPresentationReconciler;
import org.eclipse.jface.text.presentation.PresentationReconciler;
import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
import org.eclipse.jface.text.quickassist.QuickAssistAssistant;
import org.eclipse.jface.text.reconciler.IReconciler;
import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
import org.eclipse.jface.text.reconciler.Reconciler;
import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
import org.eclipse.jface.text.source.IAnnotationHover;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.swt.widgets.Shell;
/**
* The source viewer configuration implements functionality for the Haskell editor.
*
* @author Leif Frenzel
* @author B. Scott Michel (bscottm@ieee.org)
*/
public class HaskellSourceViewerConfiguration extends SourceViewerConfiguration implements IEditorPreferenceNames {
/** The associated Haskell editor */
final HaskellEditor editor;
/** The plugin's preference store, needed to create a new ScannerManager */
private IPreferenceStore prefStore=HaskellUIPlugin.getEditorPreferenceStore();
/** The syntax highlighting and other content management container */
private ScannerManager scannerManager;
/** The constructor
*
* @param editor The associated Haskell editor
*/
public HaskellSourceViewerConfiguration( final HaskellEditor editor ) {
this.editor = editor;
}
/** Set the source viewer's preference store.
*
* <p>Note: Currently only referenced by {@link SyntaxPreviewer}</p>
*
* @param prefStore The preference store
*/
public void setPreferenceStore( final IPreferenceStore prefStore ) {
this.prefStore = prefStore;
}
// interface methods of SourceViewerConfiguration
// ///////////////////////////////////////////////
@Override
public ITextHover getTextHover( final ISourceViewer sourceViewer, final String contentType ) {
ITextHover result = null;
//if( IDocument.DEFAULT_CONTENT_TYPE.equals( contentType ) ) {
result = new HaskellTextHover( editor, sourceViewer );
//}
return result;
}
@Override
public IHyperlinkDetector[] getHyperlinkDetectors(final ISourceViewer sourceViewer) {
IHyperlinkDetector[] detectors = {
new HaskellHyperlinkDetector( editor ),
new URLHyperlinkDetector()
};
return detectors;
}
@Override
public IAutoEditStrategy[] getAutoEditStrategies( final ISourceViewer sv, final String contentType ) {
final TabsToSpacesConverter tabConverter = new TabsToSpacesConverter();
tabConverter.setLineTracker( new DefaultLineTracker() );
tabConverter.setNumberOfSpacesPerTab( getTabWidth( sv ) );
return new IAutoEditStrategy[] {
new HaskellAutoIndentStrategy(),
tabConverter
};
}
@Override
public String[] getConfiguredContentTypes( final ISourceViewer sv ) {
return new String[] { IDocument.DEFAULT_CONTENT_TYPE // plain text
,HaskellEditor.TEXT_CONTENTTYPE
};
// IPartitionTypes.HS_LITERATE_COMMENT,
// IPartitionTypes.HS_COMMENT,
// IPartitionTypes.HS_CHARACTER,
// IPartitionTypes.HS_STRING
// };
}
@Override
public int getTabWidth( final ISourceViewer sourceViewer ) {
return getPreferenceStore().getInt( EDITOR_TAB_WIDTH );
}
@Override
public IContentAssistant getContentAssistant(final ISourceViewer viewer) {
final ContentAssistant ca = new ContentAssistant();
HaskellContentAssistProcessor processor=new HaskellContentAssistProcessor(ca);
ca.setContentAssistProcessor(processor, IDocument.DEFAULT_CONTENT_TYPE);
ca.setProposalPopupOrientation(IContentAssistant.PROPOSAL_OVERLAY);
ca.setInformationControlCreator( new IInformationControlCreator() {
@Override
public IInformationControl createInformationControl( final Shell parent ) {
//return new HaskellInformationControl(parent,viewer.getTextWidget().getFont());
return new DefaultInformationControl( parent, false );
}
} );
ca.setStatusLineVisible( true );
ca.setStatusMessage( "msg" );
ca.enablePrefixCompletion( true );
ca.setRepeatedInvocationMode( true );
ca.enableAutoActivation(true);
ca.enableAutoInsert(true);
ca.setAutoActivationDelay(500);
return ca;
}
/**
* Get the scanner manager. If the preference store (prefStore) is set, then return a new {@link ScannerManager}
* that uses the preference store; otherwise, return the ScannerManager singleton instance.
* */
public ScannerManager getScannerManager() {
if ( prefStore != null ) {
if ( scannerManager == null ){
scannerManager = new ScannerManager( prefStore );
}
return scannerManager;
}
return ScannerManager.getInstance();
}
/** the presentation reconciler is responsible for syntax coloring. */
@Override
public IPresentationReconciler getPresentationReconciler(final ISourceViewer sv) {
boolean colorInThread=false;
if (editor!=null && editor.getDocument()!=null){
int sizeInK=HaskellUIPlugin.getDefault().getPreferenceStore().getInt( IEditorPreferenceNames.EDITOR_COLORING_THREAD_THRESHOLD );
if (sizeInK>-1){
int length=editor.getDocument().get().length();
colorInThread=length>=sizeInK*1024;
}
}
//boolean big=length>20000; // more than 20K is big
PresentationReconciler reconciler = colorInThread?new HaskellPresentationReconciler():new PresentationReconciler();
IFile file = (editor != null ? editor.findFile() : null);
// get token scanner from partitioner to avoid duplicates
IDocumentPartitioner dp=null;
if (editor!=null && editor.getDocument()!=null){
dp=editor.getDocument().getDocumentPartitioner();
}
ScionTokenScanner codeScanner=null;
if (dp instanceof HaskellDocumentPartitioner){
codeScanner=((HaskellDocumentPartitioner)dp).getScanner();
}
//if (codeScanner==null){
codeScanner=new ScionTokenScanner(getScannerManager(), file);
//}
if (editor!=null){
editor.setTokenScanner( codeScanner );
}
DefaultDamagerRepairer dr=new DefaultDamagerRepairer( codeScanner );
reconciler.setDamager( dr, IDocument.DEFAULT_CONTENT_TYPE );
reconciler.setRepairer( dr, IDocument.DEFAULT_CONTENT_TYPE );
DefaultDamagerRepairer dr2=new DefaultDamagerRepairer( codeScanner );
reconciler.setDamager( dr2, HaskellEditor.TEXT_CONTENTTYPE );
reconciler.setRepairer( dr2, HaskellEditor.TEXT_CONTENTTYPE );
return reconciler;
}
@Override
public IAnnotationHover getAnnotationHover(final ISourceViewer sv) {
return new AnnotationHover();
}
@Override
public String[] getDefaultPrefixes(final ISourceViewer sourceViewer,
final String contentType) {
return new String[] { "--" }; //$NON-NLS-1$
}
@Override
public String[] getIndentPrefixes(final ISourceViewer sourceViewer, final String contentType) {
int tabWidth = getTabWidth(sourceViewer);
StringBuilder prefix = new StringBuilder();
String[] ret=new String[tabWidth+2];
for (int i = 0; i <= tabWidth; i++) {
if (isSpacesForTabs()) {
for (int j = 0; j + i < tabWidth; j++) {
prefix.append(' ');
}
if (i != 0) {
prefix.append('\t');
}
} else {
for (int j = 0; j < i; j++) {
prefix.append(' ');
}
if (i != tabWidth) {
prefix.append('\t');
}
}
ret[i]=prefix.toString();
prefix.setLength( 0 );
}
ret[tabWidth+1]=""; //$NON-NLS-1$
return ret;
}
@Override
public IQuickAssistAssistant getQuickAssistAssistant(final ISourceViewer sourceViewer ) {
QuickAssistAssistant qaa=new QuickAssistAssistant();
qaa.setQuickAssistProcessor( new QuickAssistProcessor() );
return qaa;
}
@Override
public IReconciler getReconciler( final ISourceViewer sourceViewer ) {
IReconciler result = null;
// the editor may be null if this configuration is used in a preview
// (source viewer without editor)
if( editor != null ) {
IReconcilingStrategy strategySpell = new HaskellReconcilingStrategy( editor , sourceViewer,true);
IReconcilingStrategy strategyNoSpell = new HaskellReconcilingStrategy( editor , sourceViewer,false);
//MonoReconciler mr = new MonoReconciler( strategy, false );
//mr.setProgressMonitor( new NullProgressMonitor() );
//mr.setDelay( 500 );
Reconciler r=new Reconciler();
r.setReconcilingStrategy( strategyNoSpell, IDocument.DEFAULT_CONTENT_TYPE );
r.setReconcilingStrategy( strategySpell, HaskellEditor.TEXT_CONTENTTYPE );
result=r;
}
return result;
}
// helping methods
// ////////////////
private IPreferenceStore getPreferenceStore() {
if (prefStore!=null){
return prefStore;
}
return HaskellUIPlugin.getDefault().getPreferenceStore();
}
private boolean isSpacesForTabs() {
//String key = IEditorPreferenceNames.EDITOR_SPACES_FOR_TABS;
//return getPreferenceStore().getBoolean( key );
return true; // too problematic otherwise
}
// private boolean isLatexLiterate() {
// boolean result = false;
// if( editor != null && editor.getEditorInput() instanceof IFileEditorInput ) {
// IFileEditorInput fei = ( IFileEditorInput )editor.getEditorInput();
// IFile file = fei.getFile();
// try {
// if( file != null && file.getContentDescription() != null ) {
// QualifiedName name = LiterateContentDescriber.STYLE;
// Object property = file.getContentDescription().getProperty( name );
// result = LiterateContentDescriber.LATEX.equals( property );
// }
// } catch( final CoreException cex ) {
// HaskellUIPlugin.log( cex );
// }
// }
// return result;
// }
}