| /*=============================================================================# |
| # 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; |
| } |
| |
| } |