diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java b/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java index f5275065d1b2..f4ff47e47bff 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java @@ -23,12 +23,14 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.python.PythonStringUtil; import com.jetbrains.python.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -54,6 +56,9 @@ public class PyStatementMover extends LineMover { PsiElement elementToMove1 = PyUtil.findNonWhitespaceAtOffset(file, start); PsiElement elementToMove2 = PyUtil.findNonWhitespaceAtOffset(file, end); if (elementToMove1 == null || elementToMove2 == null) return false; + + if (ifInsideString(document, lineNumber, elementToMove1, down)) return false; + elementToMove1 = getCommentOrStatement(document, elementToMove1); elementToMove2 = getCommentOrStatement(document, elementToMove2); @@ -72,6 +77,24 @@ public class PyStatementMover extends LineMover { return true; } + private static boolean ifInsideString(@NotNull final Document document, int lineNumber, @NotNull final PsiElement elementToMove1, boolean down) { + int start = document.getLineStartOffset(lineNumber); + final int end = document.getLineEndOffset(lineNumber); + int nearLine = down ? lineNumber + 1 : lineNumber - 1; + if (nearLine >= document.getLineCount() || nearLine <= 0) return false; + final PyStringLiteralExpression stringLiteralExpression = PsiTreeUtil.getParentOfType(elementToMove1, PyStringLiteralExpression.class); + if (stringLiteralExpression != null) { + final Pair quotes = PythonStringUtil.getQuotes(stringLiteralExpression.getText()); + if (quotes != null && (quotes.first.equals("'''") || quotes.first.equals("\"\"\""))) { + final String text1 = document.getText(TextRange.create(start, end)).trim(); + final String text2 = document.getText(TextRange.create(document.getLineStartOffset(nearLine), document.getLineEndOffset(nearLine))).trim(); + if (!text1.startsWith(quotes.first) && !text1.endsWith(quotes.second) && !text2.startsWith(quotes.first) && !text2.endsWith(quotes.second)) + return true; + } + } + return false; + } + @Nullable private static LineRange getDestinationScope(@NotNull final PsiFile file, @NotNull final Editor editor, @NotNull final PsiElement elementToMove, boolean down) { diff --git a/python/testData/mover/insideDocComment.py b/python/testData/mover/insideDocComment.py new file mode 100644 index 000000000000..1f2b305b93b1 --- /dev/null +++ b/python/testData/mover/insideDocComment.py @@ -0,0 +1,7 @@ +def fcn(self, foo, bar): + """ + :type foo: int + :type bar: str + """ + self.foo = foo + self.bar = bar \ No newline at end of file diff --git a/python/testData/mover/insideDocComment_afterDown.py b/python/testData/mover/insideDocComment_afterDown.py new file mode 100644 index 000000000000..83dbf6192f0d --- /dev/null +++ b/python/testData/mover/insideDocComment_afterDown.py @@ -0,0 +1,7 @@ +def fcn(self, foo, bar): + """ + :type bar: str + :type foo: int + """ + self.foo = foo + self.bar = bar \ No newline at end of file diff --git a/python/testData/mover/insideDocComment_afterUp.py b/python/testData/mover/insideDocComment_afterUp.py new file mode 100644 index 000000000000..fe14fa7b461e --- /dev/null +++ b/python/testData/mover/insideDocComment_afterUp.py @@ -0,0 +1,7 @@ +""" + :type foo: int + :type bar: str + """ +def fcn(self, foo, bar): + self.foo = foo + self.bar = bar \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyStatementMoverTest.java b/python/testSrc/com/jetbrains/python/PyStatementMoverTest.java index 583864a26600..3539150731b6 100644 --- a/python/testSrc/com/jetbrains/python/PyStatementMoverTest.java +++ b/python/testSrc/com/jetbrains/python/PyStatementMoverTest.java @@ -256,6 +256,10 @@ public class PyStatementMoverTest extends PyTestCase { doTest(); } + public void testInsideDocComment() { //PY-11595 + doTest(); + } + public void testWith() { // PY-5202 try { setLanguageLevel(LanguageLevel.PYTHON27);