mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-162062 Move Statement: Scope of shifted block changes
fix for Python use cases
This commit is contained in:
+87
-86
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user