/******************************************************************************* * Copyright (c) 2005, 2016 IBM Corporation 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: * xored software, Inc. - initial API and implementation * xored software, Inc. - fix tab handling (Bug# 200024) (Alex Panchenko) *******************************************************************************/ package org.eclipse.dltk.ruby.internal.ui.text; import java.util.Map; import org.eclipse.core.runtime.Assert; import org.eclipse.dltk.internal.ui.editor.EditorUtility; import org.eclipse.dltk.internal.ui.editor.ScriptSourceViewer; import org.eclipse.dltk.internal.ui.text.ScriptElementProvider; import org.eclipse.dltk.ruby.internal.ui.text.completion.RubyCompletionProcessor; import org.eclipse.dltk.ruby.internal.ui.text.completion.RubyContentAssistPreference; import org.eclipse.dltk.ruby.internal.ui.typehierarchy.RubyHierarchyInformationControl; import org.eclipse.dltk.ui.text.AbstractScriptScanner; import org.eclipse.dltk.ui.text.IColorManager; import org.eclipse.dltk.ui.text.ScriptPresentationReconciler; import org.eclipse.dltk.ui.text.ScriptSourceViewerConfiguration; import org.eclipse.dltk.ui.text.completion.ContentAssistPreference; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.AbstractInformationControlManager; import org.eclipse.jface.text.IAutoEditStrategy; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.contentassist.ContentAssistant; import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.information.IInformationPresenter; import org.eclipse.jface.text.information.IInformationProvider; import org.eclipse.jface.text.information.InformationPresenter; import org.eclipse.jface.text.presentation.IPresentationReconciler; import org.eclipse.jface.text.presentation.PresentationReconciler; import org.eclipse.jface.text.rules.DefaultDamagerRepairer; import org.eclipse.jface.text.rules.ITokenScanner; import org.eclipse.jface.text.rules.RuleBasedScanner; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.texteditor.ITextEditor; public class RubySourceViewerConfiguration extends ScriptSourceViewerConfiguration { private RubyTextTools fTextTools; private RubyCodeScanner fCodeScanner; private AbstractScriptScanner fStringScanner; private AbstractScriptScanner fSingleQuoteStringScanner; private AbstractScriptScanner fCommentScanner; private AbstractScriptScanner fDocScanner; public RubySourceViewerConfiguration(IColorManager colorManager, IPreferenceStore preferenceStore, ITextEditor editor, String partitioning) { super(colorManager, preferenceStore, editor, partitioning); } @Override public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) { return IRubyPartitions.RUBY_PARTITION_TYPES; } @Override protected void initializeScanners() { Assert.isTrue(isNewSetup()); fCodeScanner = new RubyCodeScanner(getColorManager(), fPreferenceStore); fStringScanner = new RubyStringScanner(getColorManager(), fPreferenceStore); fSingleQuoteStringScanner = new RubySingleQuoteStringScanner( getColorManager(), fPreferenceStore); fCommentScanner = createCommentScanner( IRubyColorConstants.RUBY_SINGLE_LINE_COMMENT, IRubyColorConstants.RUBY_TODO_COMMENT); fDocScanner = new RubyDocScanner(getColorManager(), fPreferenceStore); } /** * @return <code>true</code> iff the new setup without text tools is in use. */ private boolean isNewSetup() { return fTextTools == null; } protected RuleBasedScanner getStringScanner() { return fStringScanner; } protected RuleBasedScanner getCommentScanner() { return fCommentScanner; } @Override public IPresentationReconciler getPresentationReconciler( ISourceViewer sourceViewer) { PresentationReconciler reconciler = new ScriptPresentationReconciler(); reconciler .setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)); DefaultDamagerRepairer dr = new DefaultDamagerRepairer(fCodeScanner); reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE); reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE); dr = new DefaultDamagerRepairer(getStringScanner()); reconciler.setDamager(dr, IRubyPartitions.RUBY_STRING); reconciler.setRepairer(dr, IRubyPartitions.RUBY_STRING); dr = new DefaultDamagerRepairer(getStringScanner()); reconciler.setDamager(dr, IRubyPartitions.RUBY_PERCENT_STRING); reconciler.setRepairer(dr, IRubyPartitions.RUBY_PERCENT_STRING); dr = new DefaultDamagerRepairer(getSingleQuoteStringScanner()); reconciler.setDamager(dr, IRubyPartitions.RUBY_SINGLE_QUOTE_STRING); reconciler.setRepairer(dr, IRubyPartitions.RUBY_SINGLE_QUOTE_STRING); dr = new DefaultDamagerRepairer(getDocScanner()); reconciler.setDamager(dr, IRubyPartitions.RUBY_DOC); reconciler.setRepairer(dr, IRubyPartitions.RUBY_DOC); dr = new DefaultDamagerRepairer(getCommentScanner()); reconciler.setDamager(dr, IRubyPartitions.RUBY_COMMENT); reconciler.setRepairer(dr, IRubyPartitions.RUBY_COMMENT); return reconciler; } private ITokenScanner getSingleQuoteStringScanner() { return fSingleQuoteStringScanner; } private ITokenScanner getDocScanner() { return fDocScanner; } /** * Adapts the behavior of the contained components to the change encoded in * the given event. * <p> * Clients are not allowed to call this method if the old setup with text * tools is in use. * </p> * * @param event * the event to which to adapt * @see RubySourceViewerConfiguration#ScriptSourceViewerConfiguration(IColorManager, * IPreferenceStore, ITextEditor, String) */ @Override public void handlePropertyChangeEvent(PropertyChangeEvent event) { Assert.isTrue(isNewSetup()); if (fCodeScanner.affectsBehavior(event)) fCodeScanner.adaptToPreferenceChange(event); if (fStringScanner.affectsBehavior(event)) fStringScanner.adaptToPreferenceChange(event); if (fSingleQuoteStringScanner.affectsBehavior(event)) fSingleQuoteStringScanner.adaptToPreferenceChange(event); if (fDocScanner.affectsBehavior(event)) fDocScanner.adaptToPreferenceChange(event); if (fCommentScanner.affectsBehavior(event)) fCommentScanner.adaptToPreferenceChange(event); } /** * Determines whether the preference change encoded by the given event * changes the behavior of one of its contained components. * * @param event * the event to be investigated * @return <code>true</code> if event causes a behavioral change * */ @Override public boolean affectsTextPresentation(PropertyChangeEvent event) { return fCodeScanner.affectsBehavior(event) || fStringScanner.affectsBehavior(event) || fSingleQuoteStringScanner.affectsBehavior(event) || fCommentScanner.affectsBehavior(event) || fDocScanner.affectsBehavior(event); } private IInformationControlCreator getHierarchyPresenterControlCreator( ISourceViewer sourceViewer) { return new IInformationControlCreator() { @Override public IInformationControl createInformationControl(Shell parent) { int shellStyle = SWT.RESIZE; int treeStyle = SWT.V_SCROLL | SWT.H_SCROLL; return new RubyHierarchyInformationControl(parent, shellStyle, treeStyle); } }; } @Override public IInformationPresenter getHierarchyPresenter( ScriptSourceViewer sourceViewer, boolean doCodeResolve) { // Do not create hierarchy presenter if there's no CU. if (getEditor() != null && getEditor().getEditorInput() != null && EditorUtility.getEditorInputModelElement(getEditor(), true) == null) return null; InformationPresenter presenter = new InformationPresenter( getHierarchyPresenterControlCreator(sourceViewer)); presenter .setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)); presenter.setAnchor(AbstractInformationControlManager.ANCHOR_GLOBAL); IInformationProvider provider = new ScriptElementProvider(getEditor(), doCodeResolve); presenter.setInformationProvider(provider, IDocument.DEFAULT_CONTENT_TYPE); presenter.setSizeConstraints(50, 20, true, false); return presenter; } @Override public IAutoEditStrategy[] getAutoEditStrategies( ISourceViewer sourceViewer, String contentType) { // // TODO: check contentType. think, do we really need it? :) String partitioning = getConfiguredDocumentPartitioning(sourceViewer); return new IAutoEditStrategy[] { new RubyAutoEditStrategy(partitioning) }; } @Override protected void alterContentAssistant(ContentAssistant assistant) { IContentAssistProcessor scriptProcessor = new RubyCompletionProcessor( getEditor(), assistant, IDocument.DEFAULT_CONTENT_TYPE); assistant.setContentAssistProcessor(scriptProcessor, IDocument.DEFAULT_CONTENT_TYPE); assistant.setContentAssistProcessor(scriptProcessor, IRubyPartitions.RUBY_SINGLE_QUOTE_STRING); assistant.setContentAssistProcessor(scriptProcessor, IRubyPartitions.RUBY_STRING); } @Override protected ContentAssistPreference getContentAssistPreference() { return RubyContentAssistPreference.getDefault(); } @Override protected Map getHyperlinkDetectorTargets(final ISourceViewer sourceViewer) { final Map targets = super.getHyperlinkDetectorTargets(sourceViewer); targets.put("org.eclipse.dltk.ruby.code", getEditor()); //$NON-NLS-1$ return targets; } }