/******************************************************************************* * Copyright (c) 2015, 2016 Pivotal, Inc. * 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: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.editor.support.yaml; import java.util.HashSet; import java.util.Set; import javax.inject.Provider; import org.dadacoalition.yedit.editor.YEditSourceViewerConfiguration; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.IDocument; 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.IContentAssistant; import org.eclipse.jface.text.reconciler.IReconciler; import org.eclipse.jface.text.reconciler.IReconcilingStrategy; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.DefaultAnnotationHover; import org.eclipse.jface.text.source.IAnnotationHover; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Shell; import org.springframework.ide.eclipse.editor.support.EditorSupportActivator; import org.springframework.ide.eclipse.editor.support.ForceableReconciler; import org.springframework.ide.eclipse.editor.support.completions.CompletionFactory; import org.springframework.ide.eclipse.editor.support.completions.ICompletionEngine; import org.springframework.ide.eclipse.editor.support.completions.ProposalProcessor; import org.springframework.ide.eclipse.editor.support.hover.HoverInfoProvider; import org.springframework.ide.eclipse.editor.support.hover.HoverInfoTextHover; import org.springframework.ide.eclipse.editor.support.reconcile.DefaultQuickfixContext; import org.springframework.ide.eclipse.editor.support.reconcile.QuickfixContext; import org.springframework.ide.eclipse.editor.support.reconcile.ReconcileProblemAnnotationHover; import org.springframework.ide.eclipse.editor.support.util.DefaultUserInteractions; import org.springframework.ide.eclipse.editor.support.yaml.ast.YamlASTProvider; import org.springframework.ide.eclipse.editor.support.yaml.hover.YamlHoverInfoProvider; import org.springframework.ide.eclipse.editor.support.yaml.structure.YamlStructureProvider; import org.yaml.snakeyaml.Yaml; /** * @author Kris De Volder */ public abstract class AbstractYamlSourceViewerConfiguration extends YEditSourceViewerConfiguration { private static final Set<String> ANNOTIONS_SHOWN_IN_TEXT = new HashSet<String>(); static { ANNOTIONS_SHOWN_IN_TEXT.add("org.eclipse.jdt.ui.warning"); ANNOTIONS_SHOWN_IN_TEXT.add("org.eclipse.jdt.ui.error"); } private static final Set<String> ANNOTIONS_SHOWN_IN_OVERVIEW_BAR = ANNOTIONS_SHOWN_IN_TEXT; //TODO: the ANNOTIONS_SHOWN_IN_TEXT and ANNOTIONS_SHOWN_IN_OVERVIEW_BAR should be replaced with // properly using preferences. An example of how to set this up can be found in the code // of the Java properties file editor. Roughly these things need to happen: // 1) use methods like 'isShownIntext' and 'isShownInOverviewRuler' which are defined in // our super class. // 2) initialize the super class with a preference store (simialr to how java properties file does it) // 3) To be able to do 2) it is necessary to add a constructor to YEditSourceViewerConfiguration which // accepts preference store and passes it to its super class. So this requires a patch to // YEdit source code. private Provider<Shell> shellProvider; private final String DIALOG_SETTINGS_KEY = this.getClass().getName(); private final YamlASTProvider astProvider = new YamlASTProvider(new Yaml()); private YamlCompletionEngine completionEngine; protected ForceableReconciler fReconciler; public AbstractYamlSourceViewerConfiguration(Provider<Shell> shellProvider) { this.shellProvider = shellProvider; } protected final IDialogSettings getDialogSettings() { IDialogSettings dialogSettings = getPluginDialogSettings(); IDialogSettings existing = dialogSettings.getSection(DIALOG_SETTINGS_KEY); if (existing!=null) { return existing; } IDialogSettings created = dialogSettings.addNewSection(DIALOG_SETTINGS_KEY); Point defaultPopupSize = getDefaultPopupSize(); if (defaultPopupSize!=null) { int suggestW = defaultPopupSize.x; int suggestH = defaultPopupSize.y; created.put(ContentAssistant.STORE_SIZE_X, suggestW); created.put(ContentAssistant.STORE_SIZE_Y, suggestH); } return created; } protected Point getDefaultPopupSize() { return null; } protected abstract IDialogSettings getPluginDialogSettings(); @Override public final IContentAssistant getContentAssistant(ISourceViewer viewer) { IContentAssistant _a = super.getContentAssistant(viewer); if (_a instanceof ContentAssistant) { ContentAssistant a = (ContentAssistant)_a; //IContentAssistProcessor processor = assistant.getContentAssistProcessor(IDocument.DEFAULT_CONTENT_TYPE); //if (processor!=null) { //TODO: don't overwrite existing processor but wrap it so // we combine our proposals with existing propopals //} a.setInformationControlCreator(getInformationControlCreator(viewer)); a.enableColoredLabels(true); a.enablePrefixCompletion(false); a.enableAutoInsert(true); a.enableAutoActivation(true); a.setRestoreCompletionProposalSize(getDialogSettings()); ProposalProcessor processor = new ProposalProcessor(getCompletionEngine()); a.setContentAssistProcessor(processor, IDocument.DEFAULT_CONTENT_TYPE); a.setSorter(CompletionFactory.SORTER); } return _a; } @Override public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType, int stateMask) { if (contentType.equals(IDocument.DEFAULT_CONTENT_TYPE) && ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK==stateMask) { ITextHover delegate = getTextAnnotationHover(sourceViewer); try { HoverInfoProvider hoverProvider = getHoverProvider(); if (hoverProvider!=null) { return new HoverInfoTextHover(sourceViewer, getHoverProvider(), delegate); } } catch (Exception e) { EditorSupportActivator.log(e); } return delegate; } else { return super.getTextHover(sourceViewer, contentType, stateMask); } } public final ICompletionEngine getCompletionEngine() { if (completionEngine==null) { completionEngine = new YamlCompletionEngine(getStructureProvider(), getAssistContextProvider()); } return completionEngine; } protected final HoverInfoProvider getHoverProvider() { return new YamlHoverInfoProvider(getAstProvider(), getStructureProvider(), getAssistContextProvider()); } protected final YamlASTProvider getAstProvider() { return astProvider; } @Override public final IReconciler getReconciler(ISourceViewer sourceViewer) { if (fReconciler==null) { fReconciler = createReconciler(sourceViewer); } return fReconciler; } @Override public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer) { return new DefaultAnnotationHover() { @Override protected boolean isIncluded(Annotation annotation) { return ANNOTIONS_SHOWN_IN_OVERVIEW_BAR.contains(annotation.getType()); } }; } protected ITextHover getTextAnnotationHover(ISourceViewer sourceViewer) { return new ReconcileProblemAnnotationHover(sourceViewer, getQuickfixContext(sourceViewer)); } protected Shell getShell() { return shellProvider.get(); } protected final QuickfixContext getQuickfixContext(ISourceViewer sourceViewer) { return new DefaultQuickfixContext( getPluginId(), getPreferencesStore(), sourceViewer, new DefaultUserInteractions(getShell()) ); } protected abstract String getPluginId(); protected abstract IPreferenceStore getPreferencesStore(); protected abstract YamlStructureProvider getStructureProvider(); protected abstract YamlAssistContextProvider getAssistContextProvider(); protected IReconcilingStrategy createReconcilerStrategy(ISourceViewer sourceViewer) { return null; } protected ForceableReconciler createReconciler(ISourceViewer sourceViewer) { //TODO: aplication.properties|yaml editors are overriding this. That should not be necessary. IReconcilingStrategy strategy = createReconcilerStrategy(sourceViewer); if (strategy!=null) { ForceableReconciler reconciler = new ForceableReconciler(strategy); reconciler.setDelay(500); return reconciler; } return null; } }