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 b41370fd5c5e..c1875bcf8b91 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 @@ -7,6 +7,7 @@ import com.intellij.codeInsight.generation.OverrideImplementExploreUtil; import com.intellij.lang.ASTNode; import com.intellij.lang.folding.CustomFoldingBuilder; import com.intellij.lang.folding.FoldingDescriptor; +import com.intellij.lang.folding.NamedFoldingDescriptor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.FoldingGroup; @@ -69,10 +70,8 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem return "..."; } - private static boolean areOnAdjacentLines(PsiElement e1, PsiElement e2) { - Document document = e1.getContainingFile().getViewProvider().getDocument(); - return document != null && - document.getLineNumber(e1.getTextRange().getEndOffset()) + 1 == document.getLineNumber(e2.getTextRange().getStartOffset()); + private static boolean areOnAdjacentLines(PsiElement e1, PsiElement e2, Document document) { + return document.getLineNumber(e1.getTextRange().getEndOffset()) + 1 == document.getLineNumber(e2.getTextRange().getStartOffset()); } private static boolean isSimplePropertyAccessor(PsiMethod method) { @@ -576,13 +575,14 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem } } - private static boolean addOneLineMethodFolding(List descriptorList, PsiMethod method) { + private boolean addOneLineMethodFolding(List descriptorList, PsiMethod method) { if (!JavaCodeFoldingSettings.getInstance().isCollapseOneLineMethods()) { return false; } + Document document = method.getContainingFile().getViewProvider().getDocument(); PsiCodeBlock body = method.getBody(); - if (body == null) { + if (body == null || document == null) { return false; } PsiJavaToken lBrace = body.getLBrace(); @@ -597,7 +597,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem return false; } - if (!areOnAdjacentLines(body.getLBrace(), statement) || !areOnAdjacentLines(statement, body.getRBrace())) { + if (!areOnAdjacentLines(lBrace, statement, document) || !areOnAdjacentLines(statement, rBrace, document)) { //the user might intend to type at an empty line return false; } @@ -610,22 +610,15 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem return false; } - FoldingGroup group = FoldingGroup.newGroup("one-liner"); - descriptorList.add(new FoldingDescriptor(lBrace.getNode(), new TextRange(leftStart, leftEnd), group) { - @Nullable - @Override - public String getPlaceholderText() { - return " { "; - } - }); + String leftText = " { "; + String rightText = " }"; + if (!fitsRightMargin(method, document, leftStart, rightEnd, rightStart - leftEnd + leftText.length() + rightText.length())) { + return false; + } - descriptorList.add(new FoldingDescriptor(rBrace.getNode(), new TextRange(rightStart, rightEnd), group) { - @Nullable - @Override - public String getPlaceholderText() { - return " }"; - } - }); + FoldingGroup group = FoldingGroup.newGroup("one-liner"); + descriptorList.add(new NamedFoldingDescriptor(lBrace, leftStart, leftEnd, group, leftText)); + descriptorList.add(new NamedFoldingDescriptor(rBrace, rightStart, rightEnd, group, rightText)); return true; } @@ -797,41 +790,22 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem final int closureEnd = expression.getTextRange().getEndOffset(); boolean oneLine = false; String contents = seq.subSequence(firstLineStart, lastLineEnd).toString(); - if (contents.indexOf('\n') < 0) { - final int beforeLength = closureStart - document.getLineStartOffset(document.getLineNumber(closureStart)); - final int afterLength = document.getLineEndOffset(document.getLineNumber(closureEnd)) - closureEnd; - final int resultLineLength = beforeLength + lambdas.length() + contents.length() + 5 + afterLength; - - if (isBelowRightMargin(aClass.getProject(), resultLineLength)) { - rangeStart = CharArrayUtil.shiftForward(seq, rangeStart, " \n\t"); - rangeEnd = CharArrayUtil.shiftBackward(seq, rangeEnd - 1, " \n\t") + 1; - oneLine = true; - } + if (contents.indexOf('\n') < 0 && + fitsRightMargin(aClass, document, closureStart, closureEnd, lambdas.length() + contents.length() + 5)) { + rangeStart = CharArrayUtil.shiftForward(seq, rangeStart, " \n\t"); + rangeEnd = CharArrayUtil.shiftBackward(seq, rangeEnd - 1, " \n\t") + 1; + oneLine = true; } if (rangeStart >= rangeEnd) return false; FoldingGroup group = FoldingGroup.newGroup("lambda"); - final String prettySpace = oneLine ? " " : ""; - - foldElements.add( - new FoldingDescriptor(expression.getNode(), new TextRange(closureStart, rangeStart), group) { - @Override - public String getPlaceholderText() { - return lambdas + prettySpace; - } - }); - + foldElements.add(new NamedFoldingDescriptor(expression, closureStart, rangeStart, group, lambdas + prettySpace)); if (rbrace != null && rangeEnd + 1 < closureEnd) { - foldElements - .add(new FoldingDescriptor(rbrace.getNode(), new TextRange(rangeEnd, closureEnd), group) { - @Override - public String getPlaceholderText() { - return prettySpace + "}"; - } - }); + foldElements.add(new NamedFoldingDescriptor(rbrace, rangeEnd, closureEnd, group, prettySpace + "}")); } + addCodeBlockFolds(body, foldElements, processedComments, document, quick); } } @@ -841,6 +815,12 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem return isClosure; } + private boolean fitsRightMargin(PsiElement element, Document document, int foldingStart, int foldingEnd, int collapsedLength) { + final int beforeLength = foldingStart - document.getLineStartOffset(document.getLineNumber(foldingStart)); + final int afterLength = document.getLineEndOffset(document.getLineNumber(foldingEnd)) - foldingEnd; + return isBelowRightMargin(element.getProject(), beforeLength + collapsedLength + afterLength); + } + protected abstract boolean isBelowRightMargin (Project project, final int lineLength); @Override 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 3c4cd6c1cc2c..686fc6bfc5ac 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy @@ -512,6 +512,20 @@ class Test { checkAccessorFolding(regions[0], regions[1], fooClass.methods[0]) } + public void "test don't inline very long one-line methods"() { + configure """class Foo { + int someVeryVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVariable; + + // don't create folding that would exceed the right margin + int getSomeVeryVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVariable() { + return someVeryVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVariable; + } +}""" + def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } + assert regions.size() == 1 + assert regions[0].placeholderText == '{...}' + } + private def changeFoldRegions(Closure op) { myFixture.editor.foldingModel.runBatchFoldingOperationDoNotCollapseCaret(op) } diff --git a/platform/core-impl/src/com/intellij/lang/folding/NamedFoldingDescriptor.java b/platform/core-impl/src/com/intellij/lang/folding/NamedFoldingDescriptor.java new file mode 100644 index 000000000000..abf78e50061e --- /dev/null +++ b/platform/core-impl/src/com/intellij/lang/folding/NamedFoldingDescriptor.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.lang.folding; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.editor.FoldingGroup; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class NamedFoldingDescriptor extends FoldingDescriptor { + private final String myPlaceholderText; + + public NamedFoldingDescriptor(@NotNull PsiElement e, int start, int end, @Nullable FoldingGroup group, @NotNull String placeholderText) { + this(e.getNode(), new TextRange(start, end), group, placeholderText); + } + + public NamedFoldingDescriptor(@NotNull ASTNode node, int start, int end, @Nullable FoldingGroup group, @NotNull String placeholderText) { + this(node, new TextRange(start, end), group, placeholderText); + } + + public NamedFoldingDescriptor(@NotNull ASTNode node, + @NotNull final TextRange range, + @Nullable FoldingGroup group, + @NotNull String placeholderText) { + super(node, range, group); + myPlaceholderText = placeholderText; + } + + @Override + @NotNull + public String getPlaceholderText() { + return myPlaceholderText; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/folding/GroovyFoldingBuilder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/folding/GroovyFoldingBuilder.java index 604a13f5e2d5..25b2e48463ec 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/folding/GroovyFoldingBuilder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/folding/GroovyFoldingBuilder.java @@ -21,6 +21,7 @@ import com.intellij.codeInsight.folding.impl.JavaFoldingBuilderBase; import com.intellij.lang.ASTNode; import com.intellij.lang.folding.CustomFoldingBuilder; import com.intellij.lang.folding.FoldingDescriptor; +import com.intellij.lang.folding.NamedFoldingDescriptor; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.FoldingGroup; import com.intellij.openapi.project.DumbAware; @@ -124,8 +125,8 @@ public class GroovyFoldingBuilder extends CustomFoldingBuilder implements Groovy if (next != null && PsiImplUtil.isWhiteSpaceOrNls(next) && prev != null && PsiImplUtil.isWhiteSpaceOrNls(prev)) { final FoldingGroup group = FoldingGroup.newGroup("block_group"); - descriptors.add(new NamedFoldingDescriptor(psi.getNode(), lbrace.getTextRange().getStartOffset(), next.getTextRange().getEndOffset(), group, "{")); - descriptors.add(new NamedFoldingDescriptor(psi.getNode(), prev.getTextRange().getStartOffset(), rbrace.getTextRange().getEndOffset(), group, "}")); + descriptors.add(new NamedFoldingDescriptor(psi, lbrace.getTextRange().getStartOffset(), next.getTextRange().getEndOffset(), group, "{")); + descriptors.add(new NamedFoldingDescriptor(psi, prev.getTextRange().getStartOffset(), rbrace.getTextRange().getEndOffset(), group, "}")); return; } } @@ -191,24 +192,6 @@ public class GroovyFoldingBuilder extends CustomFoldingBuilder implements Groovy } } - private static class NamedFoldingDescriptor extends FoldingDescriptor { - private final String myPlaceholderText; - - private NamedFoldingDescriptor(@NotNull ASTNode node, int start, int end, @Nullable FoldingGroup group, @NotNull String placeholderText) { - this(node, new TextRange(start, end), group, placeholderText); - } - - private NamedFoldingDescriptor(@NotNull ASTNode node, @NotNull final TextRange range, @Nullable FoldingGroup group, @NotNull String placeholderText) { - super(node, range, group); - myPlaceholderText = placeholderText; - } - - @Override - public String getPlaceholderText() { - return myPlaceholderText; - } - } - private static void processImports(final List descriptors, GrImportStatement[] imports) { if (imports.length < 2) return;