IDEA-162062 Move Statement: Scope of shifted block changes

fix for Python use cases
This commit is contained in:
Dmitry Batrak
2016-10-06 11:52:31 +03:00
parent 9aeb6bc8e5
commit 07f1ec121e
3 changed files with 89 additions and 88 deletions
@@ -54,96 +54,97 @@ class MoverWrapper {
assert myInfo.toMove2 != null;
myMover.beforeMove(editor, myInfo, myIsDown);
final Document document = editor.getDocument();
final int start = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.startLine);
final int end = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.endLine);
String textToInsert = document.getCharsSequence().subSequence(start, end).toString();
if (!StringUtil.endsWithChar(textToInsert,'\n')) textToInsert += '\n';
final int start2 = document.getLineStartOffset(myInfo.toMove2.startLine);
final int end2 = StatementUpDownMover.getLineStartSafeOffset(document,myInfo.toMove2.endLine);
String textToInsert2 = document.getCharsSequence().subSequence(start2, end2).toString();
if (!StringUtil.endsWithChar(textToInsert2,'\n')) textToInsert2 += '\n';
TextRange range = new TextRange(start, end);
TextRange range2 = new TextRange(start2, end2);
if (range.intersectsStrict(range2) && !range.equals(range2)) {
LOGGER.error("Wrong move ranges requested by " + myMover,
new Attachment("ranges.txt",
start + ":" + end + "(" + textToInsert + ")\n" + start2 + ":" + end2 + "(" + textToInsert2 + ")"));
return;
}
myInfo.range1 = document.createRangeMarker(start, end);
myInfo.range2 = document.createRangeMarker(start2, end2);
if (myInfo.range1.getStartOffset() < myInfo.range2.getStartOffset()) {
myInfo.range1.setGreedyToLeft(true);
myInfo.range1.setGreedyToRight(false);
myInfo.range2.setGreedyToLeft(true);
myInfo.range2.setGreedyToRight(true);
}
else {
myInfo.range1.setGreedyToLeft(true);
myInfo.range1.setGreedyToRight(true);
myInfo.range2.setGreedyToLeft(true);
myInfo.range2.setGreedyToRight(false);
}
final CaretModel caretModel = editor.getCaretModel();
final int caretRelativePos = caretModel.getOffset() - start;
final SelectionModel selectionModel = editor.getSelectionModel();
final int selectionStart = selectionModel.getSelectionStart();
final int selectionEnd = selectionModel.getSelectionEnd();
final boolean hasSelection = selectionModel.hasSelection();
// to prevent flicker
caretModel.moveToOffset(0);
// There is a possible case that the user performs, say, method move. It's also possible that one (or both) of moved methods
// are folded. We want to preserve their states then. The problem is that folding processing is based on PSI element pointers
// and the pointers behave as following during move up/down:
// method1() {}
// method2() {}
// Pointer for the fold region from method1 points to 'method2()' now and vice versa (check range markers processing on
// document change for further information). I.e. information about fold regions statuses holds the data swapped for
// 'method1' and 'method2'. Hence, we want to apply correct 'collapsed' status.
final FoldRegion topRegion = findTopLevelRegionInRange(editor, myInfo.range1);
final FoldRegion bottomRegion = findTopLevelRegionInRange(editor, myInfo.range2);
document.insertString(myInfo.range1.getStartOffset(), textToInsert2);
document.deleteString(myInfo.range1.getStartOffset()+textToInsert2.length(), myInfo.range1.getEndOffset());
document.insertString(myInfo.range2.getStartOffset(), textToInsert);
int s = myInfo.range2.getStartOffset() + textToInsert.length();
int e = myInfo.range2.getEndOffset();
if (e > s) {
document.deleteString(s, e);
}
final Project project = file.getProject();
PsiDocumentManager.getInstance(project).commitAllDocuments();
if (!myInfo.toMove.equals(myInfo.toMove2)) { // some movers (e.g. PyStatementMover) perform actual moving inside beforeMove/afterMove
final int start = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.startLine);
final int end = StatementUpDownMover.getLineStartSafeOffset(document, myInfo.toMove.endLine);
String textToInsert = document.getCharsSequence().subSequence(start, end).toString();
if (!StringUtil.endsWithChar(textToInsert,'\n')) textToInsert += '\n';
// Swap fold regions status if necessary.
if (topRegion != null && bottomRegion != null) {
CodeFoldingManager.getInstance(project).updateFoldRegions(editor);
editor.getFoldingModel().runBatchFoldingOperation(() -> {
FoldRegion newTopRegion = findTopLevelRegionInRange(editor, myInfo.range1);
if (newTopRegion != null) {
newTopRegion.setExpanded(bottomRegion.isExpanded());
}
final int start2 = document.getLineStartOffset(myInfo.toMove2.startLine);
final int end2 = StatementUpDownMover.getLineStartSafeOffset(document,myInfo.toMove2.endLine);
String textToInsert2 = document.getCharsSequence().subSequence(start2, end2).toString();
if (!StringUtil.endsWithChar(textToInsert2,'\n')) textToInsert2 += '\n';
FoldRegion newBottomRegion = findTopLevelRegionInRange(editor, myInfo.range2);
if (newBottomRegion != null) {
newBottomRegion.setExpanded(topRegion.isExpanded());
}
});
TextRange range = new TextRange(start, end);
TextRange range2 = new TextRange(start2, end2);
if (range.intersectsStrict(range2) && !range.equals(range2)) {
LOGGER.error("Wrong move ranges requested by " + myMover,
new Attachment("ranges.txt",
start + ":" + end + "(" + textToInsert + ")\n" + start2 + ":" + end2 + "(" + textToInsert2 + ")"));
return;
}
myInfo.range1 = document.createRangeMarker(start, end);
myInfo.range2 = document.createRangeMarker(start2, end2);
if (myInfo.range1.getStartOffset() < myInfo.range2.getStartOffset()) {
myInfo.range1.setGreedyToLeft(true);
myInfo.range1.setGreedyToRight(false);
myInfo.range2.setGreedyToLeft(true);
myInfo.range2.setGreedyToRight(true);
}
else {
myInfo.range1.setGreedyToLeft(true);
myInfo.range1.setGreedyToRight(true);
myInfo.range2.setGreedyToLeft(true);
myInfo.range2.setGreedyToRight(false);
}
final CaretModel caretModel = editor.getCaretModel();
final int caretRelativePos = caretModel.getOffset() - start;
final SelectionModel selectionModel = editor.getSelectionModel();
final int selectionStart = selectionModel.getSelectionStart();
final int selectionEnd = selectionModel.getSelectionEnd();
final boolean hasSelection = selectionModel.hasSelection();
// to prevent flicker
caretModel.moveToOffset(0);
// There is a possible case that the user performs, say, method move. It's also possible that one (or both) of moved methods
// are folded. We want to preserve their states then. The problem is that folding processing is based on PSI element pointers
// and the pointers behave as following during move up/down:
// method1() {}
// method2() {}
// Pointer for the fold region from method1 points to 'method2()' now and vice versa (check range markers processing on
// document change for further information). I.e. information about fold regions statuses holds the data swapped for
// 'method1' and 'method2'. Hence, we want to apply correct 'collapsed' status.
final FoldRegion topRegion = findTopLevelRegionInRange(editor, myInfo.range1);
final FoldRegion bottomRegion = findTopLevelRegionInRange(editor, myInfo.range2);
document.insertString(myInfo.range1.getStartOffset(), textToInsert2);
document.deleteString(myInfo.range1.getStartOffset()+textToInsert2.length(), myInfo.range1.getEndOffset());
document.insertString(myInfo.range2.getStartOffset(), textToInsert);
int s = myInfo.range2.getStartOffset() + textToInsert.length();
int e = myInfo.range2.getEndOffset();
if (e > s) {
document.deleteString(s, e);
}
PsiDocumentManager.getInstance(project).commitAllDocuments();
// Swap fold regions status if necessary.
if (topRegion != null && bottomRegion != null) {
CodeFoldingManager.getInstance(project).updateFoldRegions(editor);
editor.getFoldingModel().runBatchFoldingOperation(() -> {
FoldRegion newTopRegion = findTopLevelRegionInRange(editor, myInfo.range1);
if (newTopRegion != null) {
newTopRegion.setExpanded(bottomRegion.isExpanded());
}
FoldRegion newBottomRegion = findTopLevelRegionInRange(editor, myInfo.range2);
if (newBottomRegion != null) {
newBottomRegion.setExpanded(topRegion.isExpanded());
}
});
}
if (hasSelection) {
restoreSelection(editor, selectionStart, selectionEnd, start, end, myInfo.range2.getStartOffset());
}
caretModel.moveToOffset(myInfo.range2.getStartOffset() + caretRelativePos);
}
if (hasSelection) {
restoreSelection(editor, selectionStart, selectionEnd, start, end, myInfo.range2.getStartOffset());
}
caretModel.moveToOffset(myInfo.range2.getStartOffset() + caretRelativePos);
myMover.afterMove(editor, file, myInfo, myIsDown);
PsiDocumentManager.getInstance(project).commitDocument(document);
if (myInfo.indentTarget) {
+1 -1
View File
@@ -4,4 +4,4 @@ if condition:
class C:
pass
class B(Exception):
b=1
b=1
@@ -3,4 +3,4 @@ def f():
a = 1
else:
a = 2
#comment <caret>
#comment <caret>