IDEA-170464 "Move statement" messes up whitespace and comments around fields

fix moving through whitespace
This commit is contained in:
Dmitry Batrak
2017-04-17 11:46:03 +03:00
parent 1fe9bfd616
commit efd2f38df3
5 changed files with 93 additions and 28 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -22,13 +22,16 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
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.jsp.jspJava.JspClassLevelDeclarationStatement;
import com.intellij.psi.impl.source.tree.Factory;
import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -163,25 +166,45 @@ class DeclarationMover extends LineMover {
}
final boolean areWeMovingClass = range.firstElement instanceof PsiClass;
info.toMove = range;
try {
LineRange intraClassRange = moveInsideOutsideClassPosition(editor, sibling, down, areWeMovingClass);
if (intraClassRange == null) {
info.toMove2 = new LineRange(sibling, sibling, document);
if (down && sibling.getNextSibling() == null) return false;
}
else {
info.toMove2 = intraClassRange;
}
if (down ? info.toMove2.startLine < info.toMove.endLine : info.toMove2.endLine > info.toMove.startLine) {
return false;
}
int neibourghLine = down ? range.endLine : range.startLine - 1;
if (neibourghLine >= 0 && neibourghLine < document.getLineCount() &&
CharArrayUtil.containsOnlyWhiteSpaces(document.getImmutableCharSequence().subSequence(document.getLineStartOffset(neibourghLine),
document.getLineEndOffset(neibourghLine))) &&
emptyLineCanBeDeletedAccordingToCodeStyle(file, document, document.getLineEndOffset(neibourghLine))) {
info.toMove2 = new LineRange(neibourghLine, neibourghLine + 1);
}
catch (IllegalMoveException e) {
info.toMove2 = null;
else {
try {
LineRange intraClassRange = moveInsideOutsideClassPosition(editor, sibling, down, areWeMovingClass);
if (intraClassRange == null) {
info.toMove2 = new LineRange(sibling, sibling, document);
if (down && sibling.getNextSibling() == null) return false;
}
else {
info.toMove2 = intraClassRange;
}
if (down ? info.toMove2.startLine < info.toMove.endLine : info.toMove2.endLine > info.toMove.startLine) {
return false;
}
}
catch (IllegalMoveException e) {
info.toMove2 = null;
}
}
return true;
}
private static boolean emptyLineCanBeDeletedAccordingToCodeStyle(PsiFile file, Document document, int offset) {
CharSequence text = document.getImmutableCharSequence();
String whitespace = " \t\n";
int whitespaceStartOffset = CharArrayUtil.shiftBackward(text, offset - 1, whitespace) + 1;
int whitespaceEndOffset = CharArrayUtil.shiftForward(text, offset, whitespace);
int minLineFeeds = CodeStyleManager.getInstance(file.getProject()).getMinLineFeeds(file, whitespaceEndOffset);
int actualLineFeeds = StringUtil.countNewLines(text.subSequence(whitespaceStartOffset, whitespaceEndOffset));
return actualLineFeeds > minLineFeeds;
}
private static LineRange memberRange(@NotNull PsiElement member, Editor editor, LineRange lineRange) {
final TextRange textRange = member.getTextRange();
if (editor.getDocument().getTextLength() < textRange.getEndOffset()) return null;
@@ -278,6 +278,15 @@ public abstract class CodeStyleManager {
return -1;
}
/**
* Calculates minimum number of line feeds that should precede block starting at given offset, as dictated by formatting model.
* Returns <code>-1</code>, if required block cannot be found at provided offset,
* or spacing cannot be calculated due to some other reason.
*/
public int getMinLineFeeds(@NotNull PsiFile file, int offset) {
return -1;
}
/**
* Retrieves the current formatting mode.
*
@@ -132,6 +132,13 @@ public abstract class FormatterEx{
* or spacing cannot be calculated due to some other reason.
*/
public abstract int getSpacingForBlockAtOffset(FormattingModel model, int offset);
/**
* Calculates minimum number of line feeds that should precede block starting at given offset, as dictated by formatting model.
* Returns <code>-1</code>, if required block cannot be found at provided offset,
* or spacing cannot be calculated due to some other reason.
*/
public abstract int getMinLineFeedsBeforeBlockAtOffset(FormattingModel model, int offset);
public interface IndentInfoStorage {
void saveIndentInfo(@Nullable IndentInfo info, int startOffset);
@@ -114,24 +114,39 @@ public class FormatterImpl extends FormatterEx
@Override
public int getSpacingForBlockAtOffset(FormattingModel model, int offset) {
SpacingImpl spacing = getSpacingBeforeBlockAtOffset(model, offset);
if (spacing != null) {
int minSpaces = spacing.getMinSpaces();
if (minSpaces >= 0) {
return minSpaces;
}
}
return -1;
}
@Override
public int getMinLineFeedsBeforeBlockAtOffset(FormattingModel model, int offset) {
SpacingImpl spacing = getSpacingBeforeBlockAtOffset(model, offset);
if (spacing != null) {
int minLineFeeds = spacing.getMinLineFeeds();
if (minLineFeeds >= 0) {
return minLineFeeds;
}
}
return -1;
}
private static SpacingImpl getSpacingBeforeBlockAtOffset(FormattingModel model, int offset) {
Couple<Block> blockWithParent = getBlockAtOffset(null, model.getRootBlock(), offset);
if (blockWithParent != null) {
Block parentBlock = blockWithParent.first;
Block targetBlock = blockWithParent.second;
if (parentBlock != null && targetBlock != null) {
Block prevBlock = findPreviousSibling(parentBlock, targetBlock);
if (prevBlock != null) {
SpacingImpl spacing = (SpacingImpl)parentBlock.getSpacing(prevBlock, targetBlock);
if (spacing != null) {
int minSpaces = spacing.getMinSpaces();
if (minSpaces >= 0) {
return minSpaces;
}
}
}
if (prevBlock != null) return (SpacingImpl)parentBlock.getSpacing(prevBlock, targetBlock);
}
}
return -1;
return null;
}
@Nullable
@@ -883,10 +883,21 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting
@Override
public int getSpacing(@NotNull PsiFile file, int offset) {
FormattingModel model = createFormattingModel(file);
return model == null ? -1 : FormatterEx.getInstance().getSpacingForBlockAtOffset(model, offset);
}
@Override
public int getMinLineFeeds(@NotNull PsiFile file, int offset) {
FormattingModel model = createFormattingModel(file);
return model == null ? -1 : FormatterEx.getInstance().getMinLineFeedsBeforeBlockAtOffset(model, offset);
}
@Nullable
private static FormattingModel createFormattingModel(@NotNull PsiFile file) {
FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(file);
if (builder == null) return -1;
if (builder == null) return null;
CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(file.getProject());
FormattingModel model = builder.createModel(file, settings);
return FormatterEx.getInstance().getSpacingForBlockAtOffset(model, offset);
return builder.createModel(file, settings);
}
}