| /*=============================================================================# |
| # 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.internal.redocs.tex.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 org.eclipse.core.commands.IHandler2; |
| 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.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.sourceediting.DocEditor; |
| import org.eclipse.statet.docmlet.tex.core.ast.TexAstNode; |
| import org.eclipse.statet.docmlet.tex.core.model.TexModel; |
| import org.eclipse.statet.docmlet.tex.ui.TexUI; |
| import org.eclipse.statet.docmlet.tex.ui.editors.LtxDefaultFoldingProvider; |
| import org.eclipse.statet.docmlet.tex.ui.editors.TexMarkOccurrencesLocator; |
| import org.eclipse.statet.docmlet.tex.ui.sourceediting.TexEditingSettings; |
| import org.eclipse.statet.internal.redocs.tex.r.RedocsTexRPlugin; |
| 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.ISourceEditorAddon; |
| import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor1; |
| import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor1OutlinePage; |
| 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.model.RModel; |
| 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.tex.r.core.TexRweaveCore; |
| import org.eclipse.statet.redocs.tex.r.core.model.LtxRweaveSourceUnit; |
| import org.eclipse.statet.redocs.tex.r.core.source.LtxRweaveDocumentContentInfo; |
| import org.eclipse.statet.redocs.tex.r.ui.TexRweaveUI; |
| import org.eclipse.statet.redocs.tex.r.ui.editors.LtxRweaveEditor; |
| import org.eclipse.statet.redocs.tex.r.ui.sourceediting.LtxRweaveSourceViewerConfiguration; |
| import org.eclipse.statet.redocs.tex.r.ui.sourceediting.LtxRweaveSourceViewerConfigurator; |
| import org.eclipse.statet.rj.renv.core.REnv; |
| |
| |
| /** |
| * Editor for Sweave (LaTeX+R) code. |
| */ |
| public class LtxRweaveDocEditor extends SourceEditor1 implements LtxRweaveEditor, DocEditor { |
| |
| |
| private static final ImList<String> KEY_CONTEXTS= ImCollections.newIdentityList( |
| TexUI.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 TexMarkOccurrencesLocator docLocator= new TexMarkOccurrencesLocator(); |
| 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 TexAstNode) { |
| this.docLocator.run(run, info, astSelection, orgSelection); |
| } |
| else if (astSelection.getCovering() instanceof RAstNode) { |
| this.rLocator.run(run, info, astSelection, orgSelection); |
| } |
| } |
| |
| } |
| |
| private static class DocContentSectionIndentHandler extends RCorrectIndentHandler { |
| |
| public DocContentSectionIndentHandler(final IRSourceEditor editor) { |
| super(editor); |
| } |
| |
| @Override |
| protected List<? extends TextRegion> getCodeRanges(final AbstractDocument document, |
| final ITextSelection selection) throws BadLocationException { |
| return LtxRweaveDocumentContentInfo.INSTANCE.getRChunkCodeRegions(document, |
| selection.getOffset(), selection.getLength() ); |
| } |
| } |
| |
| |
| private LtxRweaveSourceViewerConfigurator combinedConfig; |
| |
| |
| public LtxRweaveDocEditor() { |
| super(TexRweaveCore.LTX_R_CONTENT_TYPE); |
| } |
| |
| |
| @Override |
| protected void initializeEditor() { |
| super.initializeEditor(); |
| |
| setEditorContextMenuId("org.eclipse.statet.redocs.menus.LtxRweaveEditorContextMenu"); //$NON-NLS-1$ |
| setRulerContextMenuId("org.eclipse.statet.redocs.menus.LtxRweaveEditorRulerMenu"); //$NON-NLS-1$ |
| } |
| |
| @Override |
| protected SourceEditorViewerConfigurator createConfiguration() { |
| setDocumentProvider(RedocsTexRPlugin.getInstance().getDocRDocumentProvider()); |
| |
| enableStructuralFeatures(TexModel.getLtxModelManager(), |
| TexEditingSettings.FOLDING_ENABLED_PREF, |
| TexEditingSettings.MARKOCCURRENCES_ENABLED_PREF ); |
| |
| this.combinedConfig= new LtxRweaveSourceViewerConfigurator( |
| TexRweaveCore.TEX_WORKBENCH_ACCESS, RCore.WORKBENCH_ACCESS, |
| new LtxRweaveSourceViewerConfiguration(0, this, null, null,null) ); |
| return this.combinedConfig; |
| } |
| |
| @Override |
| protected Collection<String> getContextIds() { |
| return CONTEXT_IDS; |
| } |
| |
| @Override |
| protected ISourceEditorAddon createCodeFoldingProvider() { |
| return new FoldingEditorAddon(new LtxDefaultFoldingProvider(Collections.singletonMap( |
| RModel.R_TYPE_ID, 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 LtxRweaveSourceUnit getSourceUnit() { |
| return (LtxRweaveSourceUnit) super.getSourceUnit(); |
| } |
| |
| @Override |
| protected void setupConfiguration(final IEditorInput newInput) { |
| super.setupConfiguration(newInput); |
| |
| final LtxRweaveSourceUnit su= getSourceUnit(); |
| this.combinedConfig.setSource( |
| (su != null) ? su.getTexCoreAccess() : TexRweaveCore.TEX_WORKBENCH_ACCESS, |
| (su != null) ? su.getRCoreAccess() : RCore.WORKBENCH_ACCESS ); |
| } |
| |
| |
| @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(TexRweaveUI.EDITOR_PREF_PAGE_ID); |
| pageIds.add(TexUI.EDITOR_PREF_PAGE_ID); |
| pageIds.add("org.eclipse.statet.docmlet.preferencePages.LtxTextStyles"); //$NON-NLS-1$ |
| pageIds.add("org.eclipse.statet.docmlet.preferencePages.LtxEditorTemplates"); //$NON-NLS-1$ |
| pageIds.add("org.eclipse.statet.docmlet.preferencePages.TexCodeStyle"); //$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 void doPrefixPrimary(final AbstractDocument document, final IRegion block) |
| throws BadLocationException, BadPartitioningException { |
| doPrefix(document, block, "%"); //$NON-NLS-1$ |
| } |
| }; |
| markAsStateDependentHandler(handler, true); |
| return handler; |
| } |
| |
| @Override |
| protected IHandler2 createCorrectIndentHandler() { |
| final IHandler2 handler= new DocContentSectionIndentHandler(this); |
| markAsStateDependentHandler(handler, true); |
| return handler; |
| } |
| |
| @Override |
| protected void editorContextMenuAboutToShow(final IMenuManager m) { |
| super.editorContextMenuAboutToShow(m); |
| final LtxRweaveSourceUnit 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))); |
| } |
| |
| |
| @Override |
| protected SourceEditor1OutlinePage createOutlinePage() { |
| return new LtxRweaveOutlinePage(this); |
| } |
| |
| @Override |
| protected ITemplatesPage createTemplatesPage() { |
| return new LtxRweaveEditorTemplatesPage(this); |
| } |
| |
| @Override |
| public String[] getShowInTargetIds() { |
| return new String[] { IPageLayout.ID_PROJECT_EXPLORER, IPageLayout.ID_OUTLINE, RUI.R_HELP_VIEW_ID }; |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public <T> T getAdapter(final Class<T> adapterType) { |
| if (adapterType == REnv.class) { |
| return (T) getRCoreAccess().getREnv(); |
| } |
| return super.getAdapter(adapterType); |
| } |
| |
| } |