don't expand single-line closure foldings when editing inside them

This commit is contained in:
peter
2012-03-29 13:31:00 +02:00
parent 4a3e957120
commit 8c2dc39670
7 changed files with 47 additions and 43 deletions
@@ -15,6 +15,7 @@
*/
package com.intellij.codeInsight.folding.impl;
import com.intellij.codeInsight.daemon.impl.CollectHighlightsUtil;
import com.intellij.codeInsight.folding.JavaCodeFoldingSettings;
import com.intellij.codeInsight.generation.OverrideImplementUtil;
import com.intellij.lang.ASTNode;
@@ -47,7 +48,10 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class JavaFoldingBuilder extends CustomFoldingBuilder implements DumbAware {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.folding.impl.JavaFoldingBuilder");
@@ -312,7 +316,9 @@ public class JavaFoldingBuilder extends CustomFoldingBuilder implements DumbAwar
if (importKeyword == null) return null;
int startOffset = importKeyword.getTextRange().getEndOffset() + 1;
int endOffset = statements[statements.length - 1].getTextRange().getEndOffset();
return new TextRange(startOffset, endOffset);
if (!hasErrorElementsNearby(element.getContainingFile(), startOffset, endOffset)) {
return new TextRange(startOffset, endOffset);
}
}
if (element instanceof PsiDocComment) {
return element.getTextRange();
@@ -330,6 +336,16 @@ public class JavaFoldingBuilder extends CustomFoldingBuilder implements DumbAwar
return null;
}
public static boolean hasErrorElementsNearby(final PsiFile file, int startOffset, int endOffset) {
endOffset = CharArrayUtil.shiftForward(file.getText(), endOffset, " \t\n");
for (PsiElement element : CollectHighlightsUtil.getElementsInRange(file, startOffset, endOffset)) {
if (element instanceof PsiErrorElement) {
return true;
}
}
return false;
}
@Nullable
private static TextRange getFileHeader(PsiJavaFile file) {
PsiElement first = file.getFirstChild();
@@ -167,6 +167,32 @@ class Test {
assertEquals(2, closureFolds.size())
}
public void "test closure folding doesn't expand when editing inside"() {
def text = """\
class Test {
void test() {
new Runnable() {
public void run() {
System.out.println(<caret>);
}
};
}
}
"""
configure text
def foldingModel = myFixture.editor.foldingModel as FoldingModelImpl
def closureStartFold = foldingModel.getCollapsedRegionAtOffset(text.indexOf("Runnable"))
assertNotNull closureStartFold
assertFalse closureStartFold.expanded
assert text.substring(closureStartFold.endOffset).startsWith('System') //one line closure
myFixture.type('2')
myFixture.doHighlighting()
closureStartFold = foldingModel.getCollapsedRegionAtOffset(text.indexOf("Runnable"))
assert closureStartFold
}
public void testFindInFolding() {
def text = """\
class Test {
@@ -131,7 +131,6 @@ class MoverWrapper {
}
});
}
CodeFoldingManager.getInstance(project).allowFoldingOnCaretLine(editor);
if (hasSelection) {
restoreSelection(editor, selectionStart, selectionEnd, start, myInfo.range2.getStartOffset());
@@ -50,14 +50,4 @@ public abstract class CodeFoldingManager {
public abstract void releaseFoldings(Editor editor);
public abstract void buildInitialFoldings(Editor editor);
/**
* Asks do not perform automatic expansion of fold region that is located on the caret line during the next fold regions update.
* <p/>
* This method is necessary because fold regions that are located on caret line are automatically expanded to prevent problem
* from IDEA-64687. However, we don't want such an expansion when we, for example, move method up or down.
*
* @param editor target editor
*/
public abstract void allowFoldingOnCaretLine(@NotNull Editor editor);
}
@@ -331,9 +331,4 @@ public class CodeFoldingManagerImpl extends CodeFoldingManager implements Projec
document.putUserData(FOLDING_STATE_INFO_IN_DOCUMENT_KEY, null);
}
}
@Override
public void allowFoldingOnCaretLine(@NotNull Editor editor) {
editor.putUserData(UpdateFoldRegionsOperation.ALLOW_FOLDING_ON_CARET_LINE_KEY, true);
}
}
@@ -18,14 +18,12 @@ package com.intellij.codeInsight.folding.impl;
import com.intellij.lang.folding.FoldingDescriptor;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.FoldRegion;
import com.intellij.openapi.editor.FoldingGroup;
import com.intellij.openapi.editor.ex.FoldingModelEx;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -43,9 +41,6 @@ import static com.intellij.util.containers.CollectionFactory.newTroveMap;
* @author cdr
*/
class UpdateFoldRegionsOperation implements Runnable {
static final Key<Boolean> ALLOW_FOLDING_ON_CARET_LINE_KEY = Key.create("AllowFoldingOnCaretLine.KEY");
private final Project myProject;
private final Editor myEditor;
private final PsiFile myFile;
@@ -80,9 +75,6 @@ class UpdateFoldRegionsOperation implements Runnable {
List<FoldRegion> newRegions = addNewRegions(info, foldingModel, rangeToExpandStatusMap, shouldExpand, groupExpand);
applyExpandStatus(newRegions, shouldExpand, groupExpand);
// Reset the key.
myEditor.putUserData(ALLOW_FOLDING_ON_CARET_LINE_KEY, false);
}
private static void applyExpandStatus(@NotNull List<FoldRegion> newRegions,
@@ -147,24 +139,9 @@ class UpdateFoldRegionsOperation implements Runnable {
// Considering that this code is executed only on initial fold regions construction on editor opening.
return !FoldingPolicy.isCollapseByDefault(element);
}
boolean caretInside;
if (myEditor.getUserData(ALLOW_FOLDING_ON_CARET_LINE_KEY) == Boolean.TRUE) {
caretInside = FoldingUtil.caretInsideRange(myEditor, range);
}
else {
final Document document = myEditor.getDocument();
final int firstLine = document.getLineNumber(range.getStartOffset());
final int lastLine = document.getLineNumber(range.getEndOffset());
int caretOffset = myEditor.getCaretModel().getOffset();
if (caretOffset > myEditor.getDocument().getTextLength()) {
return false;
}
final int currentLine = document.getLineNumber(caretOffset);
caretInside = firstLine <= currentLine && currentLine <= lastLine;
}
final Boolean oldStatus = rangeToExpandStatusMap.get(range);
return oldStatus == null || caretInside || oldStatus.booleanValue();
return oldStatus == null || FoldingUtil.caretInsideRange(myEditor, range) || oldStatus.booleanValue();
}
private void removeInvalidRegions(@NotNull EditorFoldingInfo info,
@@ -17,6 +17,7 @@
package org.jetbrains.plugins.groovy.lang.folding;
import com.intellij.codeInsight.folding.JavaCodeFoldingSettings;
import com.intellij.codeInsight.folding.impl.JavaFoldingBuilder;
import com.intellij.lang.ASTNode;
import com.intellij.lang.folding.CustomFoldingBuilder;
import com.intellij.lang.folding.FoldingDescriptor;
@@ -194,7 +195,7 @@ public class GroovyFoldingBuilder extends CustomFoldingBuilder implements Groovy
int start = first.getTextRange().getStartOffset();
int end = marker.getTextRange().getEndOffset();
int tail = "import ".length();
if (start + tail < end) {
if (start + tail < end && !JavaFoldingBuilder.hasErrorElementsNearby(first.getContainingFile(), start, end)) {
descriptors.add(new FoldingDescriptor(first.getNode(), new TextRange(start + tail, end)));
}
}