| /*=============================================================================# |
| # Copyright (c) 2007, 2020 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.editors; |
| |
| import static org.eclipse.statet.ecommons.ui.actions.UIActions.ADDITIONS_GROUP_ID; |
| |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.core.commands.IHandler2; |
| import org.eclipse.core.runtime.content.IContentType; |
| import org.eclipse.jface.action.IContributionItem; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.text.AbstractDocument; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.BadPartitioningException; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.jface.text.ITextSelection; |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IPageLayout; |
| import org.eclipse.ui.handlers.IHandlerService; |
| import org.eclipse.ui.menus.CommandContributionItem; |
| import org.eclipse.ui.menus.CommandContributionItemParameter; |
| import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; |
| import org.eclipse.ui.texteditor.ITextEditorActionConstants; |
| import org.eclipse.ui.texteditor.templates.ITemplatesPage; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.collections.ImList; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| import org.eclipse.statet.jcommons.text.core.TextRegion; |
| |
| import org.eclipse.statet.base.ui.IStatetUIMenuIds; |
| import org.eclipse.statet.docmlet.base.ui.DocmlBaseUI; |
| import org.eclipse.statet.docmlet.base.ui.markuphelp.MarkupHelpContextProvider; |
| import org.eclipse.statet.docmlet.base.ui.processing.actions.RunDocProcessingOnSaveExtension; |
| import org.eclipse.statet.docmlet.base.ui.sourceediting.DocEditor; |
| import org.eclipse.statet.docmlet.wikitext.core.WikitextCore; |
| import org.eclipse.statet.docmlet.wikitext.core.ast.WikitextAstNode; |
| import org.eclipse.statet.docmlet.wikitext.core.model.WikitextModel; |
| import org.eclipse.statet.docmlet.wikitext.ui.WikitextUI; |
| import org.eclipse.statet.docmlet.wikitext.ui.editors.WikidocDefaultFoldingProvider; |
| import org.eclipse.statet.docmlet.wikitext.ui.editors.WikitextMarkOccurrencesLocator; |
| import org.eclipse.statet.docmlet.wikitext.ui.sourceediting.WikitextEditingSettings; |
| import org.eclipse.statet.internal.redocs.wikitext.r.RedocsWikitextRPlugin; |
| import org.eclipse.statet.internal.redocs.wikitext.r.ui.editors.WikidocRweaveEditorTemplatesPage; |
| import org.eclipse.statet.internal.redocs.wikitext.r.ui.editors.WikidocRweaveOutlinePage; |
| import org.eclipse.statet.ltk.ast.core.util.AstSelection; |
| import org.eclipse.statet.ltk.model.core.elements.ISourceUnitModelInfo; |
| import org.eclipse.statet.ltk.ui.LTKUI; |
| import org.eclipse.statet.ltk.ui.sourceediting.AbstractMarkOccurrencesProvider; |
| import org.eclipse.statet.ltk.ui.sourceediting.ForwardSourceDocumentProvider; |
| import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditorAddon; |
| import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor1; |
| import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor1OutlinePage; |
| import org.eclipse.statet.ltk.ui.sourceediting.SourceEditorViewer; |
| import org.eclipse.statet.ltk.ui.sourceediting.SourceEditorViewerConfigurator; |
| import org.eclipse.statet.ltk.ui.sourceediting.folding.FoldingEditorAddon; |
| import org.eclipse.statet.r.core.IRCoreAccess; |
| import org.eclipse.statet.r.core.RCore; |
| import org.eclipse.statet.r.core.rsource.ast.RAstNode; |
| import org.eclipse.statet.r.core.source.IRDocumentConstants; |
| import org.eclipse.statet.r.launching.RCodeLaunching; |
| import org.eclipse.statet.r.ui.RUI; |
| import org.eclipse.statet.r.ui.editors.IRSourceEditor; |
| import org.eclipse.statet.r.ui.editors.RCorrectIndentHandler; |
| import org.eclipse.statet.r.ui.editors.RDefaultFoldingProvider; |
| import org.eclipse.statet.r.ui.editors.RMarkOccurrencesLocator; |
| import org.eclipse.statet.r.ui.sourceediting.InsertAssignmentHandler; |
| import org.eclipse.statet.redocs.r.core.source.DocContentSectionsRweaveExtension; |
| import org.eclipse.statet.redocs.r.ui.RedocsRUI; |
| import org.eclipse.statet.redocs.r.ui.sourceediting.actions.RweaveToggleCommentHandler; |
| import org.eclipse.statet.redocs.wikitext.r.core.model.WikidocRweaveSourceUnit; |
| import org.eclipse.statet.redocs.wikitext.r.core.source.RweaveMarkupLanguage; |
| import org.eclipse.statet.redocs.wikitext.r.core.source.WikidocRweaveDocumentContentInfo; |
| import org.eclipse.statet.redocs.wikitext.r.core.source.WikidocRweaveDocumentSetupParticipant; |
| import org.eclipse.statet.redocs.wikitext.r.ui.WikitextRweaveUI; |
| import org.eclipse.statet.redocs.wikitext.r.ui.sourceediting.WikidocRweaveSourceViewerConfiguration; |
| import org.eclipse.statet.redocs.wikitext.r.ui.sourceediting.WikidocRweaveSourceViewerConfigurator; |
| import org.eclipse.statet.rj.renv.core.REnv; |
| |
| |
| /** |
| * Editor for Wikitext-R documents. |
| */ |
| public abstract class WikidocRweaveDocEditor extends SourceEditor1 implements WikidocRweaveEditor, |
| DocEditor, MarkupHelpContextProvider { |
| |
| |
| private static final ImList<String> KEY_CONTEXTS= ImCollections.newIdentityList( |
| WikitextUI.EDITOR_CONTEXT_ID, |
| DocmlBaseUI.DOC_EDITOR_CONTEXT_ID, |
| RedocsRUI.RWEAVE_EDITOR_CONTEXT_ID ); |
| |
| private static final ImList<String> CONTEXT_IDS= ImCollections.concatList( |
| ACTION_SET_CONTEXT_IDS, KEY_CONTEXTS ); |
| |
| |
| private static class ThisMarkOccurrencesProvider extends AbstractMarkOccurrencesProvider { |
| |
| |
| private final WikitextMarkOccurrencesLocator docLocator= new WikitextMarkOccurrencesLocator(); |
| private final RMarkOccurrencesLocator rLocator= new RMarkOccurrencesLocator(); |
| |
| |
| public ThisMarkOccurrencesProvider(final SourceEditor1 editor) { |
| super(editor, IRDocumentConstants.R_DEFAULT_CONTENT_CONSTRAINT); |
| } |
| |
| @Override |
| protected void doUpdate(final RunData run, final ISourceUnitModelInfo info, |
| final AstSelection astSelection, final ITextSelection orgSelection) |
| throws BadLocationException, BadPartitioningException, UnsupportedOperationException { |
| if (astSelection.getCovering() instanceof WikitextAstNode) { |
| this.docLocator.run(run, info, astSelection, orgSelection); |
| } |
| else if (astSelection.getCovering() instanceof RAstNode) { |
| this.rLocator.run(run, info, astSelection, orgSelection); |
| } |
| } |
| |
| } |
| |
| private static class ThisCorrectIndentHandler extends RCorrectIndentHandler { |
| |
| public ThisCorrectIndentHandler(final IRSourceEditor editor) { |
| super(editor); |
| } |
| |
| @Override |
| protected List<? extends TextRegion> getCodeRanges(final AbstractDocument document, |
| final ITextSelection selection) throws BadLocationException { |
| return WikidocRweaveDocumentContentInfo.INSTANCE.getRChunkCodeRegions(document, |
| selection.getOffset(), selection.getLength() ); |
| } |
| |
| } |
| |
| |
| private final WikidocRweaveDocumentSetupParticipant documentSetup; |
| |
| private WikidocRweaveSourceViewerConfigurator combinedConfig; |
| |
| private final RunDocProcessingOnSaveExtension autoDocProcessing; |
| |
| |
| public WikidocRweaveDocEditor(final IContentType contentType, |
| final WikidocRweaveDocumentSetupParticipant documentSetup) { |
| super(contentType); |
| if (documentSetup == null) { |
| throw new NullPointerException("documentSetup"); //$NON-NLS-1$ |
| } |
| this.documentSetup= documentSetup; |
| |
| this.autoDocProcessing= new RunDocProcessingOnSaveExtension(this); |
| |
| initializeEditor(); |
| } |
| |
| |
| @Override |
| protected void initializeEditor() { |
| if (this.documentSetup == null) { |
| return; |
| } |
| |
| super.initializeEditor(); |
| |
| setEditorContextMenuId("org.eclipse.statet.redocs.menus.WikidocRweaveEditorContextMenu"); //$NON-NLS-1$ |
| setRulerContextMenuId("org.eclipse.statet.redocs.menus.WikidocRweaveEditorRulerMenu"); //$NON-NLS-1$ |
| } |
| |
| @Override |
| protected SourceEditorViewerConfigurator createConfiguration() { |
| setDocumentProvider(new ForwardSourceDocumentProvider( |
| RedocsWikitextRPlugin.getInstance().getDocRDocumentProvider(), |
| this.documentSetup )); |
| |
| enableStructuralFeatures(WikitextModel.getWikidocModelManager(), |
| WikitextEditingSettings.FOLDING_ENABLED_PREF, |
| WikitextEditingSettings.MARKOCCURRENCES_ENABLED_PREF ); |
| |
| this.combinedConfig= new WikidocRweaveSourceViewerConfigurator( |
| this.documentSetup, |
| WikitextCore.WORKBENCH_ACCESS, RCore.WORKBENCH_ACCESS, |
| new WikidocRweaveSourceViewerConfiguration(0, this, null, null, null) ); |
| return this.combinedConfig; |
| } |
| |
| @Override |
| protected int getSourceViewerFlags() { |
| return SourceEditorViewer.VARIABLE_LINE_HEIGHT; |
| } |
| |
| @Override |
| protected Collection<String> getContextIds() { |
| return CONTEXT_IDS; |
| } |
| |
| @Override |
| protected ISourceEditorAddon createCodeFoldingProvider() { |
| return new FoldingEditorAddon(new WikidocDefaultFoldingProvider(Collections.singletonMap( |
| RweaveMarkupLanguage.EMBEDDED_R, new RDefaultFoldingProvider() ))); |
| } |
| |
| @Override |
| protected ISourceEditorAddon createMarkOccurrencesProvider() { |
| return new ThisMarkOccurrencesProvider(this); |
| } |
| |
| |
| @Override |
| public IRCoreAccess getRCoreAccess() { |
| return this.combinedConfig.getRCoreAccess(); |
| } |
| |
| @Override |
| public DocContentSectionsRweaveExtension getDocumentContentInfo() { |
| return (DocContentSectionsRweaveExtension) super.getDocumentContentInfo(); |
| } |
| |
| @Override |
| public WikidocRweaveSourceUnit getSourceUnit() { |
| return (WikidocRweaveSourceUnit) super.getSourceUnit(); |
| } |
| |
| @Override |
| protected void setupConfiguration(final IEditorInput newInput) { |
| super.setupConfiguration(newInput); |
| |
| final WikidocRweaveSourceUnit su= getSourceUnit(); |
| this.combinedConfig.setSource( |
| (su != null) ? su.getWikitextCoreAccess() : WikitextCore.WORKBENCH_ACCESS, |
| (su != null) ? su.getRCoreAccess() : RCore.WORKBENCH_ACCESS ); |
| |
| this.autoDocProcessing.setAutoRunEnabled(false); |
| } |
| |
| |
| @Override |
| protected void handlePreferenceStoreChanged(final org.eclipse.jface.util.PropertyChangeEvent event) { |
| if (AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH.equals(event.getProperty()) |
| || AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SPACES_FOR_TABS.equals(event.getProperty())) { |
| return; |
| } |
| super.handlePreferenceStoreChanged(event); |
| } |
| |
| |
| @Override |
| protected boolean isTabsToSpacesConversionEnabled() { |
| return false; |
| } |
| |
| public void updateSettings(final boolean indentChanged) { |
| if (indentChanged) { |
| updateIndentPrefixes(); |
| } |
| } |
| |
| |
| @Override |
| protected void collectContextMenuPreferencePages(final List<String> pageIds) { |
| super.collectContextMenuPreferencePages(pageIds); |
| pageIds.add(WikitextRweaveUI.EDITOR_PREF_PAGE_ID); |
| pageIds.add(WikitextUI.EDITOR_PREF_PAGE_ID); |
| pageIds.add("org.eclipse.mylyn.internal.wikitext.ui.editor.preferences.WikiTextTemplatePreferencePage"); //$NON-NLS-1$ |
| pageIds.add("org.eclipse.statet.docmlet.preferencePages.WikitextCodeStyle"); //$NON-NLS-1$ |
| pageIds.add("org.eclipse.statet.r.preferencePages.REditorOptions"); //$NON-NLS-1$ |
| pageIds.add("org.eclipse.statet.r.preferencePages.RTextStyles"); //$NON-NLS-1$ |
| pageIds.add("org.eclipse.statet.r.preferencePages.REditorTemplates"); //$NON-NLS-1$ |
| pageIds.add("org.eclipse.statet.r.preferencePages.RCodeStyle"); //$NON-NLS-1$ |
| } |
| |
| @Override |
| protected void createActions() { |
| super.createActions(); |
| final IHandlerService handlerService= getServiceLocator() |
| .getService(IHandlerService.class); |
| |
| { final IHandler2 handler= new InsertAssignmentHandler(this); |
| handlerService.activateHandler(LTKUI.INSERT_ASSIGNMENT_COMMAND_ID, handler); |
| markAsStateDependentHandler(handler, true); |
| } |
| } |
| |
| @Override |
| protected IHandler2 createToggleCommentHandler() { |
| final IHandler2 handler= new RweaveToggleCommentHandler(this) { |
| @Override |
| protected Pattern getPrefixPattern(final String contentType, final String prefix) { |
| if (prefix.equals("<!--")) { //$NON-NLS-1$ |
| return HTML_SPACE_PREFIX_PATTERN; |
| } |
| return super.getPrefixPattern(contentType, prefix); |
| } |
| @Override |
| protected Pattern getPostfixPattern(final String contentType, final String prefix) { |
| if (prefix.equals("<!--")) { //$NON-NLS-1$ |
| return HTML_SPACE_POSTFIX_PATTERN; |
| } |
| return super.getPostfixPattern(contentType, prefix); |
| } |
| @Override |
| protected void doPrefixPrimary(final AbstractDocument document, final IRegion block) |
| throws BadLocationException, BadPartitioningException { |
| doPrefix(document, block, "<!-- ", " -->"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| }; |
| markAsStateDependentHandler(handler, true); |
| return handler; |
| } |
| |
| @Override |
| protected IHandler2 createCorrectIndentHandler() { |
| final IHandler2 handler= new ThisCorrectIndentHandler(this); |
| markAsStateDependentHandler(handler, true); |
| return handler; |
| } |
| |
| @Override |
| protected void editorContextMenuAboutToShow(final IMenuManager m) { |
| super.editorContextMenuAboutToShow(m); |
| final WikidocRweaveSourceUnit su= getSourceUnit(); |
| |
| m.insertBefore(ADDITIONS_GROUP_ID, new Separator(IStatetUIMenuIds.GROUP_SUBMIT_MENU_ID)); |
| final IContributionItem additions= m.find(ADDITIONS_GROUP_ID); |
| if (additions != null) { |
| additions.setVisible(false); |
| } |
| |
| m.remove(ITextEditorActionConstants.SHIFT_RIGHT); |
| m.remove(ITextEditorActionConstants.SHIFT_LEFT); |
| |
| m.appendToGroup(IStatetUIMenuIds.GROUP_SUBMIT_MENU_ID, new CommandContributionItem( |
| new CommandContributionItemParameter(getSite(), null, |
| RCodeLaunching.SUBMIT_SELECTION_COMMAND_ID, |
| CommandContributionItem.STYLE_PUSH ))); |
| m.appendToGroup(IStatetUIMenuIds.GROUP_SUBMIT_MENU_ID, new CommandContributionItem( |
| new CommandContributionItemParameter(getSite(), null, |
| RCodeLaunching.SUBMIT_UPTO_SELECTION_COMMAND_ID, |
| CommandContributionItem.STYLE_PUSH ))); |
| |
| m.appendToGroup(ITextEditorActionConstants.GROUP_SETTINGS, new CommandContributionItem( |
| new CommandContributionItemParameter(getSite(), null, |
| DocmlBaseUI.CONFIGURE_MARKUP_COMMAND_ID, null, |
| null, null, null, |
| "Configure Markup...", "M", null, |
| CommandContributionItem.STYLE_PUSH, null, false ))); |
| } |
| |
| |
| @Override |
| protected void editorSaved() { |
| super.editorSaved(); |
| |
| this.autoDocProcessing.onEditorSaved(); |
| } |
| |
| |
| @Override |
| protected SourceEditor1OutlinePage createOutlinePage() { |
| return new WikidocRweaveOutlinePage(this); |
| } |
| |
| @Override |
| protected ITemplatesPage createTemplatesPage() { |
| return new WikidocRweaveEditorTemplatesPage(this); |
| } |
| |
| @Override |
| public String[] getShowInTargetIds() { |
| return new String[] { IPageLayout.ID_PROJECT_EXPLORER, IPageLayout.ID_OUTLINE, RUI.R_HELP_VIEW_ID }; |
| } |
| |
| @Override |
| public @Nullable String getHelpContentId() { |
| return WikitextUI.getMarkupHelpContentIdFor(this.documentSetup.getMarkupLanguage()); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public <T> T getAdapter(final Class<T> adapterType) { |
| if (adapterType == MarkupHelpContextProvider.class) { |
| return (T) this; |
| } |
| if (adapterType == RunDocProcessingOnSaveExtension.class) { |
| return (T) this.autoDocProcessing; |
| } |
| if (adapterType == REnv.class) { |
| return (T) getRCoreAccess().getREnv(); |
| } |
| return super.getAdapter(adapterType); |
| } |
| |
| } |