blob: 39e2e17c97e8220c38341530550ba56310d8c347 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2005, 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.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.elements.ISourceStructElement;
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.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.IRCoreAccess;
import org.eclipse.statet.r.core.RCore;
import org.eclipse.statet.r.core.model.IRSourceUnit;
import org.eclipse.statet.r.core.model.RModel;
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.IRDocumentConstants;
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, 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 {
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 IRCoreAccess 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 IRSourceUnit getSourceUnit() {
return (IRSourceUnit) super.getSourceUnit();
}
@Override
public IRCoreAccess getRCoreAccess() {
return this.rConfig.getRCoreAccess();
}
@Override
protected void setupConfiguration(final IEditorInput newInput) {
super.setupConfiguration(newInput);
final IRSourceUnit 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 IRSourceUnit 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 ISourceUnitModelInfo modelInfo, final ISourceStructElement 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);
}
}