From fdfb56f0f6cedfe7c3630e279fa923e9f44dd6f2 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Tue, 12 Nov 2013 13:39:04 +0100 Subject: [PATCH] pass ASTNode at caret to WhiteSpaceFormattingStrategy.adjustWhiteSpaceIfNecessary(); use that to correctly insert \ when a line break is inserted via the document formatting model (PY-10319) --- .../formatting/FormattingDocumentModel.java | 7 +++- .../formatting/FormattingModelEx.java | 38 +++++++++++++++++++ .../formatting/AbstractBlockWrapper.java | 30 ++++++++++++--- .../formatting/CompositeBlockWrapper.java | 10 ++--- .../formatting/DelegatingFormattingModel.java | 11 +++++- .../intellij/formatting/FormatProcessor.java | 6 ++- .../intellij/formatting/FormatterImpl.java | 14 +++++-- .../AbstractWhiteSpaceFormattingStrategy.java | 4 +- ...CompositeWhiteSpaceFormattingStrategy.java | 4 +- .../DocumentBasedFormattingModel.java | 13 +++++-- .../FormattingDocumentModelImpl.java | 5 ++- .../formatter/PsiBasedFormattingModel.java | 19 +++++++--- .../WhiteSpaceFormattingStrategy.java | 6 ++- .../WhiteSpaceFormattingStrategyAdapter.java | 2 +- .../formatting/TestFormattingModel.java | 3 +- .../python/editor/PythonEnterHandler.java | 1 + .../PyWhiteSpaceFormattingStrategy.java | 9 ++++- .../formatter/wrapBeforeElse_after.py | 4 +- .../com/jetbrains/python/PyFormatterTest.java | 2 +- 19 files changed, 147 insertions(+), 41 deletions(-) create mode 100644 platform/lang-api/src/com/intellij/formatting/FormattingModelEx.java 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 getChildren() { diff --git a/platform/lang-impl/src/com/intellij/formatting/DelegatingFormattingModel.java b/platform/lang-impl/src/com/intellij/formatting/DelegatingFormattingModel.java index 245153a3afd1..edce2ee8d443 100644 --- a/platform/lang-impl/src/com/intellij/formatting/DelegatingFormattingModel.java +++ b/platform/lang-impl/src/com/intellij/formatting/DelegatingFormattingModel.java @@ -15,13 +15,14 @@ */ package com.intellij.formatting; +import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import org.jetbrains.annotations.NotNull; /** * @author yole */ -public class DelegatingFormattingModel implements FormattingModel { +public class DelegatingFormattingModel implements FormattingModelEx { private final FormattingModel myBaseModel; private final Block myRootBlock; @@ -47,6 +48,14 @@ public class DelegatingFormattingModel implements FormattingModel { return myBaseModel.replaceWhiteSpace(textRange, whiteSpace); } + @Override + public TextRange replaceWhiteSpace(TextRange textRange, ASTNode nodeAfter, String whiteSpace) { + if (myBaseModel instanceof FormattingModelEx) { + return ((FormattingModelEx) myBaseModel).replaceWhiteSpace(textRange, nodeAfter, whiteSpace); + } + return myBaseModel.replaceWhiteSpace(textRange, whiteSpace); + } + @Override public TextRange shiftIndentInsideRange(TextRange range, int indent) { return myBaseModel.shiftIndentInsideRange(range, indent); diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java index 5786bc880e38..6faa7a24d74c 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java @@ -338,7 +338,7 @@ class FormatProcessor { WhiteSpace whiteSpace = block.getWhiteSpace(); CharSequence newWs = documentModel.adjustWhiteSpaceIfNecessary( whiteSpace.generateWhiteSpace(getIndentOptionsToUse(block, indentOption)), whiteSpace.getStartOffset(), - whiteSpace.getEndOffset(), false + whiteSpace.getEndOffset(), block.getNode(), false ); if (changes.size() > 10000) { CharSequence mergeResult = BulkChangesMerger.INSTANCE.mergeToCharSequence(document.getChars(), document.getTextLength(), changes); @@ -386,7 +386,9 @@ class FormatProcessor { final TextRange textRange = whiteSpace.getTextRange(); final TextRange wsRange = shiftRange(textRange, shift); final String newWhiteSpace = _newWhiteSpace.toString(); - TextRange newWhiteSpaceRange = model.replaceWhiteSpace(wsRange, newWhiteSpace); + TextRange newWhiteSpaceRange = model instanceof FormattingModelEx + ? ((FormattingModelEx) model).replaceWhiteSpace(wsRange, block.getNode(), newWhiteSpace) + : model.replaceWhiteSpace(textRange, newWhiteSpace); shift += newWhiteSpaceRange.getLength() - textRange.getLength(); diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java b/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java index 5a413501414e..bca7dcd77142 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java @@ -16,6 +16,7 @@ package com.intellij.formatting; +import com.intellij.lang.ASTNode; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ApplicationComponent; @@ -378,7 +379,8 @@ public class FormatterImpl extends FormatterEx } WhiteSpace whiteSpace = blockAfterOffset != null ? blockAfterOffset.getWhiteSpace() : processor.getLastWhiteSpace(); - return adjustLineIndent(offset, documentModel, processor, indentOptions, model, whiteSpace); + return adjustLineIndent(offset, documentModel, processor, indentOptions, model, whiteSpace, + blockAfterOffset != null ? blockAfterOffset.getNode() : null); } finally { enableFormatting(); @@ -439,7 +441,8 @@ public class FormatterImpl extends FormatterEx final FormatProcessor processor, final CommonCodeStyleSettings.IndentOptions indentOptions, final FormattingModel model, - final WhiteSpace whiteSpace) + final WhiteSpace whiteSpace, + ASTNode nodeAfter) { boolean wsContainsCaret = whiteSpace.getStartOffset() <= offset && offset < whiteSpace.getEndOffset(); @@ -450,7 +453,12 @@ public class FormatterImpl extends FormatterEx final String newWS = whiteSpace.generateWhiteSpace(indentOptions, lineStartOffset, indent).toString(); if (!whiteSpace.equalsToString(newWS)) { try { - model.replaceWhiteSpace(whiteSpace.getTextRange(), newWS); + if (model instanceof FormattingModelEx) { + ((FormattingModelEx) model).replaceWhiteSpace(whiteSpace.getTextRange(), nodeAfter, newWS); + } + else { + model.replaceWhiteSpace(whiteSpace.getTextRange(), newWS); + } } finally { model.commitChanges(); diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/AbstractWhiteSpaceFormattingStrategy.java b/platform/lang-impl/src/com/intellij/psi/formatter/AbstractWhiteSpaceFormattingStrategy.java index d9035347f768..e19efe0b7158 100644 --- a/platform/lang-impl/src/com/intellij/psi/formatter/AbstractWhiteSpaceFormattingStrategy.java +++ b/platform/lang-impl/src/com/intellij/psi/formatter/AbstractWhiteSpaceFormattingStrategy.java @@ -43,7 +43,7 @@ public abstract class AbstractWhiteSpaceFormattingStrategy implements WhiteSpace public CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, @NotNull CharSequence text, int startOffset, - int endOffset, CodeStyleSettings codeStyleSettings) + int endOffset, CodeStyleSettings codeStyleSettings, ASTNode nodeAfter) { // Does nothing return whiteSpaceText; @@ -85,7 +85,7 @@ public abstract class AbstractWhiteSpaceFormattingStrategy implements WhiteSpace } } - return adjustWhiteSpaceIfNecessary(whiteSpaceText, buffer, 0, endOffset - startOffset, codeStyleSettings); + return adjustWhiteSpaceIfNecessary(whiteSpaceText, buffer, 0, endOffset - startOffset, codeStyleSettings, null); } @Nullable diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/CompositeWhiteSpaceFormattingStrategy.java b/platform/lang-impl/src/com/intellij/psi/formatter/CompositeWhiteSpaceFormattingStrategy.java index ad19870515df..776684f5184c 100644 --- a/platform/lang-impl/src/com/intellij/psi/formatter/CompositeWhiteSpaceFormattingStrategy.java +++ b/platform/lang-impl/src/com/intellij/psi/formatter/CompositeWhiteSpaceFormattingStrategy.java @@ -85,11 +85,11 @@ public class CompositeWhiteSpaceFormattingStrategy implements WhiteSpaceFormatti public CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, @NotNull CharSequence text, int startOffset, - int endOffset, CodeStyleSettings codeStyleSettings) + int endOffset, CodeStyleSettings codeStyleSettings, ASTNode nodeAfter) { CharSequence result = whiteSpaceText; for (WhiteSpaceFormattingStrategy strategy : myStrategies) { - result = strategy.adjustWhiteSpaceIfNecessary(result, text, startOffset, endOffset, codeStyleSettings); + result = strategy.adjustWhiteSpaceIfNecessary(result, text, startOffset, endOffset, codeStyleSettings, nodeAfter); } return result; } diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java b/platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java index 403324cf3171..169d2c70442b 100644 --- a/platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java +++ b/platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java @@ -18,7 +18,8 @@ package com.intellij.psi.formatter; import com.intellij.formatting.Block; import com.intellij.formatting.FormattingDocumentModel; -import com.intellij.formatting.FormattingModel; +import com.intellij.formatting.FormattingModelEx; +import com.intellij.lang.ASTNode; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; @@ -36,7 +37,7 @@ import org.jetbrains.annotations.Nullable; /** * @author lesya */ -public class DocumentBasedFormattingModel implements FormattingModel { +public class DocumentBasedFormattingModel implements FormattingModelEx { private final Block myRootBlock; private final FormattingDocumentModel myDocumentModel; @NotNull private final Document myDocument; @@ -86,8 +87,14 @@ public class DocumentBasedFormattingModel implements FormattingModel { return myDocumentModel; } + @Override public TextRange replaceWhiteSpace(TextRange textRange, String whiteSpace) { + return replaceWhiteSpace(textRange, null, whiteSpace); + } + + @Override + public TextRange replaceWhiteSpace(TextRange textRange, ASTNode nodeAfter, String whiteSpace) { boolean removesStartMarker; String marker; @@ -121,7 +128,7 @@ public class DocumentBasedFormattingModel implements FormattingModel { } CharSequence whiteSpaceToUse = getDocumentModel().adjustWhiteSpaceIfNecessary( - whiteSpace, textRange.getStartOffset(), textRange.getEndOffset(), false + whiteSpace, textRange.getStartOffset(), textRange.getEndOffset(), nodeAfter, false ); myDocument.replaceString(textRange.getStartOffset(), diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/FormattingDocumentModelImpl.java b/platform/lang-impl/src/com/intellij/psi/formatter/FormattingDocumentModelImpl.java index 77507a6c6abd..0cf0d3a8b266 100644 --- a/platform/lang-impl/src/com/intellij/psi/formatter/FormattingDocumentModelImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/formatter/FormattingDocumentModelImpl.java @@ -17,6 +17,7 @@ package com.intellij.psi.formatter; import com.intellij.formatting.FormattingDocumentModel; +import com.intellij.lang.ASTNode; import com.intellij.lang.Language; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -149,11 +150,11 @@ public class FormattingDocumentModelImpl implements FormattingDocumentModel { @NotNull @Override public CharSequence adjustWhiteSpaceIfNecessary(@NotNull CharSequence whiteSpaceText, int startOffset, int endOffset, - boolean changedViaPsi) + ASTNode nodeAfter, boolean changedViaPsi) { if (!changedViaPsi) { return myWhiteSpaceStrategy.adjustWhiteSpaceIfNecessary(whiteSpaceText, myDocument.getCharsSequence(), startOffset, endOffset, - mySettings); + mySettings, nodeAfter); } final PsiElement element = myFile.findElementAt(startOffset); diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/PsiBasedFormattingModel.java b/platform/lang-impl/src/com/intellij/psi/formatter/PsiBasedFormattingModel.java index 5fb63836e61d..3712158a6b4c 100644 --- a/platform/lang-impl/src/com/intellij/psi/formatter/PsiBasedFormattingModel.java +++ b/platform/lang-impl/src/com/intellij/psi/formatter/PsiBasedFormattingModel.java @@ -18,21 +18,21 @@ package com.intellij.psi.formatter; import com.intellij.formatting.Block; import com.intellij.formatting.FormattingDocumentModel; -import com.intellij.formatting.FormattingModel; +import com.intellij.formatting.FormattingModelEx; import com.intellij.lang.ASTNode; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.TokenType; -import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class PsiBasedFormattingModel implements FormattingModel { +public class PsiBasedFormattingModel implements FormattingModelEx { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.formatter.PsiBasedFormattingModel"); @@ -50,12 +50,19 @@ public class PsiBasedFormattingModel implements FormattingModel { } + + @Override public TextRange replaceWhiteSpace(TextRange textRange, String whiteSpace) { + return replaceWhiteSpace(textRange, null, whiteSpace); + } + + @Override + public TextRange replaceWhiteSpace(TextRange textRange, ASTNode nodeAfter, String whiteSpace) { String whiteSpaceToUse - = myDocumentModel.adjustWhiteSpaceIfNecessary(whiteSpace, textRange.getStartOffset(), textRange.getEndOffset(), true).toString(); + = myDocumentModel.adjustWhiteSpaceIfNecessary(whiteSpace, textRange.getStartOffset(), textRange.getEndOffset(), nodeAfter, true).toString(); final String wsReplaced = replaceWithPSI(textRange, whiteSpaceToUse); - + if (wsReplaced != null){ return new TextRange(textRange.getStartOffset(), textRange.getStartOffset() + wsReplaced.length()); } else { diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/WhiteSpaceFormattingStrategy.java b/platform/lang-impl/src/com/intellij/psi/formatter/WhiteSpaceFormattingStrategy.java index 169f162daa85..6f857a90cb88 100644 --- a/platform/lang-impl/src/com/intellij/psi/formatter/WhiteSpaceFormattingStrategy.java +++ b/platform/lang-impl/src/com/intellij/psi/formatter/WhiteSpaceFormattingStrategy.java @@ -71,20 +71,22 @@ public interface WhiteSpaceFormattingStrategy { * document symbols sub-sequence if necessary. * * + * * @param whiteSpaceText white space text to use by default for replacing sub-sequence of the given text * @param text target text which region is to be replaced by the given white space symbols * @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 the AST node following the whitespace, if known * @return symbols to use for replacing [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); }