blob: 07e9cd03d9346f97c7d797308930aee34c5b0a75 [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.r.ui.editors;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.AbstractDocument;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentRewriteSessionType;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.statet.jcommons.text.core.BasicTextRegion;
import org.eclipse.statet.jcommons.text.core.TextRegion;
import org.eclipse.statet.ecommons.ui.util.UIAccess;
import org.eclipse.statet.internal.r.ui.RUIMessages;
import org.eclipse.statet.ltk.ast.core.AstInfo;
import org.eclipse.statet.ltk.model.core.SourceDocumentRunnable;
import org.eclipse.statet.ltk.model.core.elements.ISourceUnit;
import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditor;
import org.eclipse.statet.ltk.ui.sourceediting.SourceEditorProgressHandler;
import org.eclipse.statet.r.core.RCore;
import org.eclipse.statet.r.core.model.IRSourceUnit;
import org.eclipse.statet.r.core.rsource.RSourceIndenter;
import org.eclipse.statet.r.core.source.RHeuristicTokenScanner;
/**
* Command handler to correct indentation of selected code lines.
* @see RSourceIndenter
*/
public class RCorrectIndentHandler extends SourceEditorProgressHandler {
private RSourceIndenter fIndenter;
public RCorrectIndentHandler(final ISourceEditor editor) {
super(editor);
}
@Override
protected String getTaskLabel() {
return RUIMessages.CorrectIndent_task_label;
}
@Override
protected boolean isEditTask() {
return true;
}
@Override
protected void doExecute(final ISourceEditor editor, final ISourceUnit su,
final ITextSelection selection, final IProgressMonitor monitor) throws Exception {
final AbstractDocument document= su.getDocument(monitor);
final AstInfo ast= su.getAstInfo(null, true, monitor);
if (ast == null || monitor.isCanceled() ) {
return;
}
monitor.subTask(getTaskLabel() + "...");
if (fIndenter == null) {
fIndenter= new RSourceIndenter(
RHeuristicTokenScanner.create(editor.getDocumentContentInfo()) );
}
final int startLine= selection.getStartLine(); // save before change
// if (length > 0 && document.getLineOffset(fLastLine) == start+length) {
// fLastLine--;
// }
final MultiTextEdit edits= new MultiTextEdit();
final List<? extends TextRegion> codeRanges= getCodeRanges(document, selection);
for (final TextRegion region : codeRanges) {
final int rStartLine= document.getLineOfOffset(Math.max(selection.getOffset(), region.getStartOffset()));
int rEndLine= document.getLineOfOffset(Math.min(selection.getOffset() + selection.getLength(), region.getEndOffset()));
final int rEndLineOffset= document.getLineOffset(rEndLine);
if (rEndLineOffset == region.getEndOffset()
|| (rStartLine < rEndLine && rEndLineOffset == selection.getOffset() + selection.getLength())) {
rEndLine--;
}
if (rStartLine <= rEndLine) {
this.fIndenter.setup((su instanceof IRSourceUnit) ? ((IRSourceUnit) su).getRCoreAccess() : RCore.getWorkbenchAccess());
final TextEdit rEdits= this.fIndenter.getIndentEdits(document, ast.getRoot(),
region.getStartOffset(), rStartLine, rEndLine );
if (rEdits.getChildrenSize() > 0) {
edits.addChild(rEdits);
}
}
}
if (edits.getChildrenSize() > 0) {
su.syncExec(new SourceDocumentRunnable(document, ast.getStamp().getSourceStamp(),
DocumentRewriteSessionType.SEQUENTIAL ) {
@Override
public void run() throws InvocationTargetException {
try {
edits.apply(getDocument(), TextEdit.NONE);
}
catch (final MalformedTreeException e) {
throw new InvocationTargetException(e);
}
catch (final BadLocationException e) {
throw new InvocationTargetException(e);
}
}
});
}
if (selection.getLength() == 0) {
final int newPos= fIndenter.getNewIndentOffset(startLine);
if (newPos >= 0) {
UIAccess.getDisplay().syncExec(new Runnable() {
@Override
public void run() {
if (UIAccess.isOkToUse(editor.getViewer())) {
editor.selectAndReveal(newPos, 0);
}
}
});
}
}
}
protected List<? extends TextRegion> getCodeRanges(final AbstractDocument document,
final ITextSelection selection) throws BadLocationException {
final List<TextRegion> regions= new ArrayList<>(1);
regions.add(new BasicTextRegion(0, document.getLength()));
return regions;
}
}