From 496fe62d7a9d2f6f1e9e6117942e3b71ab56ff28 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Thu, 2 Mar 2017 16:12:43 +0300 Subject: [PATCH] PY-22422 Properly unblock/commit document in PyTrailingBlankLinesPostFormatProcessor Also, avoid unnecessary premature postprocessing in the PSI file, acquire document only when it's really needed. Simplify calculation of the result range when reformat is called on a text fragment. --- ...TrailingBlankLinesPostFormatProcessor.java | 65 +++++-------------- 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java b/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java index baa6323bc344..8dda98118bec 100644 --- a/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java +++ b/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java @@ -55,7 +55,6 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces public PsiElement processElement(@NotNull PsiElement source, @NotNull CodeStyleSettings settings) { final PsiFile psiFile = source.getContainingFile(); if (isApplicableTo(psiFile)) { - applyPendingChangesToPsi(source); final TextRange whitespaceRange = findTrailingWhitespacesRange(psiFile); if (source.getTextRange().intersects(whitespaceRange)) { replaceOrDeleteTrailingWhitespaces(psiFile, whitespaceRange); @@ -70,38 +69,14 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces if (!isApplicableTo(source)) { return rangeToReformat; } - applyPendingChangesToPsi(source); final TextRange oldWhitespaceRange = findTrailingWhitespacesRange(source); if (rangeToReformat.intersects(oldWhitespaceRange)) { final TextRange newWhitespaceRange = replaceOrDeleteTrailingWhitespaces(source, oldWhitespaceRange); - final int delta = newWhitespaceRange.getLength() - oldWhitespaceRange.getLength(); - if (oldWhitespaceRange.contains(rangeToReformat)) { - return newWhitespaceRange; - } - else if (rangeToReformat.contains(oldWhitespaceRange)) { - return rangeToReformat.grown(delta); - } - else if (oldWhitespaceRange.getEndOffset() > rangeToReformat.getEndOffset()) { - return new TextRange(rangeToReformat.getStartOffset(), - Math.min(rangeToReformat.getEndOffset(), newWhitespaceRange.getEndOffset())); - } - else if (oldWhitespaceRange.getStartOffset() < rangeToReformat.getStartOffset()) { - final int unionLength = rangeToReformat.getEndOffset() - oldWhitespaceRange.getStartOffset(); - return TextRange.from(Math.max(oldWhitespaceRange.getStartOffset(), rangeToReformat.getStartOffset() + delta), - Math.min(rangeToReformat.getLength(), unionLength + delta)); - } + return rangeToReformat.grown(oldWhitespaceRange.getLength() - newWhitespaceRange.getLength()); } return rangeToReformat; } - private static void applyPendingChangesToPsi(@NotNull PsiElement source) { - final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(source.getContainingFile().getProject()); - final Document document = documentManager.getDocument(source.getContainingFile()); - if (document != null) { - documentManager.doPostponedOperationsAndUnblockDocument(document); - } - } - @NotNull private static TextRange findTrailingWhitespacesRange(@NotNull PsiFile file) { final CharSequence contents = file.getViewProvider().getContents(); @@ -120,29 +95,25 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces @NotNull private static TextRange replaceOrDeleteTrailingWhitespaces(@NotNull final PsiFile pyFile, @NotNull final TextRange whitespaceRange) { final Project project = pyFile.getProject(); - final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); - final Document document = documentManager.getDocument(pyFile); - if (document != null) { - final PyCodeStyleSettings customSettings = CodeStyleSettingsManager.getSettings(project).getCustomSettings(PyCodeStyleSettings.class); - final boolean addLineFeed = customSettings.BLANK_LINE_AT_FILE_END || EditorSettingsExternalizable.getInstance().isEnsureNewLineAtEOF(); - try { - final String text = addLineFeed ? "\n" : ""; - // Do not add extra blank line in empty file - if (!text.isEmpty() && whitespaceRange.getStartOffset() != 0) { - if (!whitespaceRange.isEmpty()) { - document.replaceString(whitespaceRange.getStartOffset(), whitespaceRange.getEndOffset(), text); - } - else { - document.insertString(document.getTextLength(), text); - } + final PyCodeStyleSettings customSettings = CodeStyleSettingsManager.getSettings(project).getCustomSettings(PyCodeStyleSettings.class); + final boolean addLineFeed = customSettings.BLANK_LINE_AT_FILE_END || EditorSettingsExternalizable.getInstance().isEnsureNewLineAtEOF(); + + final String realWhitespace = whitespaceRange.substring(pyFile.getText()); + final String desiredWhitespace = addLineFeed ? "\n" : ""; + + // Do not add extra blank line in empty file + if (!realWhitespace.equals(desiredWhitespace) && (desiredWhitespace.isEmpty() || whitespaceRange.getStartOffset() != 0)) { + final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); + final Document document = documentManager.getDocument(pyFile); + if (document != null) { + documentManager.doPostponedOperationsAndUnblockDocument(document); + try { + document.replaceString(whitespaceRange.getStartOffset(), whitespaceRange.getEndOffset(), desiredWhitespace); + return TextRange.from(whitespaceRange.getStartOffset(), desiredWhitespace.length()); } - else if (!whitespaceRange.isEmpty()) { - document.deleteString(whitespaceRange.getStartOffset(), whitespaceRange.getEndOffset()); + finally { + documentManager.commitDocument(document); } - return TextRange.from(whitespaceRange.getStartOffset(), text.length()); - } - finally { - documentManager.commitDocument(document); } } return whitespaceRange;