blob: f5ca7f6a4414a364368bf20effb300d19091ccf4 [file] [log] [blame]
/*=============================================================================#
# 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;
}
}
}