/******************************************************************************* * Copyright (c) 2005, 2010 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: * IBM Corporation - initial API and implementation * QNX Software System * Anton Leherbauer (Wind River Systems) * Sergey Prigogin (Google) * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.ui.text; import java.util.Arrays; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.AbstractInformationControlManager; import org.eclipse.jface.text.DefaultInformationControl; import org.eclipse.jface.text.DefaultTextDoubleClickStrategy; 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.ITextDoubleClickStrategy; import org.eclipse.jface.text.ITextHover; import org.eclipse.jface.text.ITextViewerExtension2; import org.eclipse.jface.text.contentassist.ContentAssistant; import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.contentassist.IContentAssistant; import org.eclipse.jface.text.formatter.IContentFormatter; import org.eclipse.jface.text.formatter.MultiPassContentFormatter; 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.quickassist.IQuickAssistAssistant; import org.eclipse.jface.text.reconciler.IReconciler; import org.eclipse.jface.text.reconciler.MonoReconciler; import org.eclipse.jface.text.rules.DefaultDamagerRepairer; import org.eclipse.jface.text.rules.RuleBasedScanner; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.IAnnotationHover; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IPathEditorInput; import org.eclipse.ui.editors.text.ILocationProvider; import org.eclipse.ui.editors.text.TextSourceViewerConfiguration; import org.eclipse.ui.ide.ResourceUtil; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.gnu.cpp.GPPLanguage; import org.eclipse.cdt.core.formatter.DefaultCodeFormatterConstants; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ICLanguageKeywords; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.LanguageManager; import org.eclipse.cdt.ui.CElementContentProvider; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.ILanguageUI; import org.eclipse.cdt.ui.text.doctools.DefaultMultilineCommentAutoEditStrategy; import org.eclipse.cdt.ui.text.doctools.IDocCommentOwner; import org.eclipse.cdt.ui.text.doctools.IDocCommentViewerConfiguration; import org.eclipse.cdt.internal.core.model.ProgressMonitorAndCanceler; import org.eclipse.cdt.internal.corext.util.CodeFormatterUtil; import org.eclipse.cdt.internal.ui.editor.CDocumentProvider; import org.eclipse.cdt.internal.ui.text.CAutoIndentStrategy; import org.eclipse.cdt.internal.ui.text.CCodeScanner; import org.eclipse.cdt.internal.ui.text.CCommentScanner; import org.eclipse.cdt.internal.ui.text.CCompositeReconcilingStrategy; import org.eclipse.cdt.internal.ui.text.CDoubleClickSelector; import org.eclipse.cdt.internal.ui.text.CFormattingStrategy; import org.eclipse.cdt.internal.ui.text.COutlineInformationControl; import org.eclipse.cdt.internal.ui.text.CPreprocessorScanner; import org.eclipse.cdt.internal.ui.text.CPresentationReconciler; import org.eclipse.cdt.internal.ui.text.CReconciler; import org.eclipse.cdt.internal.ui.text.CStringAutoIndentStrategy; import org.eclipse.cdt.internal.ui.text.CStringDoubleClickSelector; import org.eclipse.cdt.internal.ui.text.HTMLAnnotationHover; import org.eclipse.cdt.internal.ui.text.PartitionDamager; import org.eclipse.cdt.internal.ui.text.SingleTokenCScanner; import org.eclipse.cdt.internal.ui.text.TokenStore; import org.eclipse.cdt.internal.ui.text.c.hover.CEditorTextHoverDescriptor; import org.eclipse.cdt.internal.ui.text.c.hover.CEditorTextHoverProxy; import org.eclipse.cdt.internal.ui.text.c.hover.CInformationProvider; import org.eclipse.cdt.internal.ui.text.c.hover.CMacroExpansionExplorationControl; import org.eclipse.cdt.internal.ui.text.c.hover.CMacroExpansionInformationProvider; import org.eclipse.cdt.internal.ui.text.contentassist.CContentAssistProcessor; import org.eclipse.cdt.internal.ui.text.contentassist.ContentAssistPreference; import org.eclipse.cdt.internal.ui.text.correction.CCorrectionAssistant; import org.eclipse.cdt.internal.ui.text.doctools.DocCommentOwnerManager; import org.eclipse.cdt.internal.ui.typehierarchy.THInformationControl; import org.eclipse.cdt.internal.ui.typehierarchy.THInformationProvider; /** * Configuration for a <code>SourceViewer</code> which shows C/C++ code. * <p> * This class may be instantiated and subclassed by clients. * </p> * * @since 5.1 */ public class CSourceViewerConfiguration extends TextSourceViewerConfiguration { protected ITextEditor fTextEditor; /** * The document partitioning. */ protected String fDocumentPartitioning; /** * The code scanner. */ protected AbstractCScanner fCodeScanner; /** * The C multi-line comment scanner. */ protected ICTokenScanner fMultilineCommentScanner; /** * The C single-line comment scanner. */ protected ICTokenScanner fSinglelineCommentScanner; /** * The C multi-line doc comment scanner. */ protected ICTokenScanner fMultilineDocCommentScanner; /** * The C single-line doc comment scanner. */ protected ICTokenScanner fSinglelineDocCommentScanner; /** * The C string scanner. */ protected AbstractCScanner fStringScanner; /** * The preprocessor scanner. */ protected AbstractCScanner fPreprocessorScanner; /** * The color manager. */ protected IColorManager fColorManager; /** * Creates a new C source viewer configuration for viewers in the given editor * using the given preference store, the color manager and the specified document partitioning. * * @param colorManager the color manager * @param preferenceStore the preference store, can be read-only * @param editor the editor in which the configured viewer(s) will reside, or <code>null</code> if none * @param partitioning the document partitioning for this configuration, or <code>null</code> for the default partitioning */ public CSourceViewerConfiguration(IColorManager colorManager, IPreferenceStore preferenceStore, ITextEditor editor, String partitioning) { super(preferenceStore); fColorManager= colorManager; fTextEditor= editor; fDocumentPartitioning= partitioning; initializeScanners(); } /** * Returns the C string scanner for this configuration. * * @return the C string scanner */ protected RuleBasedScanner getStringScanner() { return fStringScanner; } /** * Returns the preprocessor scanner for this configuration. * * @return the preprocessor scanner */ protected RuleBasedScanner getPreprocessorScanner(ILanguage language) { if (fPreprocessorScanner != null) { return fPreprocessorScanner; } AbstractCScanner scanner= null; ICLanguageKeywords keywords = language == null ? null : (ICLanguageKeywords) language.getAdapter(ICLanguageKeywords.class); if (keywords != null) { scanner = new CPreprocessorScanner(getTokenStoreFactory(), keywords); } if (scanner == null) { keywords = (ICLanguageKeywords) GPPLanguage.getDefault().getAdapter(ICLanguageKeywords.class); scanner= new CPreprocessorScanner(getTokenStoreFactory(), keywords); } fPreprocessorScanner= scanner; return fPreprocessorScanner; } /** * Returns the color manager for this configuration. * * @return the color manager */ protected IColorManager getColorManager() { return fColorManager; } /** * Returns the editor in which the configured viewer(s) will reside. * * @return the enclosing editor */ public ITextEditor getEditor() { return fTextEditor; } /** * Creates outline presenter. * @return Presenter with outline view. */ public IInformationPresenter getOutlinePresenter(ISourceViewer sourceViewer) { final IInformationControlCreator outlineControlCreator = getOutlineControlCreator(); final InformationPresenter presenter = new InformationPresenter(outlineControlCreator); presenter.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)); presenter.setAnchor(AbstractInformationControlManager.ANCHOR_GLOBAL); final IInformationProvider provider = new CElementContentProvider(getEditor()); String[] contentTypes= getConfiguredContentTypes(sourceViewer); for (int i= 0; i < contentTypes.length; i++) presenter.setInformationProvider(provider, contentTypes[i]); presenter.setSizeConstraints(50, 20, true, false); return presenter; } /** * Creates type hierarchy presenter. * @return Presenter with type hierarchy view. */ public IInformationPresenter getHierarchyPresenter(ISourceViewer sourceViewer) { final IInformationControlCreator hierarchyControlCreator = getHierarchyControlCreator(); final InformationPresenter presenter = new InformationPresenter(hierarchyControlCreator); presenter.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)); presenter.setAnchor(AbstractInformationControlManager.ANCHOR_GLOBAL); final IInformationProvider provider = new THInformationProvider(getEditor()); String[] contentTypes= getConfiguredContentTypes(sourceViewer); for (int i= 0; i < contentTypes.length; i++) presenter.setInformationProvider(provider, contentTypes[i]); presenter.setSizeConstraints(50, 20, true, false); return presenter; } /** * Initializes language independent scanners. */ protected void initializeScanners() { fStringScanner= new SingleTokenCScanner(getTokenStoreFactory(), ICColorConstants.C_STRING); fMultilineCommentScanner= new CCommentScanner(getTokenStoreFactory(), ICColorConstants.C_MULTI_LINE_COMMENT); fSinglelineCommentScanner= new CCommentScanner(getTokenStoreFactory(), ICColorConstants.C_SINGLE_LINE_COMMENT); } /** * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getPresentationReconciler(org.eclipse.jface.text.source.ISourceViewer) */ @Override public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) { CPresentationReconciler reconciler= new CPresentationReconciler(); reconciler.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)); ILanguage language= getLanguage(); RuleBasedScanner scanner = getCodeScanner(language); DefaultDamagerRepairer dr= new DefaultDamagerRepairer(scanner); reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE); reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE); dr= new DefaultDamagerRepairer(getSinglelineCommentScanner()); reconciler.setDamager(dr, ICPartitions.C_SINGLE_LINE_COMMENT); reconciler.setRepairer(dr, ICPartitions.C_SINGLE_LINE_COMMENT); dr= new DefaultDamagerRepairer(getMultilineCommentScanner()); reconciler.setDamager(dr, ICPartitions.C_MULTI_LINE_COMMENT); reconciler.setRepairer(dr, ICPartitions.C_MULTI_LINE_COMMENT); ICTokenScanner docCommentSingleScanner= getSinglelineDocCommentScanner(getProject()); if(docCommentSingleScanner!=null) { dr= new DefaultDamagerRepairer(docCommentSingleScanner); reconciler.setDamager(dr, ICPartitions.C_SINGLE_LINE_DOC_COMMENT); reconciler.setRepairer(dr, ICPartitions.C_SINGLE_LINE_DOC_COMMENT); } ICTokenScanner docCommentMultiScanner= getMultilineDocCommentScanner(getProject()); if(docCommentMultiScanner!=null) { dr= new DefaultDamagerRepairer(docCommentMultiScanner); reconciler.setDamager(dr, ICPartitions.C_MULTI_LINE_DOC_COMMENT); reconciler.setRepairer(dr, ICPartitions.C_MULTI_LINE_DOC_COMMENT); } dr= new DefaultDamagerRepairer(getStringScanner()); reconciler.setDamager(dr, ICPartitions.C_STRING); reconciler.setRepairer(dr, ICPartitions.C_STRING); dr= new DefaultDamagerRepairer(getStringScanner()); reconciler.setDamager(dr, ICPartitions.C_CHARACTER); reconciler.setRepairer(dr, ICPartitions.C_CHARACTER); dr= new DefaultDamagerRepairer(getPreprocessorScanner(language)); reconciler.setDamager(new PartitionDamager(), ICPartitions.C_PREPROCESSOR); reconciler.setRepairer(dr, ICPartitions.C_PREPROCESSOR); return reconciler; } /** * Returns the C multi-line comment scanner for this configuration. * * @return the C multi-line comment scanner */ protected ICTokenScanner getMultilineCommentScanner() { return fMultilineCommentScanner; } /** * Returns the C single-line comment scanner for this configuration. * * @return the C single-line comment scanner */ protected ICTokenScanner getSinglelineCommentScanner() { return fSinglelineCommentScanner; } /** * Returns the C multi-line doc comment scanner for this configuration. * * @return the C multi-line doc comment scanner */ protected ICTokenScanner getMultilineDocCommentScanner(IResource resource) { if (fMultilineDocCommentScanner == null) { if (resource == null) { resource= ResourcesPlugin.getWorkspace().getRoot(); } IDocCommentViewerConfiguration owner= DocCommentOwnerManager.getInstance().getCommentOwner(resource).getMultilineConfiguration(); fMultilineDocCommentScanner= owner.createCommentScanner(getTokenStoreFactory()); if (fMultilineDocCommentScanner == null) { // fallback: normal comment highlighting fMultilineDocCommentScanner= fMultilineCommentScanner; } } return fMultilineDocCommentScanner; } /** * Returns the C single-line doc comment scanner for this configuration. * * @return the C single-line doc comment scanner */ protected ICTokenScanner getSinglelineDocCommentScanner(IResource resource) { if (fSinglelineDocCommentScanner == null) { if (resource == null) { resource= ResourcesPlugin.getWorkspace().getRoot(); } IDocCommentViewerConfiguration owner= DocCommentOwnerManager.getInstance().getCommentOwner(resource).getSinglelineConfiguration(); fSinglelineDocCommentScanner= owner.createCommentScanner(getTokenStoreFactory()); if (fSinglelineDocCommentScanner == null) { // fallback: normal comment highlighting fSinglelineDocCommentScanner= fSinglelineCommentScanner; } } return fSinglelineDocCommentScanner; } /** * @return the code scanner for the given language */ protected RuleBasedScanner getCodeScanner(ILanguage language) { if (fCodeScanner != null) { return fCodeScanner; } RuleBasedScanner scanner= null; if(language != null) { ICLanguageKeywords keywords = (ICLanguageKeywords) language.getAdapter(ICLanguageKeywords.class); if(keywords != null) { scanner = new CCodeScanner(getTokenStoreFactory(), keywords); } else { ILanguageUI languageUI = (ILanguageUI)language.getAdapter(ILanguageUI.class); if (languageUI != null) scanner = languageUI.getCodeScanner(); } } if (scanner == null) { scanner = new CCodeScanner(getTokenStoreFactory(), GPPLanguage.getDefault()); } if (scanner instanceof AbstractCScanner) { fCodeScanner= (AbstractCScanner)scanner; } return scanner; } /* * @see SourceViewerConfiguration#getContentAssistant(ISourceViewer) */ @Override public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { if (getEditor() == null) { return null; } ContentAssistant assistant = new ContentAssistant(); assistant.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)); assistant.setRestoreCompletionProposalSize(getSettings("completion_proposal_size")); //$NON-NLS-1$ IContentAssistProcessor processor = new CContentAssistProcessor(getEditor(), assistant, IDocument.DEFAULT_CONTENT_TYPE); assistant.setContentAssistProcessor(processor, IDocument.DEFAULT_CONTENT_TYPE); processor = new CContentAssistProcessor(getEditor(), assistant, ICPartitions.C_MULTI_LINE_COMMENT); assistant.setContentAssistProcessor(processor, ICPartitions.C_MULTI_LINE_COMMENT); processor = new CContentAssistProcessor(getEditor(), assistant, ICPartitions.C_SINGLE_LINE_COMMENT); assistant.setContentAssistProcessor(processor, ICPartitions.C_SINGLE_LINE_COMMENT); processor = new CContentAssistProcessor(getEditor(), assistant, ICPartitions.C_MULTI_LINE_DOC_COMMENT); assistant.setContentAssistProcessor(processor, ICPartitions.C_MULTI_LINE_DOC_COMMENT); processor = new CContentAssistProcessor(getEditor(), assistant, ICPartitions.C_SINGLE_LINE_DOC_COMMENT); assistant.setContentAssistProcessor(processor, ICPartitions.C_SINGLE_LINE_DOC_COMMENT); processor = new CContentAssistProcessor(getEditor(), assistant, ICPartitions.C_STRING); assistant.setContentAssistProcessor(processor, ICPartitions.C_STRING); processor = new CContentAssistProcessor(getEditor(), assistant, ICPartitions.C_PREPROCESSOR); assistant.setContentAssistProcessor(processor, ICPartitions.C_PREPROCESSOR); ContentAssistPreference.configure(assistant, fPreferenceStore); assistant.setProposalPopupOrientation(IContentAssistant.PROPOSAL_OVERLAY); assistant.setContextInformationPopupOrientation(IContentAssistant.CONTEXT_INFO_ABOVE); assistant.setInformationControlCreator(getInformationControlCreator(sourceViewer)); return assistant; } /** * Returns the settings for the given section. * * @param sectionName the section name * @return the settings * @since 4.0 */ protected IDialogSettings getSettings(String sectionName) { IDialogSettings settings= CUIPlugin.getDefault().getDialogSettings().getSection(sectionName); if (settings == null) settings= CUIPlugin.getDefault().getDialogSettings().addNewSection(sectionName); return settings; } /* * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getQuickAssistAssistant(org.eclipse.jface.text.source.ISourceViewer) * @since 5.0 */ @Override public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer) { if (getEditor() != null) return new CCorrectionAssistant(getEditor()); return null; } /* * @see org.eclipse.ui.editors.text.TextSourceViewerConfiguration#getReconciler(org.eclipse.jface.text.source.ISourceViewer) */ @Override public IReconciler getReconciler(ISourceViewer sourceViewer) { if (fTextEditor != null) { //Delay changed and non-incremental reconciler used due to //PR 130089 CCompositeReconcilingStrategy strategy= new CCompositeReconcilingStrategy(sourceViewer, fTextEditor, getConfiguredDocumentPartitioning(sourceViewer)); MonoReconciler reconciler= new CReconciler(fTextEditor, strategy); reconciler.setIsIncrementalReconciler(false); reconciler.setProgressMonitor(new ProgressMonitorAndCanceler()); reconciler.setDelay(500); return reconciler; } return null; } /* * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getAutoEditStrategies(org.eclipse.jface.text.source.ISourceViewer, java.lang.String) */ @Override public IAutoEditStrategy[] getAutoEditStrategies(ISourceViewer sourceViewer, String contentType) { String partitioning= getConfiguredDocumentPartitioning(sourceViewer); IDocCommentOwner owner= DocCommentOwnerManager.getInstance().getCommentOwner(getProject()); IAutoEditStrategy single= owner.getSinglelineConfiguration().createAutoEditStrategy(); IAutoEditStrategy multi= owner.getMultilineConfiguration().createAutoEditStrategy(); IAutoEditStrategy[] NONE= new IAutoEditStrategy[0]; if (ICPartitions.C_MULTI_LINE_COMMENT.equals(contentType)) return new IAutoEditStrategy[] { new DefaultMultilineCommentAutoEditStrategy() }; if (ICPartitions.C_SINGLE_LINE_DOC_COMMENT.equals(contentType)) return single!=null ? new IAutoEditStrategy[] {single} : NONE; else if (ICPartitions.C_MULTI_LINE_DOC_COMMENT.equals(contentType)) return multi!=null? new IAutoEditStrategy[] {multi} : NONE; else if (ICPartitions.C_STRING.equals(contentType)) return new IAutoEditStrategy[] { /*new SmartSemicolonAutoEditStrategy(partitioning),*/ new CStringAutoIndentStrategy(partitioning, getCProject()) }; else return new IAutoEditStrategy[] { new CAutoIndentStrategy(partitioning, getCProject()) }; } /** * @see SourceViewerConfiguration#getDoubleClickStrategy(ISourceViewer, String) */ @Override public ITextDoubleClickStrategy getDoubleClickStrategy(ISourceViewer sourceViewer, String contentType) { if (ICPartitions.C_MULTI_LINE_COMMENT.equals(contentType) || ICPartitions.C_SINGLE_LINE_COMMENT.equals(contentType)) { return new DefaultTextDoubleClickStrategy(); } else if (ICPartitions.C_SINGLE_LINE_DOC_COMMENT.equals(contentType)) { IDocCommentOwner owner= DocCommentOwnerManager.getInstance().getCommentOwner(getProject()); ITextDoubleClickStrategy single= owner.getSinglelineConfiguration().createDoubleClickStrategy(); return single != null ? single : new DefaultTextDoubleClickStrategy(); } else if(ICPartitions.C_MULTI_LINE_DOC_COMMENT.equals(contentType)) { IDocCommentOwner owner= DocCommentOwnerManager.getInstance().getCommentOwner(getProject()); ITextDoubleClickStrategy multi= owner.getMultilineConfiguration().createDoubleClickStrategy(); return multi!=null ? multi : new DefaultTextDoubleClickStrategy(); } else if (ICPartitions.C_STRING.equals(contentType) || ICPartitions.C_CHARACTER.equals(contentType)) { return new CStringDoubleClickSelector(getConfiguredDocumentPartitioning(sourceViewer)); } else if (ICPartitions.C_PREPROCESSOR.equals(contentType)) { return new CStringDoubleClickSelector(getConfiguredDocumentPartitioning(sourceViewer), new CDoubleClickSelector()); } return new CDoubleClickSelector(); } /** * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getDefaultPrefixes(ISourceViewer, String) */ @Override public String[] getDefaultPrefixes(ISourceViewer sourceViewer, String contentType) { return new String[] { "//", "//!", "" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } /* * @see SourceViewerConfiguration#getIndentPrefixes(ISourceViewer, String) */ @Override public String[] getIndentPrefixes(ISourceViewer sourceViewer, String contentType) { ICProject project= getCProject(); final int tabWidth= CodeFormatterUtil.getTabWidth(project); final int indentWidth= CodeFormatterUtil.getIndentWidth(project); boolean allowTabs= tabWidth <= indentWidth; String indentMode; if (project == null) indentMode= CCorePlugin.getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR); else indentMode= project.getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, true); boolean useSpaces= CCorePlugin.SPACE.equals(indentMode) || DefaultCodeFormatterConstants.MIXED.equals(indentMode); // assert allowTabs || useSpaces; if (!allowTabs) return new String[] { getStringWithSpaces(indentWidth), "" }; //$NON-NLS-1$ else if (!useSpaces) return getIndentPrefixesForTab(tabWidth); else return getIndentPrefixesForSpaces(tabWidth); } /** * Computes and returns the indent prefixes for space indentation * and the given <code>tabWidth</code>. * * @param tabWidth the display tab width * @return the indent prefixes * @see #getIndentPrefixes(ISourceViewer, String) */ protected String[] getIndentPrefixesForSpaces(int tabWidth) { String[] indentPrefixes= new String[tabWidth + 2]; indentPrefixes[0]= getStringWithSpaces(tabWidth); for (int i= 0; i < tabWidth; i++) { String spaces= getStringWithSpaces(i); if (i < tabWidth) indentPrefixes[i+1]= spaces + '\t'; else indentPrefixes[i+1]= new String(spaces); } indentPrefixes[tabWidth + 1]= ""; //$NON-NLS-1$ return indentPrefixes; } /** * Creates and returns a String with <code>count</code> spaces. * * @param count the space count * @return the string with the spaces */ protected static String getStringWithSpaces(int count) { char[] spaceChars= new char[count]; Arrays.fill(spaceChars, ' '); return new String(spaceChars); } /** * Returns the ICProject associated with this CSourceViewerConfiguration, or null if * no ICProject could be determined * @return the ICProject or <code>null</code> */ protected ICProject getCProject() { ITextEditor editor= getEditor(); if (editor == null) return null; ICElement element= null; IEditorInput input= editor.getEditorInput(); IDocumentProvider provider= editor.getDocumentProvider(); if (provider instanceof CDocumentProvider) { CDocumentProvider cudp= (CDocumentProvider) provider; element= cudp.getWorkingCopy(input); } if (element == null) return null; return element.getCProject(); } /* * @see SourceViewerConfiguration#getTabWidth(ISourceViewer) */ @Override public int getTabWidth(ISourceViewer sourceViewer) { return CodeFormatterUtil.getTabWidth(getCProject()); } /** * Returns the configured indent width for this viewer. * @param sourceViewer * @return the indent width */ public int getIndentWidth(ISourceViewer sourceViewer) { return CodeFormatterUtil.getIndentWidth(getCProject()); } /** * Returns whether spaces should be used exclusively for indentation. * * @param sourceViewer * @return <code>true</code> if spaces should be used for indentation */ public boolean useSpacesOnly(ISourceViewer sourceViewer) { ICProject project= getCProject(); String option; if (project == null) option= CCorePlugin.getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR); else option= project.getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, true); return CCorePlugin.SPACE.equals(option); } /** * @see SourceViewerConfiguration#getAnnotationHover(ISourceViewer) */ @Override public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer) { return new HTMLAnnotationHover() { @Override protected boolean isIncluded(Annotation annotation) { return isShowInVerticalRuler(annotation); } }; } /* * @see SourceViewerConfiguration#getConfiguredTextHoverStateMasks(ISourceViewer, String) * @since 2.1 */ @Override public int[] getConfiguredTextHoverStateMasks(ISourceViewer sourceViewer, String contentType) { CEditorTextHoverDescriptor[] hoverDescs= CUIPlugin.getDefault().getCEditorTextHoverDescriptors(); int stateMasks[]= new int[hoverDescs.length]; int stateMasksLength= 0; for (CEditorTextHoverDescriptor hoverDesc : hoverDescs) { if (hoverDesc.isEnabled()) { int j= 0; int stateMask= hoverDesc.getStateMask(); while (j < stateMasksLength) { if (stateMasks[j] == stateMask) break; j++; } if (j == stateMasksLength) stateMasks[stateMasksLength++]= stateMask; } } if (stateMasksLength == hoverDescs.length) return stateMasks; int[] shortenedStateMasks= new int[stateMasksLength]; System.arraycopy(stateMasks, 0, shortenedStateMasks, 0, stateMasksLength); return shortenedStateMasks; } /* * @see SourceViewerConfiguration#getTextHover(ISourceViewer, String, int) * @since 2.1 */ @Override public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType, int stateMask) { CEditorTextHoverDescriptor[] hoverDescs= CUIPlugin.getDefault().getCEditorTextHoverDescriptors(); int i= 0; while (i < hoverDescs.length) { if (hoverDescs[i].isEnabled() && hoverDescs[i].getStateMask() == stateMask) return new CEditorTextHoverProxy(hoverDescs[i], getEditor()); i++; } return null; } /* * @see SourceViewerConfiguration#getTextHover(ISourceViewer, String) */ @Override public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) { return getTextHover(sourceViewer, contentType, ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK); } /** * @see SourceViewerConfiguration#getConfiguredContentTypes(ISourceViewer) */ @Override public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) { return new String[] { IDocument.DEFAULT_CONTENT_TYPE, ICPartitions.C_MULTI_LINE_COMMENT, ICPartitions.C_SINGLE_LINE_COMMENT, ICPartitions.C_STRING, ICPartitions.C_CHARACTER, ICPartitions.C_PREPROCESSOR, ICPartitions.C_SINGLE_LINE_DOC_COMMENT, ICPartitions.C_MULTI_LINE_DOC_COMMENT }; } /** * @see SourceViewerConfiguration#getContentFormatter(ISourceViewer) */ @Override public IContentFormatter getContentFormatter(ISourceViewer sourceViewer) { final MultiPassContentFormatter formatter = new MultiPassContentFormatter(getConfiguredDocumentPartitioning(sourceViewer), IDocument.DEFAULT_CONTENT_TYPE); formatter.setMasterStrategy(new CFormattingStrategy()); return formatter; } public boolean affectsBehavior(PropertyChangeEvent event) { if ((fMultilineDocCommentScanner != null && fMultilineDocCommentScanner.affectsBehavior(event)) || (fSinglelineDocCommentScanner != null && fSinglelineDocCommentScanner.affectsBehavior(event)) || fMultilineCommentScanner.affectsBehavior(event) || fSinglelineCommentScanner.affectsBehavior(event) || fStringScanner.affectsBehavior(event)) { return true; } if (fCodeScanner != null && fCodeScanner.affectsBehavior(event)) { return true; } if (fPreprocessorScanner != null && fPreprocessorScanner.affectsBehavior(event)) { return true; } return false; } /* * @see SourceViewerConfiguration#getHoverControlCreator(ISourceViewer) * @since 2.0 */ @Override public IInformationControlCreator getInformationControlCreator(ISourceViewer sourceViewer) { return new IInformationControlCreator() { public IInformationControl createInformationControl(Shell parent) { return new DefaultInformationControl(parent, false); } }; } /** * Returns the information presenter control creator. The creator is a factory creating the * presenter controls for the given source viewer. This implementation always returns a creator * for <code>DefaultInformationControl</code> instances. * * @param sourceViewer the source viewer to be configured by this configuration * @return an information control creator * @since 5.0 */ protected IInformationControlCreator getInformationPresenterControlCreator(ISourceViewer sourceViewer) { return new IInformationControlCreator() { public IInformationControl createInformationControl(Shell parent) { return new DefaultInformationControl(parent, true); } }; } /* * @see SourceViewerConfiguration#getInformationPresenter(ISourceViewer) * @since 2.0 */ @Override public IInformationPresenter getInformationPresenter(ISourceViewer sourceViewer) { InformationPresenter presenter= new InformationPresenter(getInformationPresenterControlCreator(sourceViewer)); presenter.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)); // Register information provider IInformationProvider provider= new CInformationProvider(getEditor()); String[] contentTypes= getConfiguredContentTypes(sourceViewer); for (String contentType : contentTypes) presenter.setInformationProvider(provider, contentType); presenter.setSizeConstraints(60, 10, true, true); return presenter; } /** * 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 */ public boolean affectsTextPresentation(PropertyChangeEvent event) { return affectsBehavior(event); } /** * 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 CSourceViewerConfiguration#CSourceViewerConfiguration(IColorManager, IPreferenceStore, ITextEditor, String) */ public void handlePropertyChangeEvent(PropertyChangeEvent event) { if (fCodeScanner != null && fCodeScanner.affectsBehavior(event)) fCodeScanner.adaptToPreferenceChange(event); if (fMultilineDocCommentScanner!=null && fMultilineDocCommentScanner.affectsBehavior(event)) fMultilineDocCommentScanner.adaptToPreferenceChange(event); if (fSinglelineDocCommentScanner!=null && fSinglelineDocCommentScanner.affectsBehavior(event)) fSinglelineDocCommentScanner.adaptToPreferenceChange(event); if (fMultilineCommentScanner.affectsBehavior(event)) fMultilineCommentScanner.adaptToPreferenceChange(event); if (fSinglelineCommentScanner.affectsBehavior(event)) fSinglelineCommentScanner.adaptToPreferenceChange(event); if (fStringScanner.affectsBehavior(event)) fStringScanner.adaptToPreferenceChange(event); if (fPreprocessorScanner != null && fPreprocessorScanner.affectsBehavior(event)) fPreprocessorScanner.adaptToPreferenceChange(event); } /* * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getConfiguredDocumentPartitioning(org.eclipse.jface.text.source.ISourceViewer) */ @Override public String getConfiguredDocumentPartitioning(ISourceViewer sourceViewer) { if (fDocumentPartitioning != null) return fDocumentPartitioning; return super.getConfiguredDocumentPartitioning(sourceViewer); } /** * Creates control for outline presentation in editor. * @return Control. */ protected IInformationControlCreator getOutlineControlCreator() { final IInformationControlCreator conrolCreator = new IInformationControlCreator() { /** * @see org.eclipse.jface.text.IInformationControlCreator#createInformationControl(org.eclipse.swt.widgets.Shell) */ public IInformationControl createInformationControl(Shell parent) { int shellStyle= SWT.RESIZE; int treeStyle= SWT.V_SCROLL | SWT.H_SCROLL; return new COutlineInformationControl(parent, shellStyle, treeStyle); } }; return conrolCreator; } /** * Creates control for outline presentation in editor. * @return Control. */ protected IInformationControlCreator getHierarchyControlCreator() { final IInformationControlCreator conrolCreator = new IInformationControlCreator() { /** * @see org.eclipse.jface.text.IInformationControlCreator#createInformationControl(org.eclipse.swt.widgets.Shell) */ public IInformationControl createInformationControl(Shell parent) { int shellStyle= SWT.RESIZE; int treeStyle= SWT.V_SCROLL | SWT.H_SCROLL; return new THInformationControl(parent, shellStyle, treeStyle); } }; return conrolCreator; } protected ILanguage getLanguage() { if (fTextEditor == null) { return GPPLanguage.getDefault(); } ICElement element = CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(fTextEditor.getEditorInput()); if (element instanceof ITranslationUnit) { try { return ((ITranslationUnit)element).getLanguage(); } catch (CoreException e) { CUIPlugin.log(e); } } else { // compute the language from the plain editor input IContentType contentType = null; IEditorInput input = fTextEditor.getEditorInput(); IFile file = ResourceUtil.getFile(input); if (file != null) { contentType = CCorePlugin.getContentType(file.getProject(), file.getName()); } else if (input instanceof IPathEditorInput) { IPath path = ((IPathEditorInput)input).getPath(); contentType = CCorePlugin.getContentType(path.lastSegment()); } else { ILocationProvider locationProvider = (ILocationProvider)input.getAdapter(ILocationProvider.class); if (locationProvider != null) { IPath path = locationProvider.getPath(input); if (path != null) { contentType = CCorePlugin.getContentType(path.lastSegment()); } } } if (contentType != null) { return LanguageManager.getInstance().getLanguage(contentType); } } // fallback return GPPLanguage.getDefault(); } /** * Reset cached language dependent scanners. */ public void resetScanners() { fCodeScanner= null; fMultilineDocCommentScanner= null; fSinglelineDocCommentScanner= null; fPreprocessorScanner= null; } /** * Creates macro exploration presenter. * @param sourceViewer * @return Presenter with macro exploration view. * * @since 5.0 */ public IInformationPresenter getMacroExplorationPresenter(ISourceViewer sourceViewer) { final IInformationControlCreator controlCreator= getMacroExplorationControlCreator(); final InformationPresenter presenter = new InformationPresenter(controlCreator); presenter.setRestoreInformationControlBounds(getDialogSettings(CMacroExpansionExplorationControl.KEY_CONTROL_BOUNDS), true, true); presenter.setSizeConstraints(320, 120, true, false); presenter.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)); presenter.setAnchor(AbstractInformationControlManager.ANCHOR_GLOBAL); final IInformationProvider provider = new CMacroExpansionInformationProvider(getEditor()); String[] contentTypes= getConfiguredContentTypes(sourceViewer); for (int i= 0; i < contentTypes.length; i++) presenter.setInformationProvider(provider, contentTypes[i]); presenter.setSizeConstraints(50, 20, true, false); return presenter; } protected IDialogSettings getDialogSettings(String sectionName) { if (sectionName == null) { return null; } IDialogSettings settings= CUIPlugin.getDefault().getDialogSettings().getSection(sectionName); if (settings == null) { settings= CUIPlugin.getDefault().getDialogSettings().addNewSection(sectionName); } return settings; } /** * Creates control for macro exploration in editor. * @return Control. */ protected IInformationControlCreator getMacroExplorationControlCreator() { final IInformationControlCreator conrolCreator = new IInformationControlCreator() { public IInformationControl createInformationControl(Shell parent) { return new CMacroExpansionExplorationControl(parent); } }; return conrolCreator; } /** * @return the IProject associated with this CSourceViewerConfiguration, or null if * no IProject could be determined */ protected IProject getProject() { ICProject cproject= getCProject(); return cproject!=null ? cproject.getProject() :null; } protected ITokenStoreFactory getTokenStoreFactory() { return new ITokenStoreFactory() { public ITokenStore createTokenStore(String[] propertyColorNames) { return new TokenStore(getColorManager(), fPreferenceStore, propertyColorNames); } }; } /* * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getHyperlinkDetectorTargets(org.eclipse.jface.text.source.ISourceViewer) */ @Override protected Map<String, IAdaptable> getHyperlinkDetectorTargets(ISourceViewer sourceViewer) { @SuppressWarnings("unchecked") Map<String, IAdaptable> targets= super.getHyperlinkDetectorTargets(sourceViewer); targets.put("org.eclipse.cdt.ui.cCode", fTextEditor); //$NON-NLS-1$ return targets; } }