| /*=============================================================================# |
| # Copyright (c) 2005, 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.r.ui.editors; |
| |
| import static org.eclipse.statet.ecommons.ui.actions.UIActions.ADDITIONS_GROUP_ID; |
| |
| import java.util.Collection; |
| import java.util.List; |
| |
| import org.eclipse.core.commands.IHandler2; |
| import org.eclipse.help.IContextProvider; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.IContributionItem; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.Separator; |
| 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.jface.text.Region; |
| import org.eclipse.jface.text.source.SourceViewer; |
| import org.eclipse.swt.events.HelpEvent; |
| import org.eclipse.swt.events.HelpListener; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IPageLayout; |
| import org.eclipse.ui.PlatformUI; |
| 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.ecommons.ui.SharedUIResources; |
| |
| import org.eclipse.statet.base.ui.IStatetUIMenuIds; |
| import org.eclipse.statet.internal.r.ui.RUIPlugin; |
| import org.eclipse.statet.internal.r.ui.help.IRUIHelpContextIds; |
| import org.eclipse.statet.ltk.ast.core.util.AstSelection; |
| import org.eclipse.statet.ltk.model.core.element.SourceStructElement; |
| import org.eclipse.statet.ltk.model.core.element.SourceUnitModelInfo; |
| 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.ISourceFragmentEditorInput; |
| 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.RCore; |
| import org.eclipse.statet.r.core.RCoreAccess; |
| import org.eclipse.statet.r.core.model.RModel; |
| import org.eclipse.statet.r.core.model.RSourceUnit; |
| import org.eclipse.statet.r.core.rsource.ast.FDef; |
| import org.eclipse.statet.r.core.rsource.ast.RAstNode; |
| import org.eclipse.statet.r.core.source.RDocumentConstants; |
| import org.eclipse.statet.r.core.source.RDocumentContentInfo; |
| import org.eclipse.statet.r.launching.RCodeLaunching; |
| import org.eclipse.statet.r.ui.RUI; |
| import org.eclipse.statet.r.ui.RUIHelp; |
| 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.REditorOptions; |
| import org.eclipse.statet.r.ui.editors.RMarkOccurrencesLocator; |
| import org.eclipse.statet.r.ui.sourceediting.InsertAssignmentHandler; |
| import org.eclipse.statet.r.ui.sourceediting.RSourceViewerConfiguration; |
| import org.eclipse.statet.r.ui.sourceediting.RSourceViewerConfigurator; |
| import org.eclipse.statet.rj.renv.core.REnv; |
| |
| |
| public class REditor extends SourceEditor1 implements IRSourceEditor { |
| |
| |
| private static final ImList<String> KEY_CONTEXTS= ImCollections.newIdentityList( |
| "org.eclipse.statet.r.contexts.REditor" ); //$NON-NLS-1$ |
| |
| private static final ImList<String> CONTEXT_IDS= ImCollections.concatList( |
| ACTION_SET_CONTEXT_IDS, KEY_CONTEXTS ); |
| |
| |
| private static class MarkOccurrencesProvider extends AbstractMarkOccurrencesProvider { |
| |
| |
| private final RMarkOccurrencesLocator locator= new RMarkOccurrencesLocator(); |
| |
| |
| public MarkOccurrencesProvider(final SourceEditor1 editor) { |
| super(editor, RDocumentConstants.R_DEFAULT_CONTENT_CONSTRAINT); |
| } |
| |
| @Override |
| protected void doUpdate(final RunData run, final SourceUnitModelInfo info, |
| final AstSelection astSelection, final ITextSelection orgSelection) |
| throws BadLocationException, BadPartitioningException, UnsupportedOperationException { |
| this.locator.run(run, info, astSelection, orgSelection); |
| } |
| |
| } |
| |
| |
| private RSourceViewerConfigurator rConfig; |
| |
| private IContextProvider helpContextProvider; |
| |
| |
| public REditor() { |
| super(RCore.R_CONTENT_TYPE); |
| } |
| |
| |
| @Override |
| protected void initializeEditor() { |
| super.initializeEditor(); |
| |
| setHelpContextId(IRUIHelpContextIds.R_EDITOR); |
| setEditorContextMenuId("org.eclipse.statet.r.menus.REditorContextMenu"); //$NON-NLS-1$ |
| setRulerContextMenuId("org.eclipse.statet.r.menus.REditorRulerMenu"); //$NON-NLS-1$ |
| } |
| |
| |
| @Override |
| protected SourceEditorViewerConfigurator createConfiguration() { |
| setDocumentProvider(RUIPlugin.getInstance().getRDocumentProvider()); |
| |
| enableStructuralFeatures(RModel.getRModelManager(), |
| REditorOptions.FOLDING_ENABLED_PREF, |
| REditorOptions.PREF_MARKOCCURRENCES_ENABLED ); |
| |
| final RCoreAccess initAccess= RCore.WORKBENCH_ACCESS; |
| this.rConfig= new RSourceViewerConfigurator(initAccess, |
| new RSourceViewerConfiguration(RDocumentContentInfo.INSTANCE, 0, this, |
| null, null, null )); |
| return this.rConfig; |
| } |
| |
| @Override |
| protected SourceEditorViewerConfigurator createInfoConfigurator() { |
| return new RSourceViewerConfigurator(getRCoreAccess(), |
| new RSourceViewerConfiguration(0, null, SharedUIResources.getColors()) ); |
| } |
| |
| @Override |
| protected void setDocumentProvider(final IEditorInput input) { |
| if (input instanceof ISourceFragmentEditorInput) { |
| setDocumentProvider(RUIPlugin.getInstance().getRFragmentDocumentProvider()); |
| overwriteTitleImage(input.getImageDescriptor()); |
| } |
| else { |
| setDocumentProvider(RUIPlugin.getInstance().getRDocumentProvider()); |
| overwriteTitleImage(null); |
| } |
| } |
| |
| @Override |
| protected Image getDefaultImage() { |
| return RUIPlugin.getInstance().getImageRegistry().get(RUI.IMG_OBJ_R_SCRIPT); |
| } |
| |
| @Override |
| public void createPartControl(final Composite parent) { |
| super.createPartControl(parent); |
| |
| // Editor Help: |
| final SourceViewer viewer= (SourceViewer) getSourceViewer(); |
| this.helpContextProvider= RUIHelp.createEnrichedRHelpContextProvider(this, IRUIHelpContextIds.R_EDITOR); |
| viewer.getTextWidget().addHelpListener(new HelpListener() { |
| @Override |
| public void helpRequested(final HelpEvent e) { |
| PlatformUI.getWorkbench().getHelpSystem().displayHelp(REditor.this.helpContextProvider.getContext(null)); |
| } |
| }); |
| } |
| |
| @Override |
| protected ISourceEditorAddon createCodeFoldingProvider() { |
| return new FoldingEditorAddon(new RDefaultFoldingProvider()); |
| } |
| |
| @Override |
| protected ISourceEditorAddon createMarkOccurrencesProvider() { |
| return new MarkOccurrencesProvider(this); |
| } |
| |
| |
| @Override |
| public RSourceUnit getSourceUnit() { |
| return (RSourceUnit)super.getSourceUnit(); |
| } |
| |
| @Override |
| public RCoreAccess getRCoreAccess() { |
| return this.rConfig.getRCoreAccess(); |
| } |
| |
| @Override |
| protected void setupConfiguration(final IEditorInput newInput) { |
| super.setupConfiguration(newInput); |
| |
| final RSourceUnit su= getSourceUnit(); |
| this.rConfig.setSource((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; |
| } |
| |
| @Override |
| protected Collection<String> getContextIds() { |
| return CONTEXT_IDS; |
| } |
| |
| @Override |
| protected void collectContextMenuPreferencePages(final List<String> pageIds) { |
| super.collectContextMenuPreferencePages(pageIds); |
| 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); |
| } |
| { final Action action= new RDoubleCommentAction(this, getRCoreAccess()); |
| setAction(action.getId(), action); |
| markAsStateDependentAction(action.getId(), true); |
| } |
| { final IHandler2 handler= new RStripCommentsHandler(this); |
| handlerService.activateHandler(LTKUI.STRIP_COMMENTS_COMMAND_ID, handler); |
| } |
| } |
| |
| @Override |
| protected IHandler2 createCorrectIndentHandler() { |
| final IHandler2 handler= new RCorrectIndentHandler(this); |
| markAsStateDependentHandler(handler, true); |
| return handler; |
| } |
| |
| @Override |
| protected void editorContextMenuAboutToShow(final IMenuManager m) { |
| super.editorContextMenuAboutToShow(m); |
| final RSourceUnit su= getSourceUnit(); |
| |
| m.insertBefore(ADDITIONS_GROUP_ID, new Separator("search")); //$NON-NLS-1$ |
| |
| 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))); |
| if (su != null && !su.isReadOnly()) { |
| m.appendToGroup(IStatetUIMenuIds.GROUP_SUBMIT_MENU_ID, new CommandContributionItem(new CommandContributionItemParameter( |
| getSite(), null, RCodeLaunching.SUBMIT_SELECTION_PASTEOUTPUT_COMMAND_ID, CommandContributionItem.STYLE_PUSH))); |
| } |
| } |
| |
| @Override |
| protected IRegion getRangeToReveal(final SourceUnitModelInfo modelInfo, final SourceStructElement element) { |
| final FDef def= element.getAdapter(FDef.class); |
| if (def != null) { |
| final RAstNode cont= def.getContChild(); |
| final int offset= element.getSourceRange().getStartOffset(); |
| int length= cont.getStartOffset() - offset; |
| if (cont.getLength() > 0) { |
| length++; |
| } |
| return new Region(offset, length); |
| } |
| return null; |
| } |
| |
| |
| @Override |
| protected SourceEditor1OutlinePage createOutlinePage() { |
| return new ROutlinePage(this); |
| } |
| |
| @Override |
| protected ITemplatesPage createTemplatesPage() { |
| return new REditorTemplatesPage(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(); |
| } |
| if (adapterType == IContextProvider.class) { |
| return (T) this.helpContextProvider; |
| } |
| return super.getAdapter(adapterType); |
| } |
| |
| } |