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