mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-132554 automatic window scroll after CTRL-ALT-L
This commit is contained in:
@@ -17,7 +17,6 @@ package com.intellij.openapi.editor.impl;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.TextChange;
|
||||
import com.intellij.util.text.CharArrayCharSequence;
|
||||
import com.intellij.util.text.StringFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -174,6 +173,20 @@ public class BulkChangesMerger {
|
||||
data[i + offset] = text.charAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an offset of some location in the document, returns offset of this location after application of given changes. List of changes
|
||||
* is supposed to satisfy the same constraints as required by {@link #mergeToCharSequence(char[], int, List)} method.
|
||||
*/
|
||||
public int updateOffset(int originalOffset, @NotNull List<? extends TextChange> changes) {
|
||||
int offset = originalOffset;
|
||||
for (TextChange change : changes) {
|
||||
if (originalOffset > change.getStart()) {
|
||||
offset += change.getText().length() - (change.getEnd() - change.getStart());
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
private static class Context {
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.formatting.FormattingProgressTask;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.SelectionModel;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -34,8 +36,11 @@ import com.intellij.util.diff.FilesTooBigForDiffException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
@@ -106,8 +111,6 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
|
||||
throws IncorrectOperationException
|
||||
{
|
||||
return new FutureTask<Boolean>(new Callable<Boolean>() {
|
||||
private Document myDocument;
|
||||
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
FormattingProgressTask.FORMATTING_CANCELLED_FLAG.set(false);
|
||||
@@ -115,16 +118,18 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
|
||||
Collection<TextRange> ranges = getRangesToFormat(processChangedTextOnly, file);
|
||||
|
||||
CharSequence before = null;
|
||||
Document document = PsiDocumentManager.getInstance(myProject).getDocument(file);
|
||||
if (getInfoCollector() != null) {
|
||||
myDocument = PsiDocumentManager.getInstance(myProject).getDocument(file);
|
||||
LOG.assertTrue(myDocument != null);
|
||||
before = myDocument.getImmutableCharSequence();
|
||||
LOG.assertTrue(document != null);
|
||||
before = document.getImmutableCharSequence();
|
||||
}
|
||||
|
||||
CaretVisualPositionKeeper caretPositionKeeper = new CaretVisualPositionKeeper(document);
|
||||
CodeStyleManager.getInstance(myProject).reformatText(file, ranges);
|
||||
caretPositionKeeper.restoreOriginalLocation();
|
||||
|
||||
if (before != null) {
|
||||
prepareUserNotificationMessage(myDocument, before);
|
||||
prepareUserNotificationMessage(document, before);
|
||||
}
|
||||
|
||||
return !FormattingProgressTask.FORMATTING_CANCELLED_FLAG.get();
|
||||
@@ -165,4 +170,32 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
|
||||
|
||||
return !myRanges.isEmpty() ? myRanges : ContainerUtil.newArrayList(file.getTextRange());
|
||||
}
|
||||
|
||||
private static class CaretVisualPositionKeeper {
|
||||
private final Map<Editor, Integer> myCaretRelativeVerticalPositions = new HashMap<Editor, Integer>();
|
||||
|
||||
private CaretVisualPositionKeeper(@Nullable Document document) {
|
||||
if (document == null) return;
|
||||
|
||||
Editor[] editors = EditorFactory.getInstance().getEditors(document);
|
||||
for (Editor editor : editors) {
|
||||
Rectangle visibleArea = editor.getScrollingModel().getVisibleArea();
|
||||
Point pos = editor.visualPositionToXY(editor.getCaretModel().getVisualPosition());
|
||||
int relativePosition = pos.y - visibleArea.y;
|
||||
myCaretRelativeVerticalPositions.put(editor, relativePosition);
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreOriginalLocation() {
|
||||
for (Map.Entry<Editor, Integer> e : myCaretRelativeVerticalPositions.entrySet()) {
|
||||
Editor editor = e.getKey();
|
||||
int relativePosition = e.getValue();
|
||||
Point caretLocation = editor.visualPositionToXY(editor.getCaretModel().getVisualPosition());
|
||||
int scrollOffset = caretLocation.y - relativePosition;
|
||||
editor.getScrollingModel().disableAnimation();
|
||||
editor.getScrollingModel().scrollVertically(scrollOffset);
|
||||
editor.getScrollingModel().enableAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.TextChange;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.editor.impl.BulkChangesMerger;
|
||||
@@ -349,9 +351,7 @@ class FormatProcessor {
|
||||
{
|
||||
FormattingDocumentModel documentModel = model.getDocumentModel();
|
||||
Document document = documentModel.getDocument();
|
||||
if (document == null) {
|
||||
return false;
|
||||
}
|
||||
CaretOffsetUpdater caretOffsetUpdater = new CaretOffsetUpdater(document);
|
||||
|
||||
List<TextChange> changes = new ArrayList<TextChange>();
|
||||
int shift = 0;
|
||||
@@ -363,6 +363,7 @@ class FormatProcessor {
|
||||
whiteSpace.getEndOffset(), block.getNode(), false
|
||||
);
|
||||
if (changes.size() > 10000) {
|
||||
caretOffsetUpdater.update(changes);
|
||||
CharSequence mergeResult = BulkChangesMerger.INSTANCE.mergeToCharSequence(document.getChars(), document.getTextLength(), changes);
|
||||
document.replaceString(0, document.getTextLength(), mergeResult);
|
||||
shift += currentIterationShift;
|
||||
@@ -373,8 +374,10 @@ class FormatProcessor {
|
||||
currentIterationShift += change.getDiff();
|
||||
changes.add(change);
|
||||
}
|
||||
caretOffsetUpdater.update(changes);
|
||||
CharSequence mergeResult = BulkChangesMerger.INSTANCE.mergeToCharSequence(document.getChars(), document.getTextLength(), changes);
|
||||
document.replaceString(0, document.getTextLength(), mergeResult);
|
||||
caretOffsetUpdater.restoreCaretLocations();
|
||||
cleanupBlocks(blocksToModify);
|
||||
return true;
|
||||
}
|
||||
@@ -1487,4 +1490,28 @@ class FormatProcessor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class CaretOffsetUpdater {
|
||||
private final Map<Editor, Integer> myCaretOffsets = new HashMap<Editor, Integer>();
|
||||
|
||||
private CaretOffsetUpdater(@NotNull Document document) {
|
||||
Editor[] editors = EditorFactory.getInstance().getEditors(document);
|
||||
for (Editor editor : editors) {
|
||||
myCaretOffsets.put(editor, editor.getCaretModel().getOffset());
|
||||
}
|
||||
}
|
||||
|
||||
private void update(@NotNull List<? extends TextChange> changes) {
|
||||
BulkChangesMerger merger = BulkChangesMerger.INSTANCE;
|
||||
for (Map.Entry<Editor, Integer> entry : myCaretOffsets.entrySet()) {
|
||||
entry.setValue(merger.updateOffset(entry.getValue(), changes));
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreCaretLocations() {
|
||||
for (Map.Entry<Editor, Integer> entry : myCaretOffsets.entrySet()) {
|
||||
entry.getKey().getCaretModel().moveToOffset(entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +127,18 @@ public class BulkChangesMergerTest {
|
||||
doTest("0123456789ABC", "0abc1358d9eBC", c("abc", 1), c("", 2, 3), c("", 4, 5), c("", 6, 8), c("d", 9), c("e", 10, 11));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateOffset() {
|
||||
doTestUpdateOffset(5, 5, c("a", 6));
|
||||
doTestUpdateOffset(5, 6, c("a", 3));
|
||||
doTestUpdateOffset(5, 5, c("a", 6, 7));
|
||||
doTestUpdateOffset(5, 5, c("a", 3, 4));
|
||||
doTestUpdateOffset(5, 4, c("", 3, 4));
|
||||
doTestUpdateOffset(5, 5, c("", 6, 7));
|
||||
|
||||
doTestUpdateOffset(5, 2, c("", 0, 1), c("", 2, 3), c("", 3, 4));
|
||||
}
|
||||
|
||||
//@Config(inplace = true)
|
||||
//@Test
|
||||
//public void client() {
|
||||
@@ -176,6 +188,10 @@ public class BulkChangesMergerTest {
|
||||
assertEquals(expected, actual.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void doTestUpdateOffset(int initialOffset, int expectedOffset, TextChangeImpl... changes) {
|
||||
assertEquals(expectedOffset, myMerger.updateOffset(initialOffset, Arrays.asList(changes)));
|
||||
}
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
Reference in New Issue
Block a user