Package ro.redeul.google.go.intentions.statements

Source Code of ro.redeul.google.go.intentions.statements.MoveSimpleStatementOutIntention

package ro.redeul.google.go.intentions.statements;

import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import ro.redeul.google.go.intentions.Intention;
import ro.redeul.google.go.intentions.IntentionExecutionException;
import ro.redeul.google.go.lang.lexer.GoTokenTypes;
import ro.redeul.google.go.lang.psi.expressions.GoExpr;
import ro.redeul.google.go.lang.psi.expressions.literals.GoLiteralIdentifier;
import ro.redeul.google.go.lang.psi.statements.GoForWithClausesStatement;
import ro.redeul.google.go.lang.psi.statements.GoIfStatement;
import ro.redeul.google.go.lang.psi.statements.GoSimpleStatement;
import ro.redeul.google.go.lang.psi.statements.GoStatement;
import ro.redeul.google.go.lang.psi.statements.switches.GoSwitchExpressionStatement;
import ro.redeul.google.go.lang.psi.statements.switches.GoSwitchTypeStatement;
import ro.redeul.google.go.lang.psi.visitors.GoRecursiveElementVisitor;

import java.util.*;

import static com.intellij.psi.util.PsiTreeUtil.findFirstParent;
import static ro.redeul.google.go.lang.psi.utils.GoPsiUtils.*;
import static ro.redeul.google.go.util.EditorUtil.reformatPositions;

public class MoveSimpleStatementOutIntention extends Intention {

    private static final Comparator<PsiElement> REVERSE_POSITION_COMPARATOR = new Comparator<PsiElement>() {
        @Override
        public int compare(PsiElement o1, PsiElement o2) {
            return o2.getTextOffset() - o1.getTextOffset();
        }
    };

    @Override
    protected boolean satisfiedBy(PsiElement element) {
        return isInIfStatement(element) ||
               isInSwitchStatement(element) ||
               isInForClauseStatement(element);
    }

    private static boolean isInIfStatement(PsiElement element) {
        GoIfStatement stmt = findParentOfType(element, GoIfStatement.class);
        if (stmt == null) {
            return false;
        }

        GoSimpleStatement ss = stmt.getSimpleStatement();
        return ss != null && ss.getTextRange().contains(element.getTextRange());
    }

    private static boolean isInSwitchStatement(PsiElement element) {
        GoSwitchExpressionStatement seStmt = findParentOfType(element, GoSwitchExpressionStatement.class);
        if (seStmt != null) {
            GoSimpleStatement ss = seStmt.getSimpleStatement();
            return ss != null && ss.getTextRange().contains(element.getTextRange());
        }

        GoSwitchTypeStatement stStmt = findParentOfType(element, GoSwitchTypeStatement.class);
        if (stStmt != null) {
            GoSimpleStatement ss = stStmt.getSimpleStatement();
            return ss != null && ss.getTextRange().contains(element.getTextRange());
        }
        return false;
    }

    private static boolean isInForClauseStatement(PsiElement element) {
        GoForWithClausesStatement forStatement = findParentOfType(element, GoForWithClausesStatement.class);
        if (forStatement == null) {
            return false;
        }

        GoStatement statement = forStatement.getInitialStatement();
        return statement != null && statement.getTextRange().contains(element.getTextRange());
    }

    @Override
    protected void processIntention(@NotNull PsiElement element, Editor editor)
            throws IntentionExecutionException {
        GoIfStatement ifStatement = findParentOfType(element, GoIfStatement.class);
        if (ifStatement != null) {
            moveSimpleStatementOut(editor, ifStatement);
            return;
        }

        GoSwitchExpressionStatement seStmt = findParentOfType(element, GoSwitchExpressionStatement.class);
        if (seStmt != null) {
            moveSimpleStatementOut(editor, seStmt);
            return;
        }

        GoSwitchTypeStatement stStmt = findParentOfType(element, GoSwitchTypeStatement.class);
        if (stStmt != null) {
            moveSimpleStatementOut(editor, stStmt);
            return;
        }

        GoForWithClausesStatement forStatement = findParentOfType(element, GoForWithClausesStatement.class);
        if (forStatement != null) {
            moveSimpleStatementOut(editor, forStatement);
        }
    }

    private static void moveSimpleStatementOut(Editor editor, GoForWithClausesStatement forStatement) {
        GoStatement simpleStatement = forStatement.getInitialStatement();
        PsiElement semi = findChildOfType(forStatement, GoTokenTypes.oSEMI);
        if (simpleStatement == null || semi == null) {
            return;
        }

        int start = simpleStatement.getTextOffset();
        int end = semi.getTextOffset();
        move(editor, forStatement, simpleStatement.getText(), start, end);
    }

    private static void moveSimpleStatementOut(Editor editor, GoSwitchTypeStatement stStmt) {
        GoSimpleStatement simpleStatement = stStmt.getSimpleStatement();
        PsiElement endElement = stStmt.getTypeGuard();
        endElement = endElement.getPrevSibling();

        if (simpleStatement == null || endElement == null) {
            return;
        }

        int start = simpleStatement.getTextOffset();
        int end = endElement.getTextRange().getEndOffset();
        move(editor, stStmt, simpleStatement.getText(), start, end);
    }

    private static void moveSimpleStatementOut(Editor editor, GoSwitchExpressionStatement seStmt) {
        GoSimpleStatement simpleStatement = seStmt.getSimpleStatement();
        PsiElement endElement = seStmt.getExpression();
        if (endElement == null) {
            endElement = findChildOfType(seStmt, GoTokenTypes.oSEMI);
        } else {
            endElement = endElement.getPrevSibling();
        }

        if (simpleStatement == null || endElement == null) {
            return;
        }

        int start = simpleStatement.getTextOffset();
        int end = endElement.getTextRange().getEndOffset();
        move(editor, seStmt, simpleStatement.getText(), start, end);
    }

    private static void move(Editor editor, final GoStatement statement, final String declaration, final int start, final int end) {
        final Document document = editor.getDocument();
        RangeMarker range = document.createRangeMarker(statement.getTextOffset(), end);
        WriteCommandAction writeCommandAction = new WriteCommandAction(editor.getProject()) {
            @Override
            protected void run(@NotNull Result result) throws Throwable {
                document.deleteString(start, end);
                document.insertString(statement.getTextOffset(), declaration + "\n");
            }
        };
        writeCommandAction.execute();
        reformatPositions(statement.getContainingFile(), range);
    }

    public static void moveSimpleStatementOut(Editor editor, GoIfStatement ifStatement) {
        final GoSimpleStatement simpleStatement = ifStatement.getSimpleStatement();
        final GoExpr condition = ifStatement.getExpression();
        if (simpleStatement == null || condition == null) {
            return;
        }

        moveDependentSimpleStatementsFirst(editor, ifStatement, simpleStatement);

        PsiElement outermostIf = ifStatement;
        while (outermostIf instanceof GoIfStatement && outermostIf.getParent() instanceof GoIfStatement) {
            outermostIf = outermostIf.getParent();
        }

        final Document document = editor.getDocument();
        RangeMarker range = document.createRangeMarker(outermostIf.getTextOffset(), condition.getTextOffset());
        final PsiElement finalOutermostIf = outermostIf;
        WriteCommandAction writeCommandAction = new WriteCommandAction(ifStatement.getContainingFile().getProject()) {
            @Override
            protected void run(@NotNull Result result) throws Throwable {
                document.deleteString(simpleStatement.getTextOffset(), condition.getTextOffset());
                document.insertString(finalOutermostIf.getTextOffset(), simpleStatement.getText() + "\n");
            }
        };
        writeCommandAction.execute();
        reformatPositions(ifStatement.getContainingFile(), range);
    }

    private static void moveDependentSimpleStatementsFirst(Editor editor, GoIfStatement ifStatement,
                                                           GoSimpleStatement simpleStatement) {
        List<GoIfStatement> dependentIfs = findAllDependentIfs(ifStatement, simpleStatement);
        Collections.sort(dependentIfs, REVERSE_POSITION_COMPARATOR);

        for (GoIfStatement dependent : dependentIfs) {
            moveSimpleStatementOut(editor, dependent);
        }
    }

    private static List<GoIfStatement> findAllDependentIfs(GoIfStatement ifStatement,
                                                           GoSimpleStatement simpleStatement) {
        final List<GoIfStatement> dependentIfs = new ArrayList<GoIfStatement>();
        final Set<GoIfStatement> outerIfs = findAllOuterIfs(ifStatement);

        new GoRecursiveElementVisitor() {
            @Override
            public void visitLiteralIdentifier(GoLiteralIdentifier identifier) {
                PsiElement resolve = resolveSafely(identifier, PsiElement.class);
                if (resolve == null) {
                    return;
                }

                PsiElement parent = findFirstParent(resolve, new Condition<PsiElement>() {
                    @Override
                    public boolean value(PsiElement element) {
                        return element instanceof GoIfStatement && outerIfs.contains(element);
                    }
                });

                if (parent instanceof GoIfStatement) {
                    dependentIfs.add((GoIfStatement) parent);
                }
            }
        }.visitElement(simpleStatement);
        return dependentIfs;
    }

    private static Set<GoIfStatement> findAllOuterIfs(GoIfStatement ifStatement) {
        final Set<GoIfStatement> outerIfs = new HashSet<GoIfStatement>();
        while (ifStatement != null && ifStatement.getParent() instanceof GoIfStatement) {
            ifStatement = (GoIfStatement) ifStatement.getParent();
            outerIfs.add(ifStatement);
        }
        return outerIfs;
    }
}
TOP

Related Classes of ro.redeul.google.go.intentions.statements.MoveSimpleStatementOutIntention

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.