mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
PostprocessReformattingAspect rewrite
This commit is contained in:
@@ -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, " ");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -3,4 +3,4 @@ def bar():
|
||||
print("Hello")
|
||||
|
||||
def foo():
|
||||
bar()
|
||||
bar()
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#Comment to method
|
||||
def foo():
|
||||
<selection>print("Hello")</selection>
|
||||
<selection>print("Hello")</selection>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class A:
|
||||
|
||||
pass
|
||||
|
||||
class B(A):
|
||||
@@ -22,4 +21,4 @@ class D(A):
|
||||
pass
|
||||
|
||||
def meth_a2(self):
|
||||
pass
|
||||
pass
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user