mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -28,7 +28,15 @@ public abstract class PyRunConfigurationFactory {
|
||||
return ServiceManager.getService(PyRunConfigurationFactory.class);
|
||||
}
|
||||
|
||||
public abstract PythonRunConfigurationParams createPythonScriptRunConfiguration(Module module, String scriptName);
|
||||
/**
|
||||
* Creates a run configuration to run a specified Python script.
|
||||
*
|
||||
* @param module the module in the context of which the script is run.
|
||||
* @param scriptName the path to the script file.
|
||||
* @param singleton if true, the "Check no other instances are running" option will be set for the run configuration.
|
||||
* @return the settings of the created run configuration.
|
||||
*/
|
||||
public abstract PythonRunConfigurationParams createPythonScriptRunConfiguration(Module module, String scriptName, boolean singleton);
|
||||
|
||||
public abstract RunnerAndConfigurationSettings createRunConfiguration(Module module, ConfigurationFactory factory);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.editor.PythonEnterHandler;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -30,13 +31,12 @@ public class RemoveUnnecessaryBackslashQuickFix implements LocalQuickFix {
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiElement problemElement = descriptor.getPsiElement();
|
||||
if (problemElement != null) {
|
||||
PyElement parent = PsiTreeUtil.getParentOfType(problemElement, PySequenceExpression.class, PyDictLiteralExpression.class,
|
||||
PyParenthesizedExpression.class, PyArgumentList.class, PyParameterList.class);
|
||||
PsiElement parent = PsiTreeUtil.getParentOfType(problemElement, PythonEnterHandler.IMPLICIT_WRAP_CLASSES);
|
||||
removeBackSlash(parent);
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeBackSlash(PyElement parent) {
|
||||
private static void removeBackSlash(PsiElement parent) {
|
||||
if (parent != null) {
|
||||
Stack<PsiElement> stack = new Stack<PsiElement>();
|
||||
if (parent instanceof PyParenthesizedExpression)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.jetbrains.python.codeInsight.controlflow;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public interface InstructionTypeCallback {
|
||||
@Nullable
|
||||
PyType getType(TypeEvalContext context, @Nullable PsiElement anchor);
|
||||
}
|
||||
+17
-15
@@ -1,11 +1,12 @@
|
||||
package com.jetbrains.python.codeInsight.controlflow;
|
||||
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.containers.CollectionFactory;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.types.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -43,9 +44,9 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
final PyExpression typeElement = args[1];
|
||||
final boolean positive = myPositive;
|
||||
if (!processTuple(target, typeElement)) {
|
||||
pushAssertion(target, new Function<TypeEvalContext, PyType>() {
|
||||
pushAssertion(target, new InstructionTypeCallback() {
|
||||
@Override
|
||||
public PyType fun(TypeEvalContext context) {
|
||||
public PyType getType(TypeEvalContext context, PsiElement anchor) {
|
||||
final List<PyType> types = new ArrayList<PyType>();
|
||||
types.add(context.getType(typeElement));
|
||||
return createAssertionType(context.getType(target), types, positive, context);
|
||||
@@ -59,9 +60,9 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
if (args.length == 1 && args[0] instanceof PyReferenceExpression) {
|
||||
final PyReferenceExpression target = (PyReferenceExpression)args[0];
|
||||
final boolean positive = myPositive;
|
||||
pushAssertion(target, new Function<TypeEvalContext, PyType>() {
|
||||
pushAssertion(target, new InstructionTypeCallback() {
|
||||
@Override
|
||||
public PyType fun(TypeEvalContext context) {
|
||||
public PyType getType(TypeEvalContext context, PsiElement anchor) {
|
||||
final List<PyType> types = new ArrayList<PyType>();
|
||||
types.add(PyTypeParser.getTypeByName(target, PyNames.CALLABLE));
|
||||
return createAssertionType(context.getType(target), types, positive, context);
|
||||
@@ -74,9 +75,9 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
@Override
|
||||
public void visitPyReferenceExpression(final PyReferenceExpression node) {
|
||||
if (node.getParent() instanceof PyIfPart) {
|
||||
pushAssertion(node, new Function<TypeEvalContext, PyType>() {
|
||||
pushAssertion(node, new InstructionTypeCallback() {
|
||||
@Override
|
||||
public PyType fun(TypeEvalContext context) {
|
||||
public PyType getType(TypeEvalContext context, PsiElement anchor) {
|
||||
final List<PyType> types = new ArrayList<PyType>();
|
||||
types.add(PyNoneType.INSTANCE);
|
||||
return createAssertionType(context.getType(node), types, false, context);
|
||||
@@ -95,9 +96,9 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
if (lhs instanceof PyReferenceExpression && rhs instanceof PyReferenceExpression) {
|
||||
final PyReferenceExpression target = (PyReferenceExpression)lhs;
|
||||
if (PyNames.NONE.equals(rhs.getName())) {
|
||||
pushAssertion(target, new Function<TypeEvalContext, PyType>() {
|
||||
pushAssertion(target, new InstructionTypeCallback() {
|
||||
@Override
|
||||
public PyType fun(TypeEvalContext context) {
|
||||
public PyType getType(TypeEvalContext context, @Nullable PsiElement anchor) {
|
||||
final List<PyType> types = new ArrayList<PyType>();
|
||||
types.add(PyNoneType.INSTANCE);
|
||||
return createAssertionType(context.getType(target), types, false, context);
|
||||
@@ -117,9 +118,9 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
if (contained instanceof PyTupleExpression) {
|
||||
final PyTupleExpression tuple = (PyTupleExpression)contained;
|
||||
final boolean positive = myPositive;
|
||||
pushAssertion(target, new Function<TypeEvalContext, PyType>() {
|
||||
pushAssertion(target, new InstructionTypeCallback() {
|
||||
@Override
|
||||
public PyType fun(TypeEvalContext context) {
|
||||
public PyType getType(TypeEvalContext context, @Nullable PsiElement anchor) {
|
||||
final List<PyType> types = new ArrayList<PyType>();
|
||||
for (PyExpression e : tuple.getElements()) {
|
||||
types.add(context.getType(e));
|
||||
@@ -133,6 +134,7 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
return pushed;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyType createAssertionType(PyType initial, List<PyType> types, boolean positive, TypeEvalContext context) {
|
||||
final List<PyType> members = new ArrayList<PyType>();
|
||||
for (PyType t : types) {
|
||||
@@ -151,15 +153,15 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
return initial;
|
||||
}
|
||||
|
||||
private void pushAssertion(PyReferenceExpression element, Function<TypeEvalContext, PyType> getType) {
|
||||
private void pushAssertion(PyReferenceExpression element, InstructionTypeCallback getType) {
|
||||
myStack.push(new Assertion(element, getType));
|
||||
}
|
||||
|
||||
static class Assertion {
|
||||
private final PyReferenceExpression element;
|
||||
private Function<TypeEvalContext, PyType> myFunction;
|
||||
private InstructionTypeCallback myFunction;
|
||||
|
||||
Assertion(PyReferenceExpression element, Function<TypeEvalContext, PyType> getType) {
|
||||
Assertion(PyReferenceExpression element, InstructionTypeCallback getType) {
|
||||
this.element = element;
|
||||
this.myFunction = getType;
|
||||
}
|
||||
@@ -168,7 +170,7 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
|
||||
return element;
|
||||
}
|
||||
|
||||
public Function<TypeEvalContext, PyType> getTypeEvalFunction() {
|
||||
public InstructionTypeCallback getTypeEvalFunction() {
|
||||
return myFunction;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,19 +3,28 @@ package com.jetbrains.python.codeInsight.controlflow;
|
||||
import com.intellij.codeInsight.controlflow.ControlFlowBuilder;
|
||||
import com.intellij.codeInsight.controlflow.impl.InstructionImpl;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.Function;
|
||||
import com.jetbrains.python.psi.PyElement;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.impl.PyTargetExpressionImpl;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ReadWriteInstruction extends InstructionImpl {
|
||||
final Function<TypeEvalContext, PyType> EXPR_TYPE = new Function<TypeEvalContext, PyType>() {
|
||||
final InstructionTypeCallback EXPR_TYPE = new InstructionTypeCallback() {
|
||||
@Nullable
|
||||
@Override
|
||||
public PyType fun(TypeEvalContext context) {
|
||||
return myElement instanceof PyExpression ? context.getType((PyExpression)myElement) : null;
|
||||
public PyType getType(TypeEvalContext context, @Nullable PsiElement anchor) {
|
||||
if (myElement instanceof PyTargetExpressionImpl) {
|
||||
return ((PyTargetExpressionImpl) myElement).getTypeWithAnchor(context, anchor);
|
||||
}
|
||||
if (myElement instanceof PyExpression) {
|
||||
return context.getType((PyExpression)myElement);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -50,7 +59,7 @@ public class ReadWriteInstruction extends InstructionImpl {
|
||||
|
||||
private final String myName;
|
||||
private final ACCESS myAccess;
|
||||
private final Function<TypeEvalContext, PyType> myGetType;
|
||||
private final InstructionTypeCallback myGetType;
|
||||
|
||||
private ReadWriteInstruction(final ControlFlowBuilder builder,
|
||||
final PsiElement element,
|
||||
@@ -63,7 +72,7 @@ public class ReadWriteInstruction extends InstructionImpl {
|
||||
final PsiElement element,
|
||||
final String name,
|
||||
final ACCESS access,
|
||||
@Nullable final Function<TypeEvalContext, PyType> getType) {
|
||||
@Nullable final InstructionTypeCallback getType) {
|
||||
super(builder, element);
|
||||
myName = name;
|
||||
myAccess = access;
|
||||
@@ -100,13 +109,13 @@ public class ReadWriteInstruction extends InstructionImpl {
|
||||
public static ReadWriteInstruction assertType(final ControlFlowBuilder builder,
|
||||
final PsiElement element,
|
||||
final String name,
|
||||
final Function<TypeEvalContext, PyType> getType) {
|
||||
final InstructionTypeCallback getType) {
|
||||
return new ReadWriteInstruction(builder, element, name, ACCESS.ASSERTTYPE, getType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PyType getType(TypeEvalContext context) {
|
||||
return myGetType.fun(context);
|
||||
public PyType getType(TypeEvalContext context, @Nullable PsiElement anchor) {
|
||||
return myGetType.getType(context, anchor);
|
||||
}
|
||||
|
||||
@NonNls
|
||||
|
||||
@@ -179,7 +179,7 @@ public class ScopeImpl implements Scope {
|
||||
|
||||
@Override
|
||||
public void visitPyElement(PyElement node) {
|
||||
if (node instanceof PsiNamedElement) {
|
||||
if (node instanceof PsiNamedElement && !(node instanceof PyKeywordArgument)) {
|
||||
namedElements.put(node.getName(), (PsiNamedElement)node);
|
||||
}
|
||||
// TODO: Cython-specific code
|
||||
|
||||
@@ -29,7 +29,15 @@ import org.jetbrains.annotations.Nullable;
|
||||
public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
private boolean needPostProcess = false;
|
||||
|
||||
private static final Class[] IMPLICIT_WRAP_CLASSES = new Class[]{
|
||||
public static final Class[] IMPLICIT_WRAP_CLASSES = new Class[] {
|
||||
PySequenceExpression.class,
|
||||
PyDictLiteralExpression.class,
|
||||
PyParenthesizedExpression.class,
|
||||
PyArgumentList.class,
|
||||
PyParameterList.class
|
||||
};
|
||||
|
||||
private static final Class[] WRAPPABLE_CLASSES = new Class[]{
|
||||
PsiComment.class,
|
||||
PyParenthesizedExpression.class,
|
||||
PyListCompExpression.class,
|
||||
@@ -116,13 +124,11 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
final boolean isEscapedBackslash = "\\".equals(doc.getText(TextRange.create(offset-2, offset - 1))) && nextIsBackslash;
|
||||
if (nextIsBackslash && !isEscapedQuote && !isEscapedBackslash) return Result.Continue;
|
||||
|
||||
final PsiElement parent = string.getParent();
|
||||
final StringBuilder replacementString = new StringBuilder();
|
||||
needPostProcess = true;
|
||||
if (parent instanceof PySequenceExpression || parent instanceof PyParenthesizedExpression ||
|
||||
parent instanceof PyBinaryExpression || parent instanceof PyKeyValueExpression ||
|
||||
parent instanceof PyNamedParameter || parent instanceof PyArgumentList) {
|
||||
replacementString.append(quote + pref + quote);
|
||||
|
||||
if (PsiTreeUtil.getParentOfType(string, IMPLICIT_WRAP_CLASSES) != null) {
|
||||
replacementString.append(quote).append(pref).append(quote);
|
||||
doc.insertString(offset, replacementString);
|
||||
caretOffset.set(caretOffset.get() + 1);
|
||||
return Result.Continue;
|
||||
@@ -132,7 +138,7 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
replacementString.append(quote);
|
||||
caretOffset.set(caretOffset.get() + 1);
|
||||
}
|
||||
replacementString.append(quote + " \\" + pref);
|
||||
replacementString.append(quote).append(" \\").append(pref);
|
||||
if (!isEscapedQuote)
|
||||
replacementString.append(quote);
|
||||
doc.insertString(offset, replacementString.toString());
|
||||
@@ -187,7 +193,7 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
PsiElement wrappableAfter = findWrappable(file, offset, false);
|
||||
if (!(wrappableBefore instanceof PsiComment)) {
|
||||
while (wrappableBefore != null) {
|
||||
PsiElement next = PsiTreeUtil.getParentOfType(wrappableBefore, IMPLICIT_WRAP_CLASSES);
|
||||
PsiElement next = PsiTreeUtil.getParentOfType(wrappableBefore, WRAPPABLE_CLASSES);
|
||||
if (next == null) {
|
||||
break;
|
||||
}
|
||||
@@ -196,7 +202,7 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
}
|
||||
if (!(wrappableAfter instanceof PsiComment)) {
|
||||
while (wrappableAfter != null) {
|
||||
PsiElement next = PsiTreeUtil.getParentOfType(wrappableAfter, IMPLICIT_WRAP_CLASSES);
|
||||
PsiElement next = PsiTreeUtil.getParentOfType(wrappableAfter, WRAPPABLE_CLASSES);
|
||||
if (next == null) {
|
||||
break;
|
||||
}
|
||||
@@ -234,8 +240,8 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
@Nullable
|
||||
private static PsiElement findWrappable(PsiFile file, int offset, boolean before) {
|
||||
PsiElement wrappable = before
|
||||
? findBeforeCaret(file, offset, IMPLICIT_WRAP_CLASSES)
|
||||
: findAfterCaret(file, offset, IMPLICIT_WRAP_CLASSES);
|
||||
? findBeforeCaret(file, offset, WRAPPABLE_CLASSES)
|
||||
: findAfterCaret(file, offset, WRAPPABLE_CLASSES);
|
||||
if (wrappable == null) {
|
||||
PsiElement emptyTuple = before
|
||||
? findBeforeCaret(file, offset, PyTupleExpression.class)
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
||||
import com.intellij.psi.impl.source.tree.TreeUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
@@ -29,12 +28,12 @@ import static com.jetbrains.python.psi.PyUtil.sure;
|
||||
* @author yole
|
||||
*/
|
||||
public class PyBlock implements ASTBlock {
|
||||
private final PyBlock myParent;
|
||||
private final Alignment _alignment;
|
||||
private final Indent _indent;
|
||||
private final ASTNode _node;
|
||||
private final Wrap _wrap;
|
||||
private final CommonCodeStyleSettings mySettings;
|
||||
private final SpacingBuilder mySpacingBuilder;
|
||||
private final PyBlockContext myContext;
|
||||
private List<PyBlock> _subBlocks = null;
|
||||
private Alignment myChildAlignment;
|
||||
private static final boolean DUMP_FORMATTING_BLOCKS = false;
|
||||
@@ -56,18 +55,18 @@ public class PyBlock implements ASTBlock {
|
||||
PyTokenTypes.LBRACE, PyTokenTypes.RBRACE,
|
||||
PyTokenTypes.LBRACKET, PyTokenTypes.RBRACKET);
|
||||
|
||||
public PyBlock(final ASTNode node,
|
||||
public PyBlock(final PyBlock parent,
|
||||
final ASTNode node,
|
||||
final Alignment alignment,
|
||||
final Indent indent,
|
||||
final Wrap wrap,
|
||||
final CommonCodeStyleSettings settings,
|
||||
SpacingBuilder spacingBuilder) {
|
||||
final PyBlockContext context) {
|
||||
myParent = parent;
|
||||
_alignment = alignment;
|
||||
_indent = indent;
|
||||
_node = node;
|
||||
_wrap = wrap;
|
||||
mySettings = settings;
|
||||
mySpacingBuilder = spacingBuilder;
|
||||
myContext = context;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -130,7 +129,7 @@ public class PyBlock implements ASTBlock {
|
||||
if (ourListElementTypes.contains(parentType)) {
|
||||
// wrapping in non-parenthesized tuple expression is not allowed (PY-1792)
|
||||
if ((parentType != PyElementTypes.TUPLE_EXPRESSION || grandparentType == PyElementTypes.PARENTHESIZED_EXPRESSION) &&
|
||||
!ourBrackets.contains(childType)) {
|
||||
!ourBrackets.contains(childType) && childType != PyTokenTypes.COMMA) {
|
||||
wrap = Wrap.createWrap(WrapType.NORMAL, true);
|
||||
}
|
||||
if (needListAlignment(child) && !isEmptyList(_node.getPsi())) {
|
||||
@@ -138,9 +137,15 @@ public class PyBlock implements ASTBlock {
|
||||
}
|
||||
}
|
||||
else if (parentType == PyElementTypes.BINARY_EXPRESSION &&
|
||||
PythonDialectsTokenSetProvider.INSTANCE.getExpressionTokens().contains(childType)) {
|
||||
childAlignment = getAlignmentForChildren();
|
||||
(PythonDialectsTokenSetProvider.INSTANCE.getExpressionTokens().contains(childType) || PyTokenTypes.OPERATIONS.contains(childType))) {
|
||||
if (grandparentType == PyElementTypes.BINARY_EXPRESSION && myParent != null) {
|
||||
childAlignment = myParent.getAlignmentForChildren();
|
||||
}
|
||||
else {
|
||||
childAlignment = getAlignmentForChildren();
|
||||
}
|
||||
}
|
||||
|
||||
if (parentType == PyElementTypes.LIST_LITERAL_EXPRESSION) {
|
||||
if (childType == PyTokenTypes.RBRACKET || childType == PyTokenTypes.LBRACKET) {
|
||||
childIndent = Indent.getNoneIndent();
|
||||
@@ -160,7 +165,7 @@ public class PyBlock implements ASTBlock {
|
||||
}
|
||||
}
|
||||
else if (parentType == PyElementTypes.DICT_LITERAL_EXPRESSION || parentType == PyElementTypes.SET_LITERAL_EXPRESSION) {
|
||||
if (childType == PyTokenTypes.RBRACE) {
|
||||
if (childType == PyTokenTypes.RBRACE || !hasLineBreaksBefore(child, 1)) {
|
||||
childIndent = Indent.getNoneIndent();
|
||||
}
|
||||
else {
|
||||
@@ -193,7 +198,7 @@ public class PyBlock implements ASTBlock {
|
||||
childIndent = Indent.getNormalIndent();
|
||||
}
|
||||
|
||||
return new PyBlock(child, childAlignment, childIndent, wrap, mySettings, mySpacingBuilder);
|
||||
return new PyBlock(this, child, childAlignment, childIndent, wrap, myContext);
|
||||
}
|
||||
|
||||
private static boolean isEmptyList(PsiElement psi) {
|
||||
@@ -224,29 +229,39 @@ public class PyBlock implements ASTBlock {
|
||||
IElementType childType = child.getElementType();
|
||||
ASTNode firstGrandchild = child.getFirstChildNode();
|
||||
IElementType firstGrandchildType = firstGrandchild == null ? null : firstGrandchild.getElementType();
|
||||
if (PyTokenTypes.OPEN_BRACES.contains(childType) || PyTokenTypes.OPEN_BRACES.contains(firstGrandchildType)) {
|
||||
if (PyTokenTypes.OPEN_BRACES.contains(childType)) {
|
||||
return false;
|
||||
}
|
||||
if (PyTokenTypes.OPEN_BRACES.contains(firstGrandchildType)) {
|
||||
PsiElement psi = child.getPsi();
|
||||
if (psi instanceof PySequenceExpression && ((PySequenceExpression)psi).getElements().length == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (PyTokenTypes.CLOSE_BRACES.contains(childType)) {
|
||||
ASTNode prevNonSpace = findPrevNonSpaceNode(child);
|
||||
if (prevNonSpace != null && prevNonSpace.getElementType() == PyTokenTypes.COMMA) {
|
||||
if (prevNonSpace != null && prevNonSpace.getElementType() == PyTokenTypes.COMMA && myContext.getMode() == FormattingMode.ADJUST_INDENT) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (_node.getElementType() == PyElementTypes.ARGUMENT_LIST) {
|
||||
if (!mySettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS) {
|
||||
if (!myContext.getSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS) {
|
||||
return false;
|
||||
}
|
||||
if (child.getElementType() == PyTokenTypes.COMMA) {
|
||||
return false;
|
||||
}
|
||||
PyArgumentList argList = (PyArgumentList)_node.getPsi();
|
||||
if (argList != null) {
|
||||
PyExpression[] arguments = argList.getArguments();
|
||||
return arguments.length > 1 || (arguments.length == 1 && PyPsiUtils.getNextComma(arguments[0].getNode()) != null);
|
||||
return arguments.length > 1 || hasLineBreaksBefore(child, 1) || (
|
||||
arguments.length == 1 && PyPsiUtils.getNextComma(arguments[0].getNode()) != null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (_node.getElementType() == PyElementTypes.PARAMETER_LIST) {
|
||||
return mySettings.ALIGN_MULTILINE_PARAMETERS;
|
||||
return myContext.getSettings().ALIGN_MULTILINE_PARAMETERS;
|
||||
}
|
||||
if (child.getElementType() == PyTokenTypes.COMMA) {
|
||||
return false;
|
||||
@@ -315,7 +330,7 @@ public class PyBlock implements ASTBlock {
|
||||
|
||||
@Nullable
|
||||
public Spacing getSpacing(Block child1, Block child2) {
|
||||
return mySpacingBuilder.getSpacing(this, child1, child2);
|
||||
return myContext.getSpacingBuilder().getSpacing(this, child1, child2);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -376,7 +391,7 @@ public class PyBlock implements ASTBlock {
|
||||
// correct indent manually.
|
||||
if (statementListsBelow > 0) { // was 1... strange
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
int indent = mySettings.getIndentOptions().INDENT_SIZE;
|
||||
int indent = myContext.getSettings().getIndentOptions().INDENT_SIZE;
|
||||
return new ChildAttributes(Indent.getSpaceIndent(indent * statementListsBelow), null);
|
||||
}
|
||||
|
||||
@@ -405,7 +420,7 @@ public class PyBlock implements ASTBlock {
|
||||
@Nullable
|
||||
private Alignment getChildAlignment() {
|
||||
if (ourListElementTypes.contains(_node.getElementType())) {
|
||||
if (_node.getPsi() instanceof PyParameterList && !mySettings.ALIGN_MULTILINE_PARAMETERS) {
|
||||
if (_node.getPsi() instanceof PyParameterList && !myContext.getSettings().ALIGN_MULTILINE_PARAMETERS) {
|
||||
return null;
|
||||
}
|
||||
if (_node.getPsi() instanceof PyDictLiteralExpression) {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.jetbrains.python.formatter;
|
||||
|
||||
import com.intellij.formatting.FormattingMode;
|
||||
import com.intellij.formatting.SpacingBuilder;
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class PyBlockContext {
|
||||
private final CommonCodeStyleSettings mySettings;
|
||||
private final SpacingBuilder mySpacingBuilder;
|
||||
private final FormattingMode myMode;
|
||||
|
||||
public PyBlockContext(CommonCodeStyleSettings settings, SpacingBuilder builder, FormattingMode mode) {
|
||||
mySettings = settings;
|
||||
mySpacingBuilder = builder;
|
||||
myMode = mode;
|
||||
}
|
||||
|
||||
public CommonCodeStyleSettings getSettings() {
|
||||
return mySettings;
|
||||
}
|
||||
|
||||
public SpacingBuilder getSpacingBuilder() {
|
||||
return mySpacingBuilder;
|
||||
}
|
||||
|
||||
public FormattingMode getMode() {
|
||||
return myMode;
|
||||
}
|
||||
}
|
||||
@@ -20,26 +20,33 @@ import static com.jetbrains.python.PyTokenTypes.*;
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class PythonFormattingModelBuilder implements FormattingModelBuilder, CustomFormattingModelBuilder {
|
||||
public class PythonFormattingModelBuilder implements FormattingModelBuilderEx, CustomFormattingModelBuilder {
|
||||
private static final boolean DUMP_FORMATTING_AST = false;
|
||||
|
||||
@NotNull
|
||||
public FormattingModel createModel(final PsiElement element, final CodeStyleSettings settings) {
|
||||
@Override
|
||||
public FormattingModel createModel(@NotNull PsiElement element,
|
||||
@NotNull CodeStyleSettings settings,
|
||||
@NotNull FormattingMode mode) {
|
||||
if (DUMP_FORMATTING_AST) {
|
||||
ASTNode fileNode = element.getContainingFile().getNode();
|
||||
System.out.println("AST tree for " + element.getContainingFile().getName() + ":");
|
||||
printAST(fileNode, 0);
|
||||
}
|
||||
final CommonCodeStyleSettings codeStyleSettings = settings.getCommonSettings(PythonLanguage.getInstance());
|
||||
final PyBlock block =
|
||||
new PyBlock(element.getNode(), null, Indent.getNoneIndent(), null, codeStyleSettings,
|
||||
createSpacingBuilder(settings));
|
||||
final PyBlockContext context = new PyBlockContext(codeStyleSettings, createSpacingBuilder(settings), mode);
|
||||
final PyBlock block = new PyBlock(null, element.getNode(), null, Indent.getNoneIndent(), null, context);
|
||||
if (DUMP_FORMATTING_AST) {
|
||||
FormattingModelDumper.dumpFormattingModel(block, 2, System.out);
|
||||
}
|
||||
return FormattingModelProvider.createFormattingModelForPsiFile(element.getContainingFile(), block, settings);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FormattingModel createModel(final PsiElement element, final CodeStyleSettings settings) {
|
||||
return createModel(element, settings, FormattingMode.REFORMAT);
|
||||
}
|
||||
|
||||
protected SpacingBuilder createSpacingBuilder(CodeStyleSettings settings) {
|
||||
final IFileElementType file = LanguageParserDefinitions.INSTANCE.forLanguage(PythonLanguage.getInstance()).getFileNodeType();
|
||||
final PyCodeStyleSettings pySettings = settings.getCustomSettings(PyCodeStyleSettings.class);
|
||||
|
||||
@@ -281,9 +281,11 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
|
||||
public static PyType getTypeFromTarget(@NotNull final PsiElement target,
|
||||
final TypeEvalContext context,
|
||||
PyReferenceExpression anchor) {
|
||||
final PyType pyType = getReferenceTypeFromProviders(target, context, anchor);
|
||||
if (pyType != null) {
|
||||
return pyType;
|
||||
if (!(target instanceof PyTargetExpression)) { // PyTargetExpression will ask about its type itself
|
||||
final PyType pyType = getReferenceTypeFromProviders(target, context, anchor);
|
||||
if (pyType != null) {
|
||||
return pyType;
|
||||
}
|
||||
}
|
||||
if (target instanceof PyTargetExpression) {
|
||||
final String name = ((PyTargetExpression)target).getName();
|
||||
@@ -310,9 +312,9 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
|
||||
augAssignment != null ? augAssignment : anchor,
|
||||
true);
|
||||
if (!defs.isEmpty()) {
|
||||
PyType type = defs.get(0).getType(context);
|
||||
PyType type = defs.get(0).getType(context, anchor);
|
||||
for (int i = 1; i < defs.size(); i++) {
|
||||
type = PyUnionType.union(type, defs.get(i).getType(context));
|
||||
type = PyUnionType.union(type, defs.get(i).getType(context, anchor));
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@@ -329,7 +331,7 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
|
||||
if (propertyDecorator != null) {
|
||||
return PyBuiltinCache.getInstance(target).getObjectType(PyNames.PROPERTY);
|
||||
}
|
||||
for (PyDecorator decorator: decoratorList.getDecorators()) {
|
||||
for (PyDecorator decorator : decoratorList.getDecorators()) {
|
||||
final PyQualifiedName qName = decorator.getQualifiedName();
|
||||
if (qName != null && (qName.endsWith(PyNames.SETTER) || qName.endsWith(PyNames.DELETER))) {
|
||||
return PyBuiltinCache.getInstance(target).getObjectType(PyNames.PROPERTY);
|
||||
@@ -342,7 +344,9 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
|
||||
}
|
||||
if (target instanceof PsiDirectory) {
|
||||
PsiFile file = ((PsiDirectory)target).findFile(PyNames.INIT_DOT_PY);
|
||||
if (file != null) return getTypeFromTarget(file, context, anchor);
|
||||
if (file != null) {
|
||||
return getTypeFromTarget(file, context, anchor);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,11 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
|
||||
}
|
||||
|
||||
public PyType getType(@NotNull TypeEvalContext context) {
|
||||
return getTypeWithAnchor(context, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PyType getTypeWithAnchor(TypeEvalContext context, @Nullable PsiElement anchor) {
|
||||
if (!TypeEvalStack.mayEvaluate(this)) {
|
||||
return null;
|
||||
}
|
||||
@@ -107,6 +112,10 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
|
||||
// imported via __all__
|
||||
return null;
|
||||
}
|
||||
final PyType pyType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(this, context, anchor);
|
||||
if (pyType != null) {
|
||||
return pyType;
|
||||
}
|
||||
if (!context.maySwitchToAST(this)) {
|
||||
final PsiElement value = getStub() != null ? findAssignedValueByStub() : findAssignedValue();
|
||||
if (value instanceof PyTypedElement) {
|
||||
|
||||
@@ -13,8 +13,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
public class PyRunConfigurationFactoryImpl extends PyRunConfigurationFactory {
|
||||
@Override
|
||||
public PythonRunConfigurationParams createPythonScriptRunConfiguration(Module module, String scriptName) {
|
||||
public PythonRunConfigurationParams createPythonScriptRunConfiguration(Module module, String scriptName, boolean singleton) {
|
||||
RunnerAndConfigurationSettings settings = createRunConfiguration(module, PythonConfigurationType.getInstance().getFactory());
|
||||
settings.setSingleton(singleton);
|
||||
PythonRunConfigurationParams configuration = (PythonRunConfigurationParams)settings.getConfiguration();
|
||||
configuration.setScriptName(scriptName);
|
||||
return configuration;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
term1 = BNF.lpar + expr + BNF.rpar\
|
||||
| if_expr\
|
||||
| numeric_value
|
||||
@@ -0,0 +1,3 @@
|
||||
term1 = BNF.lpar + expr + BNF.rpar\
|
||||
| if_expr\
|
||||
| numeric_value
|
||||
@@ -0,0 +1,7 @@
|
||||
d = {
|
||||
'success': 'OK',
|
||||
'tag_count': 2,
|
||||
'tags': [
|
||||
{'name': 'tag1', 'uses': '1', 'display': '1', 'security': 'private'},
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
d = {
|
||||
'success': 'OK',
|
||||
'tag_count': 2,
|
||||
'tags': [
|
||||
{'name': 'tag1', 'uses': '1', 'display': '1', 'security': 'private'},
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
self.assertEqual(
|
||||
{"000000000000", "111111111111"},
|
||||
foo['bar']['baz'])
|
||||
@@ -0,0 +1,3 @@
|
||||
self.assertEqual(
|
||||
{"000000000000", "111111111111"},
|
||||
foo['bar']['baz'])
|
||||
@@ -0,0 +1,4 @@
|
||||
urlpatterns = patterns('',
|
||||
(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^', include('cms.urls')),
|
||||
)
|
||||
@@ -0,0 +1,4 @@
|
||||
urlpatterns = patterns('',
|
||||
(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^', include('cms.urls')),
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
from datetime import timedelta
|
||||
|
||||
def foo(**kwargs):
|
||||
pass
|
||||
|
||||
def bar():
|
||||
foo(timedelta=timedelta)
|
||||
# <ref>
|
||||
@@ -111,6 +111,12 @@ public class PyEditingTest extends PyTestCase {
|
||||
" r'string'");
|
||||
}
|
||||
|
||||
public void testEnterInStringFormatting() { // PY-7039
|
||||
doTestEnter("foo += \"fooba<caret>r\" % foo\n",
|
||||
"foo += \"fooba\" \\\n" +
|
||||
" \"r\" % foo\n");
|
||||
}
|
||||
|
||||
public void testEnterInStatement() {
|
||||
doTestEnter("if a <caret>and b: pass", "if a \\\nand b: pass");
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
@@ -118,12 +119,12 @@ public class PyFormatterTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testSpaceInMethodDeclaration() { // PY-4241
|
||||
CodeStyleSettingsManager.getInstance().getSettings(myFixture.getProject()).SPACE_BEFORE_METHOD_PARENTHESES = true;
|
||||
settings().SPACE_BEFORE_METHOD_PARENTHESES = true;
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testOptionalAlignForMethodParameters() { // PY-3995
|
||||
CodeStyleSettingsManager.getInstance().getSettings(myFixture.getProject()).ALIGN_MULTILINE_PARAMETERS = false;
|
||||
settings().ALIGN_MULTILINE_PARAMETERS = false;
|
||||
doTest();
|
||||
}
|
||||
|
||||
@@ -132,7 +133,7 @@ public class PyFormatterTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testAlignForMethodArguments() { // PY-3995
|
||||
CodeStyleSettingsManager.getInstance().getSettings(myFixture.getProject()).ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
|
||||
settings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
|
||||
doTest();
|
||||
}
|
||||
|
||||
@@ -152,6 +153,24 @@ public class PyFormatterTest extends PyTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSetLiteralInArgList() { // PY-6672
|
||||
settings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testLiterals() { // PY-6751
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTupleInArgList() {
|
||||
settings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAlignInBinaryExpressions() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testPsiFormatting() { // IDEA-69724
|
||||
String initial =
|
||||
"def method_name(\n" +
|
||||
@@ -190,4 +209,8 @@ public class PyFormatterTest extends PyTestCase {
|
||||
});
|
||||
myFixture.checkResultByFile("formatter/" + getTestName(true) + "_after.py");
|
||||
}
|
||||
|
||||
private CodeStyleSettings settings() {
|
||||
return CodeStyleSettingsManager.getInstance().getSettings(myFixture.getProject());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,4 +472,8 @@ public class PyResolveTest extends PyResolveTestCase {
|
||||
public void testClassRedefinedField() {
|
||||
assertResolvesTo(PyClass.class, "Foo");
|
||||
}
|
||||
|
||||
public void testKWArg() {
|
||||
assertResolvesTo(PyClass.class, "timedelta");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user