package org.jbehave.eclipse.editor.story; import java.lang.reflect.Field; import java.util.List; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.contentassist.IContentAssistant; import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; 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.source.IAnnotationHover; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.jbehave.eclipse.Activator; import org.jbehave.eclipse.JBehaveProject; import org.jbehave.eclipse.editor.story.completion.StepContentAssistant; import org.jbehave.eclipse.editor.story.scanner.AllInOneScanner; import org.jbehave.eclipse.editor.story.scanner.ExampleTableScanner; import org.jbehave.eclipse.editor.story.scanner.MetaScanner; import org.jbehave.eclipse.editor.story.scanner.NarrativeScanner; import org.jbehave.eclipse.editor.story.scanner.ScenarioScanner; import org.jbehave.eclipse.editor.story.scanner.SingleTokenScanner; import org.jbehave.eclipse.editor.story.scanner.StepScanner; import org.jbehave.eclipse.editor.text.TextAttributeProvider; import org.jbehave.eclipse.editor.text.style.TextStyle; public class StoryConfiguration extends SourceViewerConfiguration { private ITokenScanner stepScanner; private ITokenScanner defaultScanner; private ITokenScanner commentScanner; private ITokenScanner scenarioScanner; private ITokenScanner narrativeScanner; private ITokenScanner miscScanner; private ITokenScanner exampleTableScanner; private TextAttributeProvider textAttributeProvider; private StoryEditor storyEditor; private PresentationReconciler reconciler; private Object reconcilerInternalListener; public StoryConfiguration(StoryEditor storyEditor, TextAttributeProvider textAttributeProvider) { this.storyEditor = storyEditor; this.textAttributeProvider = textAttributeProvider; } public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) { List<String> types = StoryPartition.names(); types.add(IDocument.DEFAULT_CONTENT_TYPE); return types.toArray(new String[types.size()]); } @Override public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { return new StepContentAssistant(); } public IHyperlinkDetector[] getHyperlinkDetectors(final ISourceViewer sourceViewer) { return new IHyperlinkDetector[] { new StepHyperLinkDetector() }; } private ITokenScanner getDefaultScanner() { if (defaultScanner == null) { defaultScanner = createScanner(TextStyle.DEFAULT); } return defaultScanner; } protected ITokenScanner getStepScanner() { if (stepScanner == null) { stepScanner = new StepScanner(getJBehaveProject(), textAttributeProvider); } return stepScanner; } protected JBehaveProject getJBehaveProject() { return storyEditor.getJBehaveProject(); } protected ITokenScanner getCommentScanner() { if (commentScanner == null) { commentScanner = createScanner(TextStyle.COMMENT); } return commentScanner; } protected ITokenScanner getScenarioScanner() { if (scenarioScanner == null) { scenarioScanner = new ScenarioScanner(getJBehaveProject(), textAttributeProvider); } return scenarioScanner; } protected ITokenScanner getNarrativeScanner() { if (narrativeScanner == null) { narrativeScanner = new NarrativeScanner(getJBehaveProject(), textAttributeProvider); } return narrativeScanner; } protected ITokenScanner getMiscScanner() { if (miscScanner == null) { miscScanner = new MetaScanner(getJBehaveProject(), textAttributeProvider); } return miscScanner; } protected ITokenScanner getExampleTableScanner() { if (exampleTableScanner == null) { exampleTableScanner = new ExampleTableScanner(getJBehaveProject(), textAttributeProvider); } return exampleTableScanner; } private ITokenScanner createScanner(String attributeKey) { return new SingleTokenScanner(textAttributeProvider, attributeKey); } @Override public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) { reconciler = new PresentationReconciler() { }; try { Field declaredField = PresentationReconciler.class.getDeclaredField("fInternalListener"); declaredField.setAccessible(true); reconcilerInternalListener = declaredField.get(reconciler); } catch (Exception e) { Activator.logError("Failed to retrieve internal listener", e); } DefaultDamagerRepairer dr; if(AllInOneScanner.allInOne) { dr = new DefaultDamagerRepairer(new AllInOneScanner(getJBehaveProject(), textAttributeProvider)); reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE); reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE); } else { dr = new DefaultDamagerRepairer(getDefaultScanner()); reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE); reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE); dr = new DefaultDamagerRepairer(getStepScanner()); reconciler.setDamager(dr, StoryPartition.Step.name()); reconciler.setRepairer(dr, StoryPartition.Step.name()); dr = new DefaultDamagerRepairer(getCommentScanner()); reconciler.setDamager(dr, StoryPartition.Comment.name()); reconciler.setRepairer(dr, StoryPartition.Comment.name()); dr = new DefaultDamagerRepairer(getScenarioScanner()); reconciler.setDamager(dr, StoryPartition.Scenario.name()); reconciler.setRepairer(dr, StoryPartition.Scenario.name()); dr = new DefaultDamagerRepairer(getNarrativeScanner()); reconciler.setDamager(dr, StoryPartition.Narrative.name()); reconciler.setRepairer(dr, StoryPartition.Narrative.name()); dr = new DefaultDamagerRepairer(getExampleTableScanner()); reconciler.setDamager(dr, StoryPartition.ExampleTable.name()); reconciler.setRepairer(dr, StoryPartition.ExampleTable.name()); dr = new DefaultDamagerRepairer(getMiscScanner()); reconciler.setDamager(dr, StoryPartition.Meta.name()); reconciler.setRepairer(dr, StoryPartition.Meta.name()); } return reconciler; } @Override public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer) { return new StoryAnnotationHover(storyEditor); } @SuppressWarnings("unchecked") public <T> T getReconcilerInternalListener(Class<T> asType) { return (T)reconcilerInternalListener; } }