PostprocessReformattingAspect rewrite

This commit is contained in:
Dmitry Jemerov
2010-02-16 21:58:47 +03:00
parent d1ceea042e
commit b1231ccb1e
15 changed files with 105 additions and 104 deletions

View File

@@ -32,7 +32,7 @@ public class PyTokenSeparatorGenerator implements TokenSeparatorGenerator {
final PsiElement leftPrevAncestor = PsiTreeUtil.findPrevParent(commonParent, left.getPsi());
final PsiElement rightPrevAncestor = PsiTreeUtil.findPrevParent(commonParent, right.getPsi());
if (leftPrevAncestor instanceof PyFunction && rightPrevAncestor instanceof PyFunction) {
if (isStatementOrFunction(leftPrevAncestor) && isStatementOrFunction(rightPrevAncestor)) {
int leftIndent = PyPsiUtils.getElementIndentation(leftPrevAncestor);
int rightIndent = PyPsiUtils.getElementIndentation(rightPrevAncestor);
int maxIndent = Math.max(leftIndent, rightIndent);
@@ -57,6 +57,10 @@ public class PyTokenSeparatorGenerator implements TokenSeparatorGenerator {
return null;
}
private static boolean isStatementOrFunction(PsiElement element) {
return element instanceof PyFunction || element instanceof PyStatement;
}
private static ASTNode createSpace(PsiManager manager) {
return createWhitespace(manager, " ");
}

View File

@@ -26,7 +26,7 @@ import static com.jetbrains.python.psi.PyUtil.sure;
/**
* @author yole
*/
public class PyBlock implements Block {
public class PyBlock implements ASTBlock {
private final PythonLanguage _language;
private final Alignment _alignment;
private final Indent _indent;
@@ -193,6 +193,10 @@ public class PyBlock implements Block {
if (isStatementOrDeclaration(type1) && isStatementOrDeclaration(type2)) {
return Spacing.createSpacing(0, Integer.MAX_VALUE, 1, false, 1);
}
if (type1 == PyTokenTypes.COLON && type2 == PyElementTypes.STATEMENT_LIST) {
return Spacing.createSpacing(1, Integer.MAX_VALUE, 0, true, 0);
}
/*
if (type1 == PyTokenTypes.COLON && type2 == PyElementTypes.STATEMENT_LIST) {
return Spacing.createSpacing(0, Integer.MAX_VALUE, 1, true, Integer.MAX_VALUE);

View File

@@ -159,6 +159,7 @@ public class PyBaseElementImpl<T extends StubElement> extends StubBasedPsiElemen
}
public PsiElement replace(@NotNull PsiElement element) throws IncorrectOperationException {
/*
PsiElement parent = getParent();
if (parent != null) {
return replacePyChild(this, element);
@@ -166,6 +167,8 @@ public class PyBaseElementImpl<T extends StubElement> extends StubBasedPsiElemen
else {
return super.replace(element);
}
*/
return super.replace(element);
}
public static PsiElement replacePyChild(final PyElement oldel, final PsiElement newel) throws IncorrectOperationException {
@@ -174,4 +177,4 @@ public class PyBaseElementImpl<T extends StubElement> extends StubBasedPsiElemen
return copy;
}
}
}

View File

@@ -3,8 +3,6 @@ package com.jetbrains.python.psi.impl;
import com.intellij.codeInsight.controlflow.ControlFlow;
import com.intellij.extapi.psi.PsiFileBase;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
@@ -29,7 +27,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;
@@ -295,16 +292,16 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
@Override
public PsiElement add(@NotNull PsiElement element) throws IncorrectOperationException {
return super.add(PyPsiUtils.preprocessElement(element));
return super.add(PyPsiUtils.removeIndentation(element));
}
@Override
public PsiElement addBefore(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException {
return super.addBefore(PyPsiUtils.preprocessElement(element), anchor);
return super.addBefore(PyPsiUtils.removeIndentation(element), anchor);
}
@Override
public PsiElement addAfter(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException {
return super.addAfter(PyPsiUtils.preprocessElement(element), anchor);
return super.addAfter(PyPsiUtils.removeIndentation(element), anchor);
}
}

View File

@@ -1,7 +1,11 @@
package com.jetbrains.python.psi.impl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.jetbrains.python.PythonFileType;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.psi.PyElementGenerator;
import com.jetbrains.python.psi.PyFunction;
@@ -39,20 +43,26 @@ public class PyFunctionBuilder {
}
public PyFunction addFunction(PsiElement target) {
String text = buildText();
PyElementGenerator generator = PythonLanguage.getInstance().getElementGenerator();
PyFunction function = generator.createFromText(target.getProject(), PyFunction.class, text);
return (PyFunction) target.add(function);
return (PyFunction) target.add(buildFunction(target.getProject()));
}
private String buildText() {
public PyFunction buildFunction(Project project) {
String text = buildText(project);
PyElementGenerator generator = PythonLanguage.getInstance().getElementGenerator();
return generator.createFromText(project, PyFunction.class, text);
}
private String buildText(Project project) {
StringBuilder builder = new StringBuilder("def ");
builder.append(myName).append("(");
builder.append(StringUtil.join(myParameters, ", "));
builder.append("):");
List<String> statements = myStatements.isEmpty() ? Collections.singletonList("pass") : myStatements;
final CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getInstance(project).getCurrentSettings();
int indentSize = codeStyleSettings.getIndentOptions(PythonFileType.INSTANCE).INDENT_SIZE;
String indent = StringUtil.repeatSymbol(' ', indentSize);
for (String statement : statements) {
builder.append("\n ").append(statement);
builder.append("\n").append(indent).append(statement);
}
return builder.toString();
}

View File

@@ -176,7 +176,7 @@ public class PyPsiUtils {
* @return
*/
@NotNull
public static PyElement preprocessElement(final PsiElement element) {
public static PyElement removeIndentation(final PsiElement element) {
final int indentLength = getElementIndentation(element);
if (indentLength == 0 && element instanceof PyElement) {
return (PyElement) element;
@@ -219,4 +219,4 @@ public class PyPsiUtils {
}
return false;
}
}
}

View File

@@ -1,23 +1,6 @@
/*
* Copyright 2005 Pythonid Project
*
* 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.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.ResolveState;
@@ -25,19 +8,15 @@ import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.PsiCached;
import com.jetbrains.python.psi.PyElementVisitor;
import com.jetbrains.python.psi.PyStatement;
import com.jetbrains.python.psi.PyStatementList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
/**
* Created by IntelliJ IDEA.
* User: yole
* Date: 29.05.2005
* Time: 16:39:47
* To change this template use File | Settings | File Templates.
* @author yole
*/
public class PyStatementListImpl extends PyElementImpl implements PyStatementList {
public PyStatementListImpl(ASTNode astNode) {
@@ -92,7 +71,13 @@ public class PyStatementListImpl extends PyElementImpl implements PyStatementLis
public PsiElement add(@NotNull PsiElement element) throws IncorrectOperationException {
final PsiElement preprocessed = preprocessElement(element);
if (preprocessed != null){
return super.add(preprocessed);
final PsiElement result = super.add(preprocessed.copy());
/*
if (result instanceof PyFunction) {
CodeStyleManager.getInstance(getManager()).adjustLineIndent(getContainingFile(), result.getTextRange());
}
*/
return result;
}
return super.add(element);
}
@@ -118,6 +103,7 @@ public class PyStatementListImpl extends PyElementImpl implements PyStatementLis
@Nullable
private PsiElement preprocessElement(PsiElement element) {
if (element instanceof PsiWhiteSpace) return element;
return PyPsiUtils.preprocessElement(element);
return PyPsiUtils.removeIndentation(element);
//return element;
}
}

View File

@@ -108,17 +108,20 @@ public class PyClassRefactoringUtil {
final String text = prepareClassText(superClass, elements, up, false, null);
if (text == null) return;
System.out.println("createClassFromText:" + text);
final PyClass newClass = PythonLanguage.getInstance().getElementGenerator().createFromText(project, PyClass.class, text);
final PyStatementList statements = superClass.getStatementList();
if (statements.getStatements().length != 0) {
for (PyElement newStatement : newClass.getStatementList().getStatements()) {
System.out.println("adding statement: " + newStatement.getText());
//statements.add(PythonLanguage.getInstance().getElementGenerator().createNewLine(project));
statements.add(newStatement);
}
} else {
statements.replace(newClass.getStatementList());
}
System.out.println("new class text: " + superClass.getText());
}
@Nullable

View File

@@ -10,8 +10,10 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.PsiRecursiveElementVisitor;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.RefactoringFactory;
@@ -25,6 +27,7 @@ import com.intellij.util.containers.hash.HashMap;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyFunctionBuilder;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
@@ -246,21 +249,16 @@ public class PyExtractMethodUtil {
}
}
// Change signature according to pass settings and
final StringBuilder builder = new StringBuilder();
builder.append("def foo(");
final String params = createMethodParamsString(variableData, false);
if (isMethod){
builder.append("self");
if (params.length() != 0){
builder.append(", ");
builder.append(params);
}
} else {
builder.append(params);
PyFunctionBuilder builder = new PyFunctionBuilder("foo");
if (isMethod) {
builder.parameter("self");
}
builder.append(")\n pass");
final PyParameterList pyParameterList =
PythonLanguage.getInstance().getElementGenerator().createFromText(project, PyFunction.class, builder.toString()).getParameterList();
for (AbstractVariableData data : variableData) {
if (data.isPassAsParameter()) {
builder.parameter(data.getName());
}
}
final PyParameterList pyParameterList = builder.buildFunction(project).getParameterList();
generatedMethod.getParameterList().replace(pyParameterList);
}
@@ -274,48 +272,39 @@ public class PyExtractMethodUtil {
private static PyFunction insertGeneratedMethod(PsiElement anchor, final PyFunction generatedMethod) {
final Pair<PsiElement, TextRange> data = anchor.getUserData(PyPsiUtils.SELECTION_BREAKS_AST_NODE);
if (data != null){
if (data != null) {
anchor = data.first;
}
final PsiNamedElement parent = PsiTreeUtil.getParentOfType(anchor, PyFile.class, PyClass.class, PyFunction.class);
PsiElement result;
if (parent instanceof PyFile || parent instanceof PyClass) {
final PsiElement statement = PyPsiUtils.getStatement(parent, anchor);
return (PyFunction) parent.addBefore(generatedMethod, statement);
PsiElement target = parent instanceof PyClass ? ((PyClass)parent).getStatementList() : parent;
final PsiElement anchorStatement = PyPsiUtils.getStatement(target, anchor);
result = target.addBefore(generatedMethod, anchorStatement);
}
return (PyFunction) parent.getParent().addBefore(generatedMethod, parent);
}
// Creates string for method parameters
private static String createMethodParamsString(final AbstractVariableData[] variableDatas, final boolean fakeSignature) {
final StringBuilder builder = new StringBuilder();
for (AbstractVariableData data : variableDatas) {
if (fakeSignature || data.isPassAsParameter()) {
if (builder.length() != 0) {
builder.append(", ");
}
builder.append(fakeSignature ? data.getOriginalName() : data.getName());
else {
result = parent.getParent().addBefore(generatedMethod, parent);
}
// to ensure correct reformatting, mark the entire method as generated
result.accept(new PsiRecursiveElementVisitor() {
@Override
public void visitElement(PsiElement element) {
super.visitElement(element);
CodeEditUtil.setNodeGenerated(element.getNode(), true);
}
}
return builder.toString();
}
private static String generateSignature(final String methodName, final AbstractVariableData[] variableData, final PsiElement expression) {
final StringBuilder builder = new StringBuilder();
builder.append("def ").append(methodName).append("(");
builder.append(createMethodParamsString(variableData, true));
builder.append("):\n");
return builder.toString();
});
return (PyFunction)result;
}
private static PyFunction generateMethodFromExpression(final Project project,
final String methodName,
final AbstractVariableData[] variableData,
final PsiElement expression) {
final StringBuilder builder = new StringBuilder();
builder.append(generateSignature(methodName, variableData, expression));
builder.append(" return ").append(expression.getText());
return PythonLanguage.getInstance().getElementGenerator().createFromText(project, PyFunction.class, builder.toString());
final PyFunctionBuilder builder = new PyFunctionBuilder(methodName);
addFakeParameters(builder, variableData);
builder.statement("return " + expression.getText());
return builder.buildFunction(project);
}
private static PyFunction generateMethodFromElements(final Project project,
@@ -323,13 +312,12 @@ public class PyExtractMethodUtil {
final AbstractVariableData[] variableData,
final List<PsiElement> elementsRange) {
assert !elementsRange.isEmpty() : "Empty statements list was selected!";
final StringBuilder builder = new StringBuilder();
builder.append(generateSignature(methodName, variableData, elementsRange.get(0)));
builder.append(" pass\n");
final PyElementGenerator pyElementGenerator = PythonLanguage.getInstance().getElementGenerator();
final PyFunction method =
pyElementGenerator.createFromText(project, PyFunction.class, builder.toString());
final PyFunctionBuilder builder = new PyFunctionBuilder(methodName);
addFakeParameters(builder, variableData);
final PyFunction method = builder.buildFunction(project);
final PyStatementList statementList = method.getStatementList();
for (PsiElement element : elementsRange) {
if (element instanceof PsiWhiteSpace){
continue;
@@ -341,6 +329,12 @@ public class PyExtractMethodUtil {
return method;
}
private static void addFakeParameters(PyFunctionBuilder builder, AbstractVariableData[] variableData) {
for (AbstractVariableData data : variableData) {
builder.parameter(data.getOriginalName());
}
}
private static Pair<String, AbstractVariableData[]> getNameAndVariableData(final Project project,
final CodeFragment fragment,
final PsiElement element) {

View File

@@ -3,4 +3,4 @@ def bar():
print("Hello")
def foo():
bar()
bar()

View File

@@ -1,3 +1,3 @@
#Comment to method
def foo():
<selection>print("Hello")</selection>
<selection>print("Hello")</selection>

View File

@@ -3,5 +3,5 @@ def bar(base_new, self_new):
except AttributeError: pass
def __init__(self):
for base in self__class__.__bases__:
bar(base, self)
for base in self__class__.__bases__:
bar(base, self)

View File

@@ -1,4 +1,4 @@
def __init__(self):
for base in self__class__.__bases__:
<selection>try: base.__init__(self)
except AttributeError: pass</selection>
for base in self__class__.__bases__:
<selection>try: base.__init__(self)
except AttributeError: pass</selection>

View File

@@ -1,5 +1,4 @@
class A:
pass
class B(A):
@@ -22,4 +21,4 @@ class D(A):
pass
def meth_a2(self):
pass
pass

View File

@@ -28,6 +28,7 @@ public class PyExtractMethodTest extends LightMarkedTestCase {
handler.invoke(myFixture.getProject(), myFixture.getEditor(), myFixture.getFile(), new FileDataContext(myFixture.getFile()));
}
catch (Exception e) {
e.printStackTrace();
assertEquals(result, e.getMessage());
return;
}
@@ -125,4 +126,4 @@ public class PyExtractMethodTest extends LightMarkedTestCase {
public void testClass() throws Throwable {
doTest("context/class.before.py", "bar", "context/class.after.py");
}
}
}