IDEA-95410 Arrangement: Preserve fold regions on arrangement

This commit is contained in:
Svetlana.Zemlyanskay
2014-01-21 10:27:26 +04:00
parent 6e02e4df8e
commit 22d73991e7
4 changed files with 195 additions and 70 deletions
@@ -15,6 +15,9 @@
*/
package com.intellij.psi.codeStyle.arrangement
import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Modifier.PRIVATE
import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Modifier.PUBLIC
/**
* @author Denis Zhdanov
* @since 11/20/12 3:34 PM
@@ -24,51 +27,152 @@ class JavaRearrangerFoldingTest extends AbstractJavaRearrangerTest {
void "test dummy"() {
}
// This should be uncommented as soon as cdr pushed fixes for range markers processing.
// void "test that doc comment folding is preserved"() {
// commonSettings.BLANK_LINES_AROUND_METHOD = 1
// doTest(
// initial: '''\
//import <fold>java.util.List;
//import java.util.Set;</fold>
//
//<fold text="/**...*/">/**
// * Class comment
// */</fold>
//class Test {
//
// <fold text="/**...*/>/**
// * Method comment
// */</fold>
// private void test(List<String> l) {}
//
// <fold text="/**...*/>/**
// * Another method comment
// */</fold>
// public void test(Set<String> s) {}
//}''',
//
// rules: [rule(PUBLIC), rule(PRIVATE)],
//
// expected: '''\
//import <fold>java.util.List;
//import java.util.Set;</fold>
//
//<fold text="/**...*/">/**
// * Class comment
// */</fold>
//class Test {
//
// <fold text="/**...*/>/**
// * Another method comment
// */</fold>
// public void test(Set<String> s) {}
//
// <fold text="/**...*/>/**
// * Method comment
// */</fold>
// private void test(List<String> l) {}
//}'''
// )
// }
void "test that doc comment folding is preserved"() {
commonSettings.BLANK_LINES_AROUND_METHOD = 1
doTest(
initial: '''\
import <fold>java.util.List;
import java.util.Set;</fold>
<fold text="/**...*/">/**
* Class comment
*/</fold>
class Test {
<fold text="/**...*/>/**
* Method comment
*/</fold>
private void test(List<String> l) {}
<fold text="/**...*/>/**
* Another method comment
*/</fold>
public void test(Set<String> s) {}
}''',
rules: [rule(PUBLIC), rule(PRIVATE)],
expected: '''\
import <fold>java.util.List;
import java.util.Set;</fold>
<fold text="/**...*/">/**
* Class comment
*/</fold>
class Test {
<fold text="/**...*/>/**
* Another method comment
*/</fold>
public void test(Set<String> s) {}
<fold text="/**...*/>/**
* Method comment
*/</fold>
private void test(List<String> l) {}
}'''
)
}
void "test that doc comment and method folding is preserved"() {
commonSettings.BLANK_LINES_AROUND_METHOD = 1
doTest(
initial: '''\
import java.util.List;
import java.util.Set;
class MyTest {
<fold text="/**...*/">/**
* comment 1
*
* @param s
*/</fold>
private void test(String s) {
}
/**
* comment 2
*
* @param i
*/
public void test(int i) {
}
}''',
rules: [rule(PUBLIC), rule(PRIVATE)],
expected: '''\
import java.util.List;
import java.util.Set;
class MyTest {
/**
* comment 2
*
* @param i
*/
public void test(int i) {
}
<fold text="/**...*/">/**
* comment 1
*
* @param s
*/</fold>
private void test(String s) {
}
}'''
)
}
void "test that single doc comment folding is preserved"() {
commonSettings.BLANK_LINES_AROUND_METHOD = 1
doTest(
initial: '''\
package a.b;
class MyTest {
/**
* private comment
*
* @param s
*/
private void test(String s) {
}
/**
* comment 2
*
* @param i
*/
public void test(int i) <fold text="{...}">{
System.out.println(1);
}</fold>
}''',
rules: [rule(PUBLIC), rule(PRIVATE)],
expected: '''\
package a.b;
class MyTest {
/**
* comment 2
*
* @param i
*/
public void test(int i) <fold text="{...}">{
System.out.println(1);
}</fold>
/**
* private comment
*
* @param s
*/
private void test(String s) {
}
}'''
)
}
}
@@ -194,7 +194,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
@Override
public void run() {
engine.arrange(finalFile, Collections.singleton(rangeToUse));
engine.arrange(editor, finalFile, Collections.singleton(rangeToUse));
}
}, getTemplatePresentation().getText(), null);
}
@@ -53,12 +53,25 @@ import java.util.*;
*/
public class ArrangementEngine {
/**
* Arranges given PSI root contents that belong to the given ranges.
* <b>Note:</b> After arrangement editor foldings we'll be preserved.
*
* @param editor
* @param file target PSI root
* @param ranges target ranges to use within the given root
*/
public void arrange(@NotNull final Editor editor, @NotNull PsiFile file, Collection<TextRange> ranges) {
arrange(file, ranges, null);
// This should be uncommented as soon as cdr pushed fixes for range markers processing.
//arrange(file, ranges, new RestoreFoldArrangementCallback(editor));
arrange(file, ranges, new RestoreFoldArrangementCallback(editor));
}
/**
* Arranges given PSI root contents that belong to the given ranges.
* <b>Note:</b> Editor foldings are not expected to be preserved.
*
* @param file target PSI root
* @param ranges target ranges to use within the given root
*/
public void arrange(@NotNull PsiFile file, @NotNull Collection<TextRange> ranges) {
arrange(file, ranges, null);
}
@@ -18,16 +18,10 @@ package com.intellij.psi.codeStyle.arrangement.engine;
import com.intellij.codeInsight.folding.CodeFoldingManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.FoldRegion;
import com.intellij.openapi.fileEditor.impl.text.CodeFoldingState;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.Comparator;
import java.util.ArrayList;
import java.util.List;
/**
@@ -37,34 +31,48 @@ import java.util.List;
public class RestoreFoldArrangementCallback implements ArrangementCallback {
@NotNull private final Editor myEditor;
@Nullable private final CodeFoldingState myCodeFoldingState;
public RestoreFoldArrangementCallback(@NotNull Editor editor) {
myEditor = editor;
Project project = editor.getProject();
if (project == null) {
myCodeFoldingState = null;
}
else {
final CodeFoldingManager foldingManager = CodeFoldingManager.getInstance(editor.getProject());
myCodeFoldingState = foldingManager.saveFoldingState(editor);
}
}
@Override
public void afterArrangement(@NotNull final List<ArrangementMoveInfo> moveInfos) {
// Restore state for the PSI elements not affected by arrangement.
Project project = myEditor.getProject();
if (myCodeFoldingState != null && project != null) {
if (project != null) {
final FoldRegion[] regions = myEditor.getFoldingModel().getAllFoldRegions();
final List<FoldRegionInfo> foldRegionsInfo = new ArrayList<FoldRegionInfo>();
for (FoldRegion region : regions) {
final FoldRegionInfo info = new FoldRegionInfo(region.getStartOffset(), region.getEndOffset(), region.isExpanded());
foldRegionsInfo.add(info);
}
final CodeFoldingManager foldingManager = CodeFoldingManager.getInstance(project);
foldingManager.updateFoldRegions(myEditor);
myEditor.getFoldingModel().runBatchFoldingOperation(new Runnable() {
@Override
public void run() {
foldingManager.restoreFoldingState(myEditor, myCodeFoldingState);
for (FoldRegionInfo info : foldRegionsInfo) {
final FoldRegion foldRegion = foldingManager.findFoldRegion(myEditor, info.myStart, info.myEnd);
if (foldRegion != null) {
foldRegion.setExpanded(info.myIsExpanded);
}
}
}
});
}
}
private static class FoldRegionInfo {
private int myStart;
private int myEnd;
private boolean myIsExpanded;
private FoldRegionInfo(int start, int end, boolean expanded) {
myStart = start;
myEnd = end;
myIsExpanded = expanded;
}
}
}