diff --git a/java/java-impl/src/com/intellij/application/options/editor/JavaCodeFoldingOptionsProvider.java b/java/java-impl/src/com/intellij/application/options/editor/JavaCodeFoldingOptionsProvider.java index e33b90bab9aa..7657ea05396d 100644 --- a/java/java-impl/src/com/intellij/application/options/editor/JavaCodeFoldingOptionsProvider.java +++ b/java/java-impl/src/com/intellij/application/options/editor/JavaCodeFoldingOptionsProvider.java @@ -27,6 +27,7 @@ import com.intellij.openapi.options.BeanConfigurable; public class JavaCodeFoldingOptionsProvider extends BeanConfigurable implements CodeFoldingOptionsProvider { public JavaCodeFoldingOptionsProvider() { super(JavaCodeFoldingSettings.getInstance()); + checkBox("COLLAPSE_ONE_LINE_METHODS", ApplicationBundle.message("checkbox.collapse.one.line.methods")); checkBox("COLLAPSE_ACCESSORS", ApplicationBundle.message("checkbox.collapse.simple.property.accessors")); checkBox("COLLAPSE_INNER_CLASSES", ApplicationBundle.message("checkbox.collapse.inner.classes")); checkBox("COLLAPSE_ANONYMOUS_CLASSES", ApplicationBundle.message("checkbox.collapse.anonymous.classes")); diff --git a/java/java-psi-api/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java b/java/java-psi-api/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java index 585ce02a81f6..360b9832431d 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java @@ -39,6 +39,8 @@ public abstract class JavaCodeFoldingSettings { public abstract boolean isCollapseAccessors(); public abstract void setCollapseAccessors(boolean value); + public abstract boolean isCollapseOneLineMethods(); + public abstract boolean isCollapseInnerClasses(); public abstract void setCollapseInnerClasses(boolean value); diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsBase.java b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsBase.java index c092b5398a81..ee3ff0c3ffd8 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsBase.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsBase.java @@ -4,7 +4,8 @@ import com.intellij.codeInsight.folding.CodeFoldingSettings; import com.intellij.codeInsight.folding.JavaCodeFoldingSettings; public class JavaCodeFoldingSettingsBase extends JavaCodeFoldingSettings { - @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ACCESSORS = true; + @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ACCESSORS = false; + @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ONE_LINE_METHODS = true; @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_INNER_CLASSES = false; @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ANONYMOUS_CLASSES = false; @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ANNOTATIONS = false; @@ -63,6 +64,10 @@ public class JavaCodeFoldingSettingsBase extends JavaCodeFoldingSettings { public void setCollapseAccessors(boolean value) { COLLAPSE_ACCESSORS = value; } + @Override + public boolean isCollapseOneLineMethods() { + return COLLAPSE_ONE_LINE_METHODS; + } @Override public boolean isCollapseInnerClasses() { diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java index 8f488089c5b1..b41370fd5c5e 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java @@ -81,11 +81,6 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem PsiStatement[] statements = body.getStatements(); if (statements.length == 0) return false; - if (!areOnAdjacentLines(body.getLBrace(), statements[0]) || !areOnAdjacentLines(statements[statements.length - 1], body.getRBrace())) { - //the user might intend to type at an empty line - return false; - } - PsiStatement statement = statements[0]; if (PropertyUtil.isSimplePropertyGetter(method)) { if (statement instanceof PsiReturnStatement) { @@ -533,8 +528,8 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem if (child instanceof PsiMethod) { PsiMethod method = (PsiMethod)child; - boolean accessor = isSimplePropertyAccessor(method) && addInlineAccessorFolding(list, method); - if (!accessor) { + boolean oneLiner = addOneLineMethodFolding(list, method); + if (!oneLiner) { addToFold(list, method, document, true); } addAnnotationsToFold(method.getModifierList(), list, document); @@ -547,7 +542,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem } PsiCodeBlock body = method.getBody(); - if (body != null && !accessor) { + if (body != null && !oneLiner) { addCodeBlockFolds(body, list, processedComments, document, quick); } } @@ -581,23 +576,33 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem } } - private static boolean addInlineAccessorFolding(List descriptorList, PsiMethod accessor) { - if (!JavaCodeFoldingSettings.getInstance().isCollapseAccessors()) { + private static boolean addOneLineMethodFolding(List descriptorList, PsiMethod method) { + if (!JavaCodeFoldingSettings.getInstance().isCollapseOneLineMethods()) { return false; } - PsiCodeBlock body = accessor.getBody(); - assert body != null; - if (body.getStatements().length > 1) { + PsiCodeBlock body = method.getBody(); + if (body == null) { + return false; + } + PsiJavaToken lBrace = body.getLBrace(); + PsiJavaToken rBrace = body.getRBrace(); + PsiStatement[] statements = body.getStatements(); + if (lBrace == null || rBrace == null || statements.length != 1) { return false; } - PsiStatement statement = body.getStatements()[0]; + PsiStatement statement = statements[0]; if (statement.textContains('\n')) { return false; } - int leftStart = accessor.getParameterList().getTextRange().getEndOffset(); + if (!areOnAdjacentLines(body.getLBrace(), statement) || !areOnAdjacentLines(statement, body.getRBrace())) { + //the user might intend to type at an empty line + return false; + } + + int leftStart = method.getParameterList().getTextRange().getEndOffset(); int leftEnd = statement.getTextRange().getStartOffset(); int rightStart = statement.getTextRange().getEndOffset(); int rightEnd = body.getTextRange().getEndOffset(); @@ -605,9 +610,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem return false; } - FoldingGroup group = FoldingGroup.newGroup("simple property accessor"); - PsiJavaToken lBrace = body.getLBrace(); - assert lBrace != null; + FoldingGroup group = FoldingGroup.newGroup("one-liner"); descriptorList.add(new FoldingDescriptor(lBrace.getNode(), new TextRange(leftStart, leftEnd), group) { @Nullable @Override @@ -616,8 +619,6 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem } }); - PsiJavaToken rBrace = body.getRBrace(); - assert rBrace != null; descriptorList.add(new FoldingDescriptor(rBrace.getNode(), new TextRange(rightStart, rightEnd), group) { @Nullable @Override @@ -627,7 +628,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem }); return true; } - + @Override protected String getLanguagePlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) { return getPlaceholderText(SourceTreeToPsiMap.treeElementToPsi(node)); @@ -644,7 +645,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem if (element instanceof PsiJavaToken && element.getParent() instanceof PsiCodeBlock && element.getParent().getParent() instanceof PsiMethod) { - return settings.isCollapseAccessors(); + return settings.isCollapseOneLineMethods(); } if (element instanceof PsiReferenceParameterList) { return settings.isCollapseConstructorGenericParameters(); @@ -654,9 +655,6 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem return settings.isCollapseImports(); } else if (element instanceof PsiMethod || element instanceof PsiClassInitializer || element instanceof PsiCodeBlock) { - if (!settings.isCollapseAccessors() && !settings.isCollapseMethods()) { - return false; - } if (element instanceof PsiMethod && isSimplePropertyAccessor((PsiMethod)element)) { return settings.isCollapseAccessors(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy index da738dc43786..3c4cd6c1cc2c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy @@ -481,17 +481,6 @@ class Test { def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } assert regions.size() == 6 - Closure checkAccessorFolding = { FoldRegion region1, FoldRegion region2, PsiMethod method -> - assert region1.startOffset == method.parameterList.textRange.endOffset - assert region1.endOffset == method.body.statements[0].textRange.startOffset - assert region1.placeholderText == ' { ' - - assert region2.startOffset == method.body.statements[0].textRange.endOffset - assert region2.endOffset == method.textRange.endOffset - assert region2.placeholderText == ' }' - assert region1.group == region2.group - } - checkAccessorFolding(regions[0], regions[1], fooClass.methods[0]) checkAccessorFolding(regions[2], regions[3], fooClass.methods[1]) @@ -499,6 +488,30 @@ class Test { assert regions[5].placeholderText == '{...}' } + static checkAccessorFolding(FoldRegion region1, FoldRegion region2, PsiMethod method) { + assert region1.startOffset == method.parameterList.textRange.endOffset + assert region1.endOffset == method.body.statements[0].textRange.startOffset + assert region1.placeholderText == ' { ' + + assert region2.startOffset == method.body.statements[0].textRange.endOffset + assert region2.endOffset == method.textRange.endOffset + assert region2.placeholderText == ' }' + assert region1.group == region2.group + } + + public void "test fold one-line methods"() { + configure """class Foo { + int someMethod() { + return 0; + } + +}""" + PsiClass fooClass = JavaPsiFacade.getInstance(project).findClass('Foo', GlobalSearchScope.allScope(project)) + def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } + assert regions.size() == 2 + checkAccessorFolding(regions[0], regions[1], fooClass.methods[0]) + } + private def changeFoldRegions(Closure op) { myFixture.editor.foldingModel.runBatchFoldingOperationDoNotCollapseCaret(op) } diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index 58e199f26f73..89e0f4e99ca0 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -348,6 +348,7 @@ checkbox.collapse.i18n.messages=I18n strings checkbox.collapse.annotations=Annotations checkbox.collapse.inner.classes=Inner classes checkbox.collapse.simple.property.accessors=Simple property accessors +checkbox.collapse.one.line.methods=One-line methods checkbox.collapse.method.bodies=Method bodies checkbox.collapse.javadoc.comments=Documentation comments checkbox.collapse.title.imports=Imports