| /*=============================================================================# |
| # Copyright (c) 2007, 2019 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.redocs.wikitext.r.ui.sourceediting; |
| |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.text.ITextDoubleClickStrategy; |
| import org.eclipse.jface.text.information.IInformationProvider; |
| import org.eclipse.jface.text.presentation.PresentationReconciler; |
| import org.eclipse.jface.text.reconciler.IReconciler; |
| import org.eclipse.jface.text.reconciler.IReconcilingStrategy; |
| import org.eclipse.jface.text.rules.DefaultDamagerRepairer; |
| import org.eclipse.jface.text.rules.ITokenScanner; |
| import org.eclipse.jface.text.source.ISourceViewer; |
| import org.eclipse.ui.editors.text.EditorsUI; |
| import org.eclipse.ui.texteditor.spelling.SpellingReconcileStrategy; |
| import org.eclipse.ui.texteditor.spelling.SpellingService; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.text.core.TextRegion; |
| |
| import org.eclipse.statet.ecommons.templates.TemplateVariableProcessor; |
| import org.eclipse.statet.ecommons.text.ICharPairMatcher; |
| import org.eclipse.statet.ecommons.text.core.sections.IDocContentSections; |
| import org.eclipse.statet.ecommons.text.core.treepartitioner.TreePartition; |
| import org.eclipse.statet.ecommons.text.core.treepartitioner.TreePartitionUtils; |
| import org.eclipse.statet.ecommons.text.ui.presentation.SingleTokenScanner; |
| import org.eclipse.statet.ecommons.text.ui.settings.TextStyleManager; |
| |
| import org.eclipse.statet.docmlet.tex.ui.sourceediting.LtxSourceViewerConfiguration; |
| import org.eclipse.statet.docmlet.wikitext.core.WikitextCoreAccess; |
| import org.eclipse.statet.docmlet.wikitext.core.source.WikitextDocumentConstants; |
| import org.eclipse.statet.docmlet.wikitext.ui.sourceediting.WikidocSourceViewerConfiguration; |
| import org.eclipse.statet.internal.redocs.wikitext.r.RedocsWikitextRPlugin; |
| import org.eclipse.statet.internal.redocs.wikitext.r.ui.sourceediting.DocRQuickOutlineInformationProvider; |
| import org.eclipse.statet.internal.redocs.wikitext.r.ui.sourceediting.RChunkTemplateCompletionComputer; |
| import org.eclipse.statet.ltk.ui.LTKUIPreferences; |
| import org.eclipse.statet.ltk.ui.sourceediting.EcoReconciler2; |
| import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditor; |
| import org.eclipse.statet.ltk.ui.sourceediting.MultiContentSectionSourceViewerConfiguration; |
| import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor1; |
| import org.eclipse.statet.ltk.ui.sourceediting.SourceEditorViewer; |
| import org.eclipse.statet.ltk.ui.sourceediting.assist.ContentAssist; |
| import org.eclipse.statet.ltk.ui.sourceediting.assist.ContentAssistCategory; |
| import org.eclipse.statet.ltk.ui.sourceediting.assist.ContentAssistComputer; |
| import org.eclipse.statet.ltk.ui.sourceediting.assist.ContentAssistProcessor; |
| import org.eclipse.statet.r.core.IRCoreAccess; |
| import org.eclipse.statet.r.core.source.IRDocumentConstants; |
| import org.eclipse.statet.r.core.source.RHeuristicTokenScanner; |
| import org.eclipse.statet.r.core.source.RPartitionNodeType; |
| import org.eclipse.statet.r.ui.editors.IRSourceEditor; |
| import org.eclipse.statet.r.ui.sourceediting.RAutoEditStrategy; |
| import org.eclipse.statet.r.ui.sourceediting.RSourceViewerConfiguration; |
| import org.eclipse.statet.r.ui.text.r.IRTextTokens; |
| import org.eclipse.statet.r.ui.text.r.RDoubleClickStrategy; |
| import org.eclipse.statet.redocs.wikitext.r.core.source.WikidocRweaveBracketPairMatcher; |
| import org.eclipse.statet.redocs.wikitext.r.core.source.WikidocRweaveDocumentContentInfo; |
| import org.eclipse.statet.redocs.wikitext.r.core.source.WikitextRweaveDocumentConstants; |
| import org.eclipse.statet.redocs.wikitext.r.ui.editors.WikidocRweaveEditor; |
| import org.eclipse.statet.yaml.ui.sourceediting.YamlSourceViewerConfiguration; |
| |
| |
| /** |
| * Default Configuration for source viewer of Wikitext-R documents. |
| */ |
| public class WikidocRweaveSourceViewerConfiguration extends MultiContentSectionSourceViewerConfiguration { |
| |
| |
| private static final String[] CONTENT_TYPES= WikitextRweaveDocumentConstants.WIKIDOC_R_CONTENT_TYPES.toArray( |
| new String[WikitextRweaveDocumentConstants.WIKIDOC_R_CONTENT_TYPES.size()]); |
| |
| |
| private static class WikidocConfiguration extends WikidocSourceViewerConfiguration { |
| |
| public WikidocConfiguration(final IDocContentSections documentContentInfo, final int flags, |
| final ISourceEditor editor, |
| final WikitextCoreAccess wikitextCoreAccess, |
| final IPreferenceStore preferenceStore) { |
| super(documentContentInfo, flags, editor, wikitextCoreAccess, preferenceStore); |
| } |
| |
| @Override |
| protected void setCoreAccess(final WikitextCoreAccess access) { |
| super.setCoreAccess(access); |
| } |
| |
| @Override |
| protected TemplateVariableProcessor getTemplateVariableProcessor() { |
| return super.getTemplateVariableProcessor(); |
| } |
| |
| } |
| |
| |
| private static class RChunkAutoEditStrategy extends RAutoEditStrategy { |
| |
| public RChunkAutoEditStrategy(final IRCoreAccess coreAccess, final ISourceEditor sourceEditor) { |
| super(coreAccess, sourceEditor); |
| } |
| |
| @Override |
| protected TextRegion getValidRange(final int offset, final TreePartition partition, final int c) { |
| switch (WikidocRweaveDocumentContentInfo.INSTANCE.getTypeByPartition(partition.getType())) { |
| case WikidocRweaveDocumentContentInfo.R: |
| return TreePartitionUtils.searchNodeUp(partition.getTreeNode(), |
| RPartitionNodeType.DEFAULT_ROOT ); |
| case WikidocRweaveDocumentContentInfo.R_CHUNK_CONTROL: |
| switch (c) { |
| case '(': |
| case '[': |
| case '{': |
| case '%': |
| case '\"': |
| case '\'': |
| return TreePartitionUtils.searchPartitionRegion(partition, |
| WikitextRweaveDocumentConstants.RCHUNK_PARTITION_CONSTRAINT ); |
| } |
| return null; |
| default: |
| return null; |
| } |
| } |
| |
| } |
| |
| private static class RChunkConfiguration extends RSourceViewerConfiguration { |
| |
| public RChunkConfiguration(final IDocContentSections documentContentInfo, final int flags, |
| final IRSourceEditor sourceEditor, |
| final IRCoreAccess coreAccess, final IPreferenceStore preferenceStore) { |
| super(documentContentInfo, flags, sourceEditor, coreAccess, preferenceStore, null); |
| } |
| |
| @Override |
| protected void setCoreAccess(final IRCoreAccess access) { |
| super.setCoreAccess(access); |
| } |
| |
| @Override |
| protected TextStyleManager getTextStyles() { |
| return super.getTextStyles(); |
| } |
| |
| @Override |
| protected ITokenScanner getScanner(final String contentType) { |
| return super.getScanner(contentType); |
| } |
| |
| @Override |
| protected RAutoEditStrategy createRAutoEditStrategy() { |
| return new RChunkAutoEditStrategy(getRCoreAccess(), getSourceEditor()); |
| } |
| |
| } |
| |
| |
| private final WikidocConfiguration docConfig; |
| private final YamlSourceViewerConfiguration yamlConfig; |
| private final LtxSourceViewerConfiguration ltxConfig; |
| private final RChunkConfiguration rConfig; |
| |
| private ITextDoubleClickStrategy rDoubleClickStrategy; |
| |
| |
| public WikidocRweaveSourceViewerConfiguration(final int flags) { |
| this(flags, null, null, null, null); |
| } |
| |
| public WikidocRweaveSourceViewerConfiguration(final int flags, |
| final WikidocRweaveEditor sourceEditor, |
| final WikitextCoreAccess wikitextCoreAccess, final IRCoreAccess rCoreAccess, |
| final IPreferenceStore preferenceStore) { |
| super(WikidocRweaveDocumentContentInfo.INSTANCE, flags, sourceEditor); |
| |
| this.docConfig= new WikidocConfiguration(WikidocRweaveDocumentContentInfo.INSTANCE, flags, |
| sourceEditor, |
| wikitextCoreAccess, preferenceStore ); |
| this.yamlConfig= new YamlSourceViewerConfiguration(WikidocRweaveDocumentContentInfo.INSTANCE, (flags & 0xFF), |
| sourceEditor, null, null, null ); |
| this.ltxConfig= new LtxSourceViewerConfiguration(WikidocRweaveDocumentContentInfo.INSTANCE, (flags & 0xFF), |
| sourceEditor, null, null, null ); |
| this.rConfig= new RChunkConfiguration(WikidocRweaveDocumentContentInfo.INSTANCE, (flags & 0xFF), |
| sourceEditor, |
| rCoreAccess, preferenceStore ); |
| |
| registerConfig(WikidocRweaveDocumentContentInfo.WIKITEXT, this.docConfig); |
| registerConfig(WikidocRweaveDocumentContentInfo.YAML, this.yamlConfig); |
| registerConfig(WikidocRweaveDocumentContentInfo.LTX, this.ltxConfig); |
| registerConfig(WikidocRweaveDocumentContentInfo.R, this.rConfig); |
| |
| setup((preferenceStore != null) ? preferenceStore : RedocsWikitextRPlugin.getInstance().getEditorPreferenceStore(), |
| LTKUIPreferences.getEditorDecorationPreferences(), |
| LTKUIPreferences.getAssistPreferences() ); |
| } |
| |
| |
| @Override |
| protected void initScanners() { |
| final TextStyleManager textStyles= this.rConfig.getTextStyles(); |
| |
| addScanner(WikitextRweaveDocumentConstants.RCHUNK_BASE_CONTENT_TYPE, |
| new SingleTokenScanner(textStyles, IRTextTokens.UNDEFINED_KEY )); |
| } |
| |
| @Override |
| protected ITokenScanner getScanner(final String contentType) { |
| if (contentType == WikitextRweaveDocumentConstants.RCHUNK_CONTROL_CONTENT_TYPE) { |
| return this.rConfig.getScanner(IRDocumentConstants.R_DEFAULT_CONTENT_TYPE); |
| } |
| if (contentType == WikitextRweaveDocumentConstants.RCHUNK_COMMENT_CONTENT_TYPE) { |
| return this.rConfig.getScanner(IRDocumentConstants.R_COMMENT_CONTENT_TYPE); |
| } |
| return super.getScanner(contentType); |
| } |
| |
| protected void setCoreAccess(final WikitextCoreAccess wikitextCoreAccess, final IRCoreAccess rCoreAccess) { |
| this.docConfig.setCoreAccess(wikitextCoreAccess); |
| this.rConfig.setCoreAccess(rCoreAccess); |
| } |
| |
| |
| @Override |
| public String[] getConfiguredContentTypes(final ISourceViewer sourceViewer) { |
| return CONTENT_TYPES; |
| } |
| |
| @Override |
| protected void initPresentationReconciler(final PresentationReconciler reconciler) { |
| super.initPresentationReconciler(reconciler); |
| |
| for (final String contentType : WikitextRweaveDocumentConstants.RCHUNK_CONTENT_TYPES) { |
| final ITokenScanner scanner= getScanner(contentType); |
| if (scanner != null) { |
| final DefaultDamagerRepairer dr= new DefaultDamagerRepairer(scanner); |
| reconciler.setDamager(dr, contentType); |
| reconciler.setRepairer(dr, contentType); |
| } |
| } |
| } |
| |
| |
| @Override |
| public ICharPairMatcher createPairMatcher() { |
| return new WikidocRweaveBracketPairMatcher(); |
| } |
| |
| @Override |
| public ITextDoubleClickStrategy getDoubleClickStrategy(final ISourceViewer sourceViewer, final String contentType) { |
| switch (WikidocRweaveDocumentContentInfo.INSTANCE.getTypeByPartition(contentType)) { |
| case WikidocRweaveDocumentContentInfo.WIKITEXT: |
| return this.docConfig.getDoubleClickStrategy(sourceViewer, contentType); |
| case WikidocRweaveDocumentContentInfo.R_CHUNK_CONTROL: |
| case WikidocRweaveDocumentContentInfo.R: |
| if (this.rDoubleClickStrategy == null) { |
| final RHeuristicTokenScanner scanner= RHeuristicTokenScanner.create(getDocumentContentInfo()); |
| this.rDoubleClickStrategy= new RDoubleClickStrategy(scanner, |
| WikidocRweaveBracketPairMatcher.createRChunkPairMatcher(scanner) ); |
| } |
| return this.rDoubleClickStrategy; |
| default: |
| return null; |
| } |
| } |
| |
| |
| protected IReconcilingStrategy getSpellingStrategy(final ISourceViewer sourceViewer) { |
| if (!(this.rConfig.getRCoreAccess().getPrefs().getPreferenceValue(WikitextRweaveEditingSettings.WIKIDOC_SPELLCHECK_ENABLED_PREF) |
| && this.fPreferenceStore.getBoolean(SpellingService.PREFERENCE_SPELLING_ENABLED)) ) { |
| return null; |
| } |
| final SpellingService spellingService= EditorsUI.getSpellingService(); |
| if (spellingService.getActiveSpellingEngineDescriptor(this.fPreferenceStore) == null) { |
| return null; |
| } |
| return new SpellingReconcileStrategy(sourceViewer, spellingService); |
| } |
| |
| |
| @Override |
| protected void initContentAssist(final ContentAssist assistant) { |
| super.initContentAssist(assistant); |
| |
| final ContentAssistComputer chunkComputer= new RChunkTemplateCompletionComputer(); |
| |
| final ContentAssistProcessor wikitextProcessor= (ContentAssistProcessor) assistant.getContentAssistProcessor( |
| WikitextDocumentConstants.WIKIDOC_DEFAULT_CONTENT_TYPE ); |
| wikitextProcessor.addCategory(new ContentAssistCategory( |
| WikitextDocumentConstants.WIKIDOC_DEFAULT_CONTENT_TYPE, |
| ImCollections.newList(chunkComputer) )); |
| // wikitextProcessor.setCompletionProposalAutoActivationCharacters(new char[] { '\\', '<' }); |
| |
| final ContentAssistProcessor controlProcessor= new ContentAssistProcessor(assistant, |
| WikitextRweaveDocumentConstants.RCHUNK_BASE_CONTENT_TYPE, |
| RedocsWikitextRPlugin.getInstance().getWikidocRweaveEditorContentAssistRegistry(), |
| getSourceEditor() ); |
| controlProcessor.addCategory(new ContentAssistCategory(WikitextRweaveDocumentConstants.RCHUNK_BASE_CONTENT_TYPE, |
| ImCollections.newList(chunkComputer) )); |
| assistant.setContentAssistProcessor(controlProcessor, WikitextRweaveDocumentConstants.RCHUNK_BASE_CONTENT_TYPE); |
| assistant.setContentAssistProcessor(controlProcessor, WikitextRweaveDocumentConstants.RCHUNK_CONTROL_CONTENT_TYPE); |
| } |
| |
| |
| @Override |
| public IReconciler getReconciler(final ISourceViewer sourceViewer) { |
| final ISourceEditor editor= getSourceEditor(); |
| if (!(editor instanceof SourceEditor1)) { |
| return null; |
| } |
| final EcoReconciler2 reconciler= (EcoReconciler2) this.docConfig.getReconciler(sourceViewer); |
| if (reconciler != null) { |
| final IReconcilingStrategy spellingStrategy= getSpellingStrategy(sourceViewer); |
| if (spellingStrategy != null) { |
| reconciler.addReconcilingStrategy(spellingStrategy); |
| } |
| } |
| return reconciler; |
| } |
| |
| |
| @Override |
| protected IInformationProvider getQuickInformationProvider(final ISourceViewer sourceViewer, |
| final int operation) { |
| final ISourceEditor editor= getSourceEditor(); |
| if (editor == null) { |
| return null; |
| } |
| switch (operation) { |
| case SourceEditorViewer.SHOW_SOURCE_OUTLINE: |
| return new DocRQuickOutlineInformationProvider(editor, operation); |
| default: |
| return null; |
| } |
| } |
| |
| } |