diff --git a/platform/lang-api/src/com/intellij/formatting/FormattingDocumentModel.java b/platform/lang-api/src/com/intellij/formatting/FormattingDocumentModel.java index 77397261c4ca..175c0fd14a2c 100644 --- a/platform/lang-api/src/com/intellij/formatting/FormattingDocumentModel.java +++ b/platform/lang-api/src/com/intellij/formatting/FormattingDocumentModel.java @@ -15,9 +15,11 @@ */ package com.intellij.formatting; +import com.intellij.lang.ASTNode; import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.TextRange; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * Represents a model of the document containing the formatted text, as seen by the @@ -73,15 +75,18 @@ public interface FormattingDocumentModel { *
* Current method adjusts given white space text if necessary. * + * + * * @param whiteSpaceText white space text to use by default * @param startOffset start offset of the document text that is intended to be replaced by the given white space text (inclusive) * @param endOffset end offset of the document text that is intended to be replaced by the given white space text (exclusive) + * @param nodeAfter the AST node following the block, if known * @param changedViaPsi flag that identifies whether formatter introduces changes via PSI tree or directly via the document * @return white space to use for replacing document symbols at[startOffset; endOffset) region
*/
@NotNull
CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, int startOffset, int endOffset,
- boolean changedViaPsi);
+ @Nullable ASTNode nodeAfter, boolean changedViaPsi);
///**
// * Allows to answer if given symbol is treated by the current model as white space symbol during formatting.
diff --git a/platform/lang-api/src/com/intellij/formatting/FormattingModelEx.java b/platform/lang-api/src/com/intellij/formatting/FormattingModelEx.java
new file mode 100644
index 000000000000..bfe3e1fb2184
--- /dev/null
+++ b/platform/lang-api/src/com/intellij/formatting/FormattingModelEx.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2013 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.intellij.formatting;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author yole
+ */
+public interface FormattingModelEx extends FormattingModel {
+ /**
+ * Replaces the contents of the specified text range in the document with the specified text
+ * string consisting of whitespace characters. If necessary, other characters may be inserted
+ * in addition to the passed whitespace (for example, \ characters for breaking lines in
+ * languages like Python).
+ *
+ * @param textRange the text range to replace with whitespace.
+ * @param nodeAfter the AST node following the whitespace, if known
+ * @param whiteSpace the whitespace to replace with.
+ * @return new white space text range
+ */
+ TextRange replaceWhiteSpace(TextRange textRange, @Nullable ASTNode nodeAfter, String whiteSpace);
+}
diff --git a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java
index 7896c1b893d6..ec55f74b3d42 100644
--- a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java
+++ b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java
@@ -16,6 +16,7 @@
package com.intellij.formatting;
+import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
@@ -38,7 +39,7 @@ public abstract class AbstractBlockWrapper {
Indent.Type.NORMAL, Indent.Type.CONTINUATION, Indent.Type.CONTINUATION_WITHOUT_FIRST
));
- protected WhiteSpace myWhiteSpace;
+ protected WhiteSpace myWhiteSpaceBefore;
protected CompositeBlockWrapper myParent;
protected int myStart;
protected int myEnd;
@@ -53,12 +54,13 @@ public abstract class AbstractBlockWrapper {
private IndentImpl myIndent = null;
private AlignmentImpl myAlignment;
private WrapImpl myWrap;
+ private final ASTNode myNode;
public AbstractBlockWrapper(final Block block,
- final WhiteSpace whiteSpace,
+ final WhiteSpace whiteSpaceBefore,
final CompositeBlockWrapper parent,
final TextRange textRange) {
- myWhiteSpace = whiteSpace;
+ myWhiteSpaceBefore = whiteSpaceBefore;
myParent = parent;
myStart = textRange.getStartOffset();
myEnd = textRange.getEndOffset();
@@ -67,6 +69,7 @@ public abstract class AbstractBlockWrapper {
myAlignment = (AlignmentImpl)block.getAlignment();
myWrap = (WrapImpl)block.getWrap();
myLanguage = deriveLanguage(block);
+ myNode = block instanceof ASTBlock ? ((ASTBlock) block).getNode() : null;
}
@Nullable
@@ -76,9 +79,24 @@ public abstract class AbstractBlockWrapper {
}
return null;
}
-
+
+ /**
+ * Returns the whitespace preceding the block.
+ *
+ * @return the whitespace preceding the block
+ */
public WhiteSpace getWhiteSpace() {
- return myWhiteSpace;
+ return myWhiteSpaceBefore;
+ }
+
+ /**
+ * Returns the AST node corresponding to the block, if known.
+ *
+ * @return the AST node or null
+ */
+ @Nullable
+ public ASTNode getNode() {
+ return myNode;
}
/**
@@ -529,7 +547,7 @@ public abstract class AbstractBlockWrapper {
myIndent = null;
myIndentFromParent = null;
myParent = null;
- myWhiteSpace = null;
+ myWhiteSpaceBefore = null;
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java
index 7f56fa495ff3..fe9f021c4777 100644
--- a/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java
+++ b/platform/lang-impl/src/com/intellij/formatting/CompositeBlockWrapper.java
@@ -30,15 +30,15 @@ public class CompositeBlockWrapper extends AbstractBlockWrapper{
* {@link Block#getTextRange() text range associated with the given block}.
*
* @param block block to wrap
- * @param whiteSpace white space before the block
+ * @param whiteSpaceBefore white space before the block
* @param parent wrapped block parent
*/
- public CompositeBlockWrapper(final Block block, final WhiteSpace whiteSpace, @Nullable final CompositeBlockWrapper parent) {
- super(block, whiteSpace, parent, block.getTextRange());
+ public CompositeBlockWrapper(final Block block, final WhiteSpace whiteSpaceBefore, @Nullable final CompositeBlockWrapper parent) {
+ super(block, whiteSpaceBefore, parent, block.getTextRange());
}
- public CompositeBlockWrapper(final Block block, final WhiteSpace whiteSpace, final CompositeBlockWrapper parent, TextRange textRange) {
- super(block, whiteSpace, parent, textRange);
+ public CompositeBlockWrapper(final Block block, final WhiteSpace whiteSpaceBefore, final CompositeBlockWrapper parent, TextRange textRange) {
+ super(block, whiteSpaceBefore, parent, textRange);
}
public List[startOffset; endOffset) sub-sequence of the given text
*/
@NotNull
CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, @NotNull CharSequence text, int startOffset,
- int endOffset, CodeStyleSettings codeStyleSettings);
+ int endOffset, CodeStyleSettings codeStyleSettings, ASTNode nodeAfter);
/**
- * PSI-based version of {@link #adjustWhiteSpaceIfNecessary(CharSequence, CharSequence, int, int, com.intellij.psi.codeStyle.CodeStyleSettings)}.
+ * PSI-based version of {@link #adjustWhiteSpaceIfNecessary(CharSequence, CharSequence, int, int, com.intellij.psi.codeStyle.CodeStyleSettings, com.intellij.lang.ASTNode)}.
*
* There is a possible case that particular changes are performed to PSI tree and it's not yet synchronized with the underlying
* document. Hence, we can't directly work with document char sequence but need to traverse PSI tree instead. I.e. we start with
diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/WhiteSpaceFormattingStrategyAdapter.java b/platform/lang-impl/src/com/intellij/psi/formatter/WhiteSpaceFormattingStrategyAdapter.java
index cd5e6e3e7982..d494238bc426 100644
--- a/platform/lang-impl/src/com/intellij/psi/formatter/WhiteSpaceFormattingStrategyAdapter.java
+++ b/platform/lang-impl/src/com/intellij/psi/formatter/WhiteSpaceFormattingStrategyAdapter.java
@@ -49,7 +49,7 @@ public class WhiteSpaceFormattingStrategyAdapter implements WhiteSpaceFormatting
public CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText,
@NotNull CharSequence text,
int startOffset,
- int endOffset, CodeStyleSettings codeStyleSettings) {
+ int endOffset, CodeStyleSettings codeStyleSettings, ASTNode nodeAfter) {
return whiteSpaceText;
}
diff --git a/platform/platform-tests/testSrc/com/intellij/formatting/TestFormattingModel.java b/platform/platform-tests/testSrc/com/intellij/formatting/TestFormattingModel.java
index afd57495c544..319a4920c723 100644
--- a/platform/platform-tests/testSrc/com/intellij/formatting/TestFormattingModel.java
+++ b/platform/platform-tests/testSrc/com/intellij/formatting/TestFormattingModel.java
@@ -1,5 +1,6 @@
package com.intellij.formatting;
+import com.intellij.lang.ASTNode;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.impl.DocumentImpl;
@@ -106,7 +107,7 @@ public class TestFormattingModel implements FormattingModel, FormattingDocumentM
@NotNull
@Override
public CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, int startOffset, int endOffset,
- boolean changedViaPsi) {
+ ASTNode nodeAfter, boolean changedViaPsi) {
return whiteSpaceText;
}
diff --git a/python/src/com/jetbrains/python/editor/PythonEnterHandler.java b/python/src/com/jetbrains/python/editor/PythonEnterHandler.java
index 04db2d175343..16bf3c717546 100644
--- a/python/src/com/jetbrains/python/editor/PythonEnterHandler.java
+++ b/python/src/com/jetbrains/python/editor/PythonEnterHandler.java
@@ -69,6 +69,7 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
PyFunction.class,
PySliceExpression.class,
PySubscriptionExpression.class,
+ PyGeneratorExpression.class
};
@Override
diff --git a/python/src/com/jetbrains/python/formatter/PyWhiteSpaceFormattingStrategy.java b/python/src/com/jetbrains/python/formatter/PyWhiteSpaceFormattingStrategy.java
index c78e4909343d..06ea87235d46 100644
--- a/python/src/com/jetbrains/python/formatter/PyWhiteSpaceFormattingStrategy.java
+++ b/python/src/com/jetbrains/python/formatter/PyWhiteSpaceFormattingStrategy.java
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.formatter;
+import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleSettings;
@@ -61,6 +62,7 @@ public class PyWhiteSpaceFormattingStrategy extends StaticSymbolWhiteSpaceDefini
* @param startOffset start offset to use with the given text (inclusive)
* @param endOffset end offset to use with the given text (exclusive)
* @param codeStyleSettings the code style settings
+ * @param nodeAfter
* @return symbols to use for replacing [startOffset; endOffset) sub-sequence of the given text
*/
@NotNull
@@ -69,11 +71,16 @@ public class PyWhiteSpaceFormattingStrategy extends StaticSymbolWhiteSpaceDefini
@NotNull CharSequence text,
int startOffset,
int endOffset,
- CodeStyleSettings codeStyleSettings)
+ CodeStyleSettings codeStyleSettings, ASTNode nodeAfter)
{
// The general idea is that '\' symbol before line feed should be preserved.
TIntIntHashMap initialBackSlashes = countBackSlashes(text, startOffset, endOffset);
if (initialBackSlashes.isEmpty()) {
+ if (nodeAfter != null && whiteSpaceText.length() > 0 && whiteSpaceText.charAt(0) == '\n' &&
+ PythonEnterHandler.needInsertBackslash(nodeAfter, false)) {
+ PyCodeStyleSettings settings = codeStyleSettings.getCustomSettings(PyCodeStyleSettings.class);
+ return (settings.SPACE_BEFORE_BACKSLASH ? " \\" : "\\") + whiteSpaceText;
+ }
return whiteSpaceText;
}
diff --git a/python/testData/formatter/wrapBeforeElse_after.py b/python/testData/formatter/wrapBeforeElse_after.py
index 216c191f4b50..b8185063fcba 100644
--- a/python/testData/formatter/wrapBeforeElse_after.py
+++ b/python/testData/formatter/wrapBeforeElse_after.py
@@ -1,2 +1,2 @@
-id = 1 if looooooooooooooooooooooooong_vaaaaaaaaaaaaaaaar == 'loooooooooooooooong_vaaaaaaaaaaaaaaaaaaaaaaaaaalue' else list(
- 'foo')[0]
\ No newline at end of file
+id = 1 if looooooooooooooooooooooooong_vaaaaaaaaaaaaaaaar == 'loooooooooooooooong_vaaaaaaaaaaaaaaaaaaaaaaaaaalue' else \
+list('foo')[0]
\ No newline at end of file
diff --git a/python/testSrc/com/jetbrains/python/PyFormatterTest.java b/python/testSrc/com/jetbrains/python/PyFormatterTest.java
index bf6c1fe1ac72..4efdb787e757 100644
--- a/python/testSrc/com/jetbrains/python/PyFormatterTest.java
+++ b/python/testSrc/com/jetbrains/python/PyFormatterTest.java
@@ -337,7 +337,7 @@ public class PyFormatterTest extends PyTestCase {
doTest();
}
- public void _testWrapBeforeElse() { // PY-10319
+ public void testWrapBeforeElse() { // PY-10319
doTest(true);
}