blob: 2ca7217e82cbbbe6e53910f8ead1a121f65b5d3e [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2008, 2021 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 java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Map;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jface.text.AbstractDocument;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentRewriteSessionType;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.ui.ISources;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.commands.IElementUpdater;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.menus.UIElement;
import org.eclipse.statet.ecommons.text.IndentUtil;
import org.eclipse.statet.ecommons.ui.workbench.WorkbenchUIUtils;
import org.eclipse.statet.internal.r.ui.RUIMessages;
import org.eclipse.statet.ltk.model.core.ModelManager;
import org.eclipse.statet.ltk.model.core.element.SourceDocumentRunnable;
import org.eclipse.statet.ltk.model.core.element.SourceStructElement;
import org.eclipse.statet.ltk.model.core.element.SourceUnit;
import org.eclipse.statet.ltk.model.core.element.SourceUnitModelInfo;
import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditor;
import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditorAssociated;
import org.eclipse.statet.ltk.ui.templates.TemplateUtils;
import org.eclipse.statet.ltk.ui.templates.TemplateUtils.EvaluatedTemplate;
import org.eclipse.statet.ltk.ui.util.LTKSelectionUtils;
import org.eclipse.statet.ltk.ui.util.LTKWorkbenchUIUtil;
import org.eclipse.statet.r.codegeneration.CodeGeneration;
import org.eclipse.statet.r.core.model.RElement;
import org.eclipse.statet.r.core.model.RLangClass;
import org.eclipse.statet.r.core.model.RLangMethod;
import org.eclipse.statet.r.core.model.RModel;
import org.eclipse.statet.r.core.model.RSourceUnit;
import org.eclipse.statet.r.core.refactoring.RRefactoring;
public class GenerateRoxygenElementComment extends AbstractHandler implements IElementUpdater {
public GenerateRoxygenElementComment() {
}
@Override
public void updateElement(final UIElement element, final Map parameters) {
WorkbenchUIUtils.aboutToUpdateCommandsElements(this, element);
try {
element.setText(RUIMessages.GenerateRoxygenElementComment_label);
}
finally {
WorkbenchUIUtils.finalizeUpdateCommandsElements(this);
}
}
@Override
public Object execute(final ExecutionEvent event) throws ExecutionException {
if (!(event.getApplicationContext() instanceof IEvaluationContext)) {
return null;
}
final SubMonitor m= SubMonitor.convert(null, 2);
SourceUnit su= null;
SourceStructElement[] elements= null;
SourceUnitModelInfo info= null;
final IEvaluationContext context= (IEvaluationContext) event.getApplicationContext();
final ISelection selection= WorkbenchUIUtils.getCurrentSelection(context);
final IWorkbenchWindow workbenchWindow= HandlerUtil.getActiveWorkbenchWindow(event);
final IWorkbenchPart part= (IWorkbenchPart) context.getVariable(ISources.ACTIVE_PART_NAME);
final ISourceEditor editor;
if (selection instanceof IStructuredSelection) {
elements= LTKSelectionUtils.getSelectedSourceStructElements((IStructuredSelection) selection);
if (elements != null && elements.length > 0) {
su= elements[0].getSourceUnit();
for (int i= 0; i < elements.length; i++) {
if (elements[i].getSourceUnit() != su) {
// should be filtered by enablement
return null;
}
}
info= su.getModelInfo(RModel.R_TYPE_ID, ModelManager.MODEL_FILE, m.newChild(1));
// update elements if necessary
}
final ISourceEditorAssociated associated= part.getAdapter(ISourceEditorAssociated.class);
editor= (associated != null) ? associated.getSourceEditor() : null;
}
else if (selection instanceof ITextSelection) {
editor= part.getAdapter(ISourceEditor.class);
if (editor != null) {
su= editor.getSourceUnit();
if (su != null) {
info= su.getModelInfo(RModel.R_TYPE_ID, ModelManager.MODEL_FILE, m.newChild(1));
elements= LTKSelectionUtils.getSelectedSourceStructElement(info, (ITextSelection) selection);
}
}
}
else {
editor= null;
}
if (su == null || elements == null || elements.length == 0 || !(su instanceof RSourceUnit)) {
return null;
}
if (!su.checkState(true, new NullProgressMonitor())) {
return false;
}
final RSourceUnit rsu= (RSourceUnit)su;
try {
final AbstractDocument doc= su.getDocument(null);
final EvaluatedTemplate[] templates= new EvaluatedTemplate[elements.length];
final String lineDelimiter= doc.getDefaultLineDelimiter();
Arrays.sort(elements, RRefactoring.getFactory().createAdapter(elements).getModelElementComparator());
ITER_ELEMENTS: for (int i= 0; i < elements.length; i++) {
switch (elements[i].getElementType() & RElement.MASK_C1) {
case RElement.C1_CLASS:
templates[i]= CodeGeneration.getClassRoxygenComment((RLangClass)elements[i], lineDelimiter);
continue ITER_ELEMENTS;
case RElement.C1_METHOD:
switch (elements[i].getElementType() & RElement.MASK_C2) {
case RElement.R_S4METHOD:
templates[i]= CodeGeneration.getMethodRoxygenComment((RLangMethod)elements[i], lineDelimiter);
continue ITER_ELEMENTS;
default:
templates[i]= CodeGeneration.getCommonFunctionRoxygenComment((RLangMethod)elements[i], lineDelimiter);
continue ITER_ELEMENTS;
}
}
}
final IndentUtil indentUtil= new IndentUtil(doc, rsu.getRCoreAccess().getRCodeStyle());
final MultiTextEdit multi= new MultiTextEdit();
int selectionStart= 0;
int selectionLength= 0;
boolean first= true;
for (int i= 0; i < elements.length; i++) {
if (templates[i] == null) {
continue;
}
final int line= doc.getLineOfOffset(elements[i].getSourceRange().getStartOffset());
final String lineIndent= indentUtil.copyLineIndent(line);
final AbstractDocument templateDoc= templates[i].startPostEdit();
TemplateUtils.indentTemplateDocument(templateDoc, lineIndent);
templates[i].finishPostEdit();
final int lineOffset= doc.getLineOffset(line);
multi.addChild(new InsertEdit(lineOffset, templates[i].getContent()));
// select offset for first comment
if (first) {
first= false;
selectionStart= doc.getLineOffset(line);
final IRegion templateSelection= templates[i].getRegionToSelect();
if (templateSelection != null) {
selectionStart += templateSelection.getOffset();
selectionLength= templateSelection.getLength();
}
else {
selectionStart += lineIndent.length();
}
}
}
if (first) {
return null;
}
final IFile resource= (IFile) su.getResource();
final IRegion initialSelection= new Region(selectionStart, selectionLength);
su.syncExec(new SourceDocumentRunnable(doc, info.getStamp().getContentStamp(),
DocumentRewriteSessionType.SEQUENTIAL ) {
@Override
public void run() throws InvocationTargetException {
try {
multi.apply(getDocument(), TextEdit.NONE);
if (editor != null) {
editor.getViewer().setSelectedRange(initialSelection.getOffset(), initialSelection.getLength());
}
else if (resource != null) {
LTKWorkbenchUIUtil.openEditor(workbenchWindow.getActivePage(), resource, initialSelection);
}
}
catch (final MalformedTreeException e) {
throw new InvocationTargetException(e);
}
catch (final BadLocationException e) {
throw new InvocationTargetException(e);
}
}
});
}
catch (final InvocationTargetException e) {
throw new ExecutionException(RUIMessages.GenerateRoxygenElementComment_error_message, e.getCause());
}
catch (final BadLocationException e) {
throw new ExecutionException(RUIMessages.GenerateRoxygenElementComment_error_message, e);
}
catch (final CoreException e) {
throw new ExecutionException(RUIMessages.GenerateRoxygenElementComment_error_message, e);
}
return null;
}
}