
com.jetbrains.python.refactoring.extractmethod.PyExtractMethodHandler Maven / Gradle / Ivy
Go to download
A packaging of the IntelliJ Community Edition python-community library.
This is release number 1 of trunk branch 142.
The newest version!
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.refactoring.extractmethod;
import com.intellij.codeInsight.codeFragment.CannotCreateCodeFragmentException;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Couple;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.RefactoringActionHandler;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.codeInsight.codeFragment.PyCodeFragment;
import com.jetbrains.python.codeInsight.codeFragment.PyCodeFragmentUtil;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import com.jetbrains.python.refactoring.PyRefactoringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author oleg
*/
public class PyExtractMethodHandler implements RefactoringActionHandler {
@Override
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file, final DataContext dataContext) {
editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
// select editor text fragment
if (!editor.getSelectionModel().hasSelection()) {
editor.getSelectionModel().selectLineAtCaret();
}
invokeOnEditor(project, editor, file);
}
@Override
public void invoke(@NotNull final Project project, @NotNull final PsiElement[] elements, final DataContext dataContext) {
}
private static void invokeOnEditor(final Project project, final Editor editor, final PsiFile file) {
CommonRefactoringUtil.checkReadOnlyStatus(project, file);
PsiElement element1 = null;
PsiElement element2 = null;
final SelectionModel selectionModel = editor.getSelectionModel();
if (selectionModel.hasSelection()) {
element1 = file.findElementAt(selectionModel.getSelectionStart());
element2 = file.findElementAt(selectionModel.getSelectionEnd() - 1);
}
else {
final CaretModel caretModel = editor.getCaretModel();
final Document document = editor.getDocument();
int lineNumber = document.getLineNumber(caretModel.getOffset());
if ((lineNumber >= 0) && (lineNumber < document.getLineCount())) {
element1 = file.findElementAt(document.getLineStartOffset(lineNumber));
element2 = file.findElementAt(document.getLineEndOffset(lineNumber) - 1);
}
}
// Pass comments and whitespaces
element1 = PyPsiUtils.getNextSignificantLeaf(element1, false);
element2 = PyPsiUtils.getPrevSignificantLeaf(element2, false);
if (element1 == null || element2 == null) {
CommonRefactoringUtil.showErrorHint(project, editor,
PyBundle.message("refactoring.extract.method.error.bad.selection"),
RefactoringBundle.message("extract.method.title"), "refactoring.extractMethod");
return;
}
if (rangeBelongsToSameClassBody(element1, element2)) {
CommonRefactoringUtil.showErrorHint(project, editor, PyBundle.message("refactoring.extract.method.error.class.level"),
RefactoringBundle.message("extract.method.title"), "refactoring.extractMethod");
return;
}
final Couple statements = getStatementsRange(element1, element2);
if (statements != null) {
final ScopeOwner owner = PsiTreeUtil.getParentOfType(statements.getFirst(), ScopeOwner.class);
if (owner == null) {
return;
}
final PyCodeFragment fragment;
try {
fragment = PyCodeFragmentUtil.createCodeFragment(owner, element1, element2);
}
catch (CannotCreateCodeFragmentException e) {
CommonRefactoringUtil.showErrorHint(project, editor, e.getMessage(),
RefactoringBundle.message("extract.method.title"), "refactoring.extractMethod");
return;
}
PyExtractMethodUtil.extractFromStatements(project, editor, fragment, statements.getFirst(), statements.getSecond());
return;
}
final PsiElement expression = PyRefactoringUtil.getSelectedExpression(project, file, element1, element2);
if (expression != null) {
final ScopeOwner owner = PsiTreeUtil.getParentOfType(element1, ScopeOwner.class);
if (owner == null) {
return;
}
final PyCodeFragment fragment;
try {
fragment = PyCodeFragmentUtil.createCodeFragment(owner, element1, element2);
}
catch (CannotCreateCodeFragmentException e) {
CommonRefactoringUtil.showErrorHint(project, editor, e.getMessage(),
RefactoringBundle.message("extract.method.title"), "refactoring.extractMethod");
return;
}
PyExtractMethodUtil.extractFromExpression(project, editor, fragment, expression);
return;
}
CommonRefactoringUtil.showErrorHint(project, editor,
PyBundle.message("refactoring.extract.method.error.bad.selection"),
RefactoringBundle.message("extract.method.title"), "refactoring.extractMethod");
}
private static boolean rangeBelongsToSameClassBody(@NotNull PsiElement element1, @NotNull PsiElement element2) {
final PyClass firstScopeOwner = PsiTreeUtil.getParentOfType(element1, PyClass.class, false, ScopeOwner.class);
final PyClass secondScopeOwner = PsiTreeUtil.getParentOfType(element2, PyClass.class, false, ScopeOwner.class);
return firstScopeOwner != null && firstScopeOwner == secondScopeOwner;
}
@Nullable
private static Couple getStatementsRange(final PsiElement element1, final PsiElement element2) {
final PsiElement parent = PsiTreeUtil.findCommonParent(element1, element2);
if (parent == null) {
return null;
}
final PyElement statementList = PyPsiUtils.getStatementList(parent);
if (statementList == null) {
return null;
}
final PsiElement statement1 = PyPsiUtils.getParentRightBefore(element1, statementList);
final PsiElement statement2 = PyPsiUtils.getParentRightBefore(element2, statementList);
if (statement1 == null || statement2 == null){
return null;
}
// return elements if they are really first and last elements of statements
if (element1 == PsiTreeUtil.getDeepestFirst(statement1) &&
element2 == PyPsiUtils.getPrevSignificantLeaf(PsiTreeUtil.getDeepestLast(statement2), !(element2 instanceof PsiComment))) {
return Couple.of(statement1, statement2);
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy