diff --git a/java/java-tests/testData/psi/autodetect/continuationIndents_DoNotCount.java b/java/java-tests/testData/psi/autodetect/continuationIndents_DoNotCount.java new file mode 100644 index 000000000000..a2714c6652c6 --- /dev/null +++ b/java/java-tests/testData/psi/autodetect/continuationIndents_DoNotCount.java @@ -0,0 +1,537 @@ +/* + * Copyright 2000-2013 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.psi; + +import com.intellij.lang.FileASTNode; +import com.intellij.openapi.application.ex.PathManagerEx; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.impl.DebugUtil; +import com.intellij.psi.impl.source.JavaLightStubBuilder; +import com.intellij.psi.stubs.StubElement; +import com.intellij.testFramework.LightIdeaTestCase; +import com.intellij.testFramework.PlatformTestUtil; +import com.intellij.util.ThrowableRunnable; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.security.SecureRandom; + +public class Test { + private static final StubBuilder NEW_BUILDER = new JavaLightStubBuilder(); + + @Override + public void setUp() throws Exception { + super.setUp(); + doTest("@interface A { int i() default 42; }\n class C { void m(int p) throws E { } }", null); // warm up + LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.HIGHEST); + } + + public void testEmpty() { + doTest("/**/", + "PsiJavaFileStub []\n" + + " IMPORT_LIST:PsiImportListStub\n"); + } + + public void testFileHeader() { + doTest("package p;\n" + + "import a/*comment to skip*/.b;\n" + + "import static c.d.*;\n" + + "import static java.util.Arrays.sort;", + + "PsiJavaFileStub [p]\n" + + " IMPORT_LIST:PsiImportListStub\n" + + " IMPORT_STATEMENT:PsiImportStatementStub[a.b]\n" + + " IMPORT_STATIC_STATEMENT:PsiImportStatementStub[static c.d.*]\n" + + " IMPORT_STATIC_STATEMENT:PsiImportStatementStub[static java.util.Arrays.sort]\n"); + } + + public void testClassDeclaration() { + doTest("package p;" + + "class A implements I, J { }\n" + + "class B extends a/*skip*/.A { class I { } }\n" + + "@java.lang.Deprecated interface I { }\n" + + "/** @deprecated just don't use */ @interface N { }", + + "PsiJavaFileStub [p]\n" + + " IMPORT_LIST:PsiImportListStub\n" + + " CLASS:PsiClassStub[name=A fqn=p.A]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:I, J]\n" + + " CLASS:PsiClassStub[name=B fqn=p.B]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " TYPE_PARAMETER:PsiTypeParameter[K]\n" + + " EXTENDS_BOUND_LIST:PsiRefListStub[EXTENDS_BOUNDS_LIST:]\n" + + " TYPE_PARAMETER:PsiTypeParameter[V]\n" + + " EXTENDS_BOUND_LIST:PsiRefListStub[EXTENDS_BOUNDS_LIST:X]\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:a/*skip*/.A]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " CLASS:PsiClassStub[name=I fqn=p.B.I]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " CLASS:PsiClassStub[interface deprecatedA name=I fqn=p.I]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=5120]\n" + + " ANNOTATION:PsiAnnotationStub[@java.lang.Deprecated]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " CLASS:PsiClassStub[interface annotation deprecated name=N fqn=p.N]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=5120]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n"); + } + + public void testMethods() { + doTest("public @interface Anno {\n" + + " int i() default 42;\n" + + " public static String s();\n" + + "}\n" + + "private class C {\n" + + " public C() throws Exception { }\n" + + " public abstract void m(final int i, int[] a1, int a2[], int[] a3[]);\n" + + " private static int v2a(int... v) [] { return v; }\n" + + "}\n" + + "interface I {\n" + + " void m1();\n" + + " default void m2() { }\n" + + "}", + + "PsiJavaFileStub []\n" + + " IMPORT_LIST:PsiImportListStub\n" + + " CLASS:PsiClassStub[interface annotation name=Anno fqn=Anno]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=1025]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " ANNOTATION_METHOD:PsiMethodStub[annotation i:int default=42]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=1025]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n" + + " ANNOTATION_METHOD:PsiMethodStub[annotation s:String]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=1033]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n" + + " CLASS:PsiClassStub[name=C fqn=C]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=2]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " METHOD:PsiMethodStub[cons C:null]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=1]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:Exception]\n" + + " METHOD:PsiMethodStub[m:void]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=1025]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " PARAMETER:PsiParameterStub[i:int]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4112]\n" + + " PARAMETER:PsiParameterStub[a1:int[]]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " PARAMETER:PsiParameterStub[a2:int[]]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " PARAMETER:PsiParameterStub[a3:int[][]]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n" + + " METHOD:PsiMethodStub[varargs v2a:int[]]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=10]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " PARAMETER:PsiParameterStub[v:int...]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n" + + " CLASS:PsiClassStub[interface name=I fqn=I]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=5120]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " METHOD:PsiMethodStub[m1:void]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=1025]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n" + + " METHOD:PsiMethodStub[m2:void]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=513]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n"); + } + + public void testFields() { + doTest("static class C {\n" + + " strictfp float f;\n" + + " int j[] = {0}, k;\n" + + " static String s = \"-\";\n" + + "}\n" + + "public class D {\n" + + " private volatile boolean b;\n" + + " public final double x;\n" + + "}", + + "PsiJavaFileStub []\n" + + " IMPORT_LIST:PsiImportListStub\n" + + " CLASS:PsiClassStub[name=C fqn=C]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4104]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " FIELD:PsiFieldStub[f:float]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=6144]\n" + + " FIELD:PsiFieldStub[j:int[]={0}]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " FIELD:PsiFieldStub[k:int]\n" + + " FIELD:PsiFieldStub[s:String=\"-\"]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4104]\n" + + " CLASS:PsiClassStub[name=D fqn=D]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=1]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " FIELD:PsiFieldStub[b:boolean]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=66]\n" + + " FIELD:PsiFieldStub[x:double]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=17]\n"); + } + + public void testAnonymousClasses() { + doTest("class C { {\n" + + " new O.P() { };\n" + + " X.new Y() { };\n" + + " f(p -> new R() { });\n" + + "} }", + + "PsiJavaFileStub []\n" + + " IMPORT_LIST:PsiImportListStub\n" + + " CLASS:PsiClassStub[name=C fqn=C]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " CLASS_INITIALIZER:PsiClassInitializerStub\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " ANONYMOUS_CLASS:PsiClassStub[anonymous name=null fqn=null baseref=O.P]\n" + + " ANONYMOUS_CLASS:PsiClassStub[anonymous name=null fqn=null baseref=Y inqualifnew]\n" + + " ANONYMOUS_CLASS:PsiClassStub[anonymous name=null fqn=null baseref=R]\n"); + } + + public void testEnums() { + doTest("enum E {\n" + + " E1() { };\n" + + " abstract void m();\n" + + "}\n" + + "public enum U { U1, U2 }", + + "PsiJavaFileStub []\n" + + " IMPORT_LIST:PsiImportListStub\n" + + " CLASS:PsiClassStub[enum name=E fqn=E]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=5120]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " ENUM_CONSTANT:PsiFieldStub[enumconst E1:E]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=25]\n" + + " ENUM_CONSTANT_INITIALIZER:PsiClassStub[anonymous enumInit name=null fqn=null baseref=E]\n" + + " METHOD:PsiMethodStub[m:void]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=5120]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n" + + " CLASS:PsiClassStub[enum name=U fqn=U]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=17]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " ENUM_CONSTANT:PsiFieldStub[enumconst U1:U]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=25]\n" + + " ENUM_CONSTANT:PsiFieldStub[enumconst U2:U]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=25]\n"); + } + + public void testLocalVariables() { + doTest("class C {\n" + + " void m() {\n" + + " int local = 0;\n" + + " Object r = new Runnable() {\n" + + " public void run() { }\n" + + " };\n" + + " for (int loop = 0; loop < 10; loop++) ;\n" + + " try (Resource r = new Resource()) { }\n" + + " try (Resource r = new Resource() {\n" + + " @Override public void close() { }\n" + + " }) { }\n" + + " }\n" + + "}", + + "PsiJavaFileStub []\n" + + " IMPORT_LIST:PsiImportListStub\n" + + " CLASS:PsiClassStub[name=C fqn=C]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " METHOD:PsiMethodStub[m:void]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n" + + " ANONYMOUS_CLASS:PsiClassStub[anonymous name=null fqn=null baseref=Runnable]\n" + + " METHOD:PsiMethodStub[run:void]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=1]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n" + + " ANONYMOUS_CLASS:PsiClassStub[anonymous name=null fqn=null baseref=Resource]\n" + + " METHOD:PsiMethodStub[close:void]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=1]\n" + + " ANNOTATION:PsiAnnotationStub[@Override]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n"); + } + + public void testNonListParameters() { + doTest("class C {\n" + + " {\n" + + " for (int i : arr) ;\n" + + " for (String s : new Iterable() {\n" + + " @Override public Iterator iterator() { return null; }\n" + + " }) ;\n" + + " try { }\n" + + " catch (Throwable t) { }\n" + + " catch (E1|E2 e) { }\n" + + " }\n" + + "}", + + "PsiJavaFileStub []\n" + + " IMPORT_LIST:PsiImportListStub\n" + + " CLASS:PsiClassStub[name=C fqn=C]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " CLASS_INITIALIZER:PsiClassInitializerStub\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " ANONYMOUS_CLASS:PsiClassStub[anonymous name=null fqn=null baseref=Iterable]\n" + + " METHOD:PsiMethodStub[iterator:Iterator]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=1]\n" + + " ANNOTATION:PsiAnnotationStub[@Override]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n"); + } + + public void testAnnotations() { + doTest("@Deprecated\n" + + "@SuppressWarnings(\"UnusedDeclaration\")\n" + + "class Foo { }", + + "PsiJavaFileStub []\n" + + " IMPORT_LIST:PsiImportListStub\n" + + " CLASS:PsiClassStub[deprecatedA name=Foo fqn=Foo]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " ANNOTATION:PsiAnnotationStub[@Deprecated]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@SuppressWarnings(\"UnusedDeclaration\")]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " NAME_VALUE_PAIR:PsiNameValuePairStubImpl\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n"); + } + + public void testTypeAnnotations() { + doTest("import j.u.@A C;\n" + + "import @A j.u.D;\n" + + "\n" + + "class C<@A T extends @A C> implements @A I<@A T> {\n" + + " @TA T<@A T1, @A ? extends @A T2> f;\n" + + " @TA T m(/*@A C this,*/ @TA int p) throws @A E {\n" + + " o.<@A1 C>m();\n" + + " new @A2 C();\n" + + " C.@A3 B v = (@A4 C)v.new @A5 C();\n" + + " m(@A6 C::m);\n" + + " @A7 T @A8[] @A9[] a = new @A7 T @A8[0] @A9[0];\n" + + " }\n" + + " int @A [] v() @A [] { }\n" + + "}", + + "PsiJavaFileStub []\n" + + " IMPORT_LIST:PsiImportListStub\n" + + " IMPORT_STATEMENT:PsiImportStatementStub[j.u.C]\n" + + " IMPORT_STATEMENT:PsiImportStatementStub[j.u.D]\n" + + " CLASS:PsiClassStub[name=C fqn=C]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " TYPE_PARAMETER:PsiTypeParameter[T]\n" + + " ANNOTATION:PsiAnnotationStub[@A]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " EXTENDS_BOUND_LIST:PsiRefListStub[EXTENDS_BOUNDS_LIST:@A C]\n" + + " ANNOTATION:PsiAnnotationStub[@A]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:@A I<@A T>]\n" + + " ANNOTATION:PsiAnnotationStub[@A]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " FIELD:PsiFieldStub[f:T<@A T1, @A ? extends @A T2>]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " ANNOTATION:PsiAnnotationStub[@TA]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " METHOD:PsiMethodStub[m:T]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " ANNOTATION:PsiAnnotationStub[@TA]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " PARAMETER:PsiParameterStub[p:int]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " ANNOTATION:PsiAnnotationStub[@TA]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:@A E]\n" + + " ANNOTATION:PsiAnnotationStub[@A]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A1]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A2]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A3]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A4]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A5]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A6]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A7]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A8]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A9]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A7]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A8]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " ANNOTATION:PsiAnnotationStub[@A9]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " METHOD:PsiMethodStub[v:int[][]]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " ANNOTATION:PsiAnnotationStub[@A]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " PARAMETER_LIST:PsiParameterListStub\n" + + " ANNOTATION:PsiAnnotationStub[@A]\n" + + " ANNOTATION_PARAMETER_LIST:PsiAnnotationParameterListStubImpl\n" + + " THROWS_LIST:PsiRefListStub[THROWS_LIST:]\n"); + } + + public void testSOEProof() { + final StringBuilder sb = new StringBuilder(); + final SecureRandom random = new SecureRandom(); + sb.append("class SOE_test {\n BigInteger BIG = new BigInteger(\n"); + int i; + for (i = 0; i < 100000; i++) { + sb.append(" \"").append(Math.abs(random.nextInt())).append("\" +\n"); + } + sb.append(" \"\");\n}"); + + final PsiJavaFile file = (PsiJavaFile)createLightFile("SOE_test.java", sb.toString()); + long t = System.currentTimeMillis(); + final StubElement tree = NEW_BUILDER.buildStubTree(file); + t = System.currentTimeMillis() - t; + assertEquals("PsiJavaFileStub []\n" + + " IMPORT_LIST:PsiImportListStub\n" + + " CLASS:PsiClassStub[name=SOE_test fqn=SOE_test]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" + + " TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" + + " EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" + + " IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" + + " FIELD:PsiFieldStub[BIG:BigInteger=;INITIALIZER_NOT_STORED;]\n" + + " MODIFIER_LIST:PsiModifierListStub[mask=4096]\n", + DebugUtil.stubTreeToString(tree)); + System.out.println("SOE depth=" + i + ", time=" + t + "ms"); + } + + public void testPerformance() throws Exception { + final String path = PathManagerEx.getTestDataPath() + "/psi/stub/StubPerformanceTest.java"; + String text = FileUtil.loadFile(new File(path)); + final PsiJavaFile file = (PsiJavaFile)createLightFile("test.java", text); + + PlatformTestUtil.startPerformanceTest("Source file size: " + text.length(), 2000, new ThrowableRunnable() { + @Override + public void run() throws Exception { + NEW_BUILDER.buildStubTree(file); + } + }).cpuBound().assertTiming(); + } + + private static void doTest(@NonNls final String source, @NonNls @Nullable final String tree) { + final PsiJavaFile file = (PsiJavaFile)createLightFile("test.java", source); + final FileASTNode fileNode = file.getNode(); + assertNotNull(fileNode); + assertFalse(fileNode.isParsed()); + + long t1 = System.nanoTime(); + final StubElement lighterTree = NEW_BUILDER.buildStubTree(file); + t1 = Math.max((System.nanoTime() - t1)/1000, 1); + assertFalse(fileNode.isParsed()); + + file.getNode().getChildren(null); // force switch to AST + + long t2 = System.nanoTime(); + final StubElement lighterTree2 = NEW_BUILDER.buildStubTree(file); // build over AST + t2 = Math.max((System.nanoTime() - t2)/1000, 1); + + file.accept(new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + assert !(element instanceof PsiErrorElement) : element; + super.visitElement(element); + } + }); + + final String lightStr = DebugUtil.stubTreeToString(lighterTree); + final String lightStr2 = DebugUtil.stubTreeToString(lighterTree2); + if (tree != null) { + System.out.println("light=" + t1 + "mks, heavy=" + t2 + "mks"); + if (!tree.isEmpty()) { + assertEquals("light tree differs", tree, lightStr); + assertEquals("light tree (2nd) differs", tree, lightStr2); + } + } + } +} diff --git a/java/java-tests/testData/psi/autodetect/continuationIndents_InMethodParameters_DoNotCount.java b/java/java-tests/testData/psi/autodetect/continuationIndents_InMethodParameters_DoNotCount.java new file mode 100644 index 000000000000..1a42f6d92b00 --- /dev/null +++ b/java/java-tests/testData/psi/autodetect/continuationIndents_InMethodParameters_DoNotCount.java @@ -0,0 +1,301 @@ +import java.util.Arrays; +import java.util.List; + +public final class TimeContentItemHelper { + + public static List TIME_PERIOD_1_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_PERIOD1_1, + TimePeriods.TIME_PERIOD1_2, + TimePeriods.TIME_PERIOD1_3, + TimePeriods.TIME_PERIOD1_4, + TimePeriods.TIME_PERIOD1_5, + TimePeriods.TIME_PERIOD1_6 + ); + + public static List TIME_PERIOD_2_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_PERIOD2_1, + TimePeriods.TIME_PERIOD2_2, + TimePeriods.TIME_PERIOD2_3, + TimePeriods.TIME_PERIOD2_4, + TimePeriods.TIME_PERIOD2_5, + TimePeriods.TIME_PERIOD2_6 + ); + + public static List TIME_PERIOD_3_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_PERIOD3_1, + TimePeriods.TIME_PERIOD3_2, + TimePeriods.TIME_PERIOD3_3, + TimePeriods.TIME_PERIOD3_4, + TimePeriods.TIME_PERIOD3_5, + TimePeriods.TIME_PERIOD3_6 + ); + + public static List TIME_PERIOD_4_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_PERIOD4_1, + TimePeriods.TIME_PERIOD4_2, + TimePeriods.TIME_PERIOD4_3, + TimePeriods.TIME_PERIOD4_4, + TimePeriods.TIME_PERIOD4_5, + TimePeriods.TIME_PERIOD4_6 + ); + + public static List TIME_PERIOD_5_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_PERIOD5_1, + TimePeriods.TIME_PERIOD5_2, + TimePeriods.TIME_PERIOD5_3, + TimePeriods.TIME_PERIOD5_4, + TimePeriods.TIME_PERIOD5_5, + TimePeriods.TIME_PERIOD5_6 + ); + + public static List TIME_PERIOD_6_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_PERIOD6_1, + TimePeriods.TIME_PERIOD6_2, + TimePeriods.TIME_PERIOD6_3, + TimePeriods.TIME_PERIOD6_4, + TimePeriods.TIME_PERIOD6_5, + TimePeriods.TIME_PERIOD6_6 + ); + + public static List> TIME_PERIOD_CONTENT_ITEM_KEY_MATRIX = Arrays.asList( + TIME_PERIOD_1_CONTENT_ITEM_KEYS, + TIME_PERIOD_2_CONTENT_ITEM_KEYS, + TIME_PERIOD_3_CONTENT_ITEM_KEYS, + TIME_PERIOD_4_CONTENT_ITEM_KEYS, + TIME_PERIOD_5_CONTENT_ITEM_KEYS, + TIME_PERIOD_6_CONTENT_ITEM_KEYS + ); + + public static List TIME_AVERAGE_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_AVERAGE1, + TimePeriods.TIME_AVERAGE2, + TimePeriods.TIME_AVERAGE3, + TimePeriods.TIME_AVERAGE4, + TimePeriods.TIME_AVERAGE5, + TimePeriods.TIME_AVERAGE6 + ); + + public static List TIME_ROOM_DESCRIPTION_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_AVERAGE_DESCRIPTION1, + TimePeriods.TIME_AVERAGE_DESCRIPTION2, + TimePeriods.TIME_AVERAGE_DESCRIPTION3, + TimePeriods.TIME_AVERAGE_DESCRIPTION4, + TimePeriods.TIME_AVERAGE_DESCRIPTION5, + TimePeriods.TIME_AVERAGE_DESCRIPTION6 + ); + + public static List TIME_1_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_AVERAGE_PRICE1_1, + TimePeriods.TIME_AVERAGE_PRICE1_2, + TimePeriods.TIME_AVERAGE_PRICE1_3, + TimePeriods.TIME_AVERAGE_PRICE1_4, + TimePeriods.TIME_AVERAGE_PRICE1_5, + TimePeriods.TIME_AVERAGE_PRICE1_6 + ); + + public static List TIME_2_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_AVERAGE_PRICE2_1, + TimePeriods.TIME_AVERAGE_PRICE2_2, + TimePeriods.TIME_AVERAGE_PRICE2_3, + TimePeriods.TIME_AVERAGE_PRICE2_4, + TimePeriods.TIME_AVERAGE_PRICE2_5, + TimePeriods.TIME_AVERAGE_PRICE2_6 + ); + + public static List TIME_3_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_AVERAGE_PRICE3_1, + TimePeriods.TIME_AVERAGE_PRICE3_2, + TimePeriods.TIME_AVERAGE_PRICE3_3, + TimePeriods.TIME_AVERAGE_PRICE3_4, + TimePeriods.TIME_AVERAGE_PRICE3_5, + TimePeriods.TIME_AVERAGE_PRICE3_6 + ); + + public static List TIME_4_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_AVERAGE_PRICE4_1, + TimePeriods.TIME_AVERAGE_PRICE4_2, + TimePeriods.TIME_AVERAGE_PRICE4_3, + TimePeriods.TIME_AVERAGE_PRICE4_4, + TimePeriods.TIME_AVERAGE_PRICE4_5, + TimePeriods.TIME_AVERAGE_PRICE4_6 + ); + + public static List TIME_5_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_AVERAGE_PRICE5_1, + TimePeriods.TIME_AVERAGE_PRICE5_2, + TimePeriods.TIME_AVERAGE_PRICE5_3, + TimePeriods.TIME_AVERAGE_PRICE5_4, + TimePeriods.TIME_AVERAGE_PRICE5_5, + TimePeriods.TIME_AVERAGE_PRICE5_6 + ); + + public static List TIME_6_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_AVERAGE_PRICE6_1, + TimePeriods.TIME_AVERAGE_PRICE6_2, + TimePeriods.TIME_AVERAGE_PRICE6_3, + TimePeriods.TIME_AVERAGE_PRICE6_4, + TimePeriods.TIME_AVERAGE_PRICE6_5, + TimePeriods.TIME_AVERAGE_PRICE6_6 + ); + + public static List> TIME_CONTENT_ITEM_KEY_MATRIX = Arrays.asList( + TIME_1_CONTENT_ITEM_KEYS, + TIME_2_CONTENT_ITEM_KEYS, + TIME_3_CONTENT_ITEM_KEYS, + TIME_4_CONTENT_ITEM_KEYS, + TIME_5_CONTENT_ITEM_KEYS, + TIME_6_CONTENT_ITEM_KEYS + ); + + public static List TIME_NOTE_LABELS_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_NOTE_LABEL_1, + TimePeriods.TIME_NOTE_LABEL_2, + TimePeriods.TIME_NOTE_LABEL_3, + TimePeriods.TIME_NOTE_LABEL_4, + TimePeriods.TIME_NOTE_LABEL_5, + TimePeriods.TIME_NOTE_LABEL_6, + TimePeriods.TIME_NOTE_LABEL_7, + TimePeriods.TIME_NOTE_LABEL_8, + TimePeriods.TIME_NOTE_LABEL_9, + TimePeriods.TIME_NOTE_LABEL_10 + ); + + public static List TIME_NOTES_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIME_NOTE_1, + TimePeriods.TIME_NOTE_2, + TimePeriods.TIME_NOTE_3, + TimePeriods.TIME_NOTE_4, + TimePeriods.TIME_NOTE_5, + TimePeriods.TIME_NOTE_6, + TimePeriods.TIME_NOTE_7, + TimePeriods.TIME_NOTE_8, + TimePeriods.TIME_NOTE_9, + TimePeriods.TIME_NOTE_10 + ); + + public static List TIME_CONTENT_ITEM_KEYS = Arrays.asList( + TimePeriods.TIMES_ENABLED, + TimePeriods.TIMES_COUNT_OF_TIMES, + TimePeriods.TIMES_COUNT_OF_TIME_PERIODS, + TimePeriods.TIMES_COUNT_OF_AVERAGES, + TimePeriods.TIME_NAME1, + TimePeriods.TIME_NAME2, + TimePeriods.TIME_NAME3, + TimePeriods.TIME_NAME4, + TimePeriods.TIME_NAME5, + TimePeriods.TIME_NAME6, + TimePeriods.TIME_PERIOD1_1, + TimePeriods.TIME_PERIOD1_2, + TimePeriods.TIME_PERIOD1_3, + TimePeriods.TIME_PERIOD1_4, + TimePeriods.TIME_PERIOD1_5, + TimePeriods.TIME_PERIOD1_6, + TimePeriods.TIME_PERIOD2_1, + TimePeriods.TIME_PERIOD2_2, + TimePeriods.TIME_PERIOD2_3, + TimePeriods.TIME_PERIOD2_4, + TimePeriods.TIME_PERIOD2_5, + TimePeriods.TIME_PERIOD2_6, + TimePeriods.TIME_PERIOD3_1, + TimePeriods.TIME_PERIOD3_2, + TimePeriods.TIME_PERIOD3_3, + TimePeriods.TIME_PERIOD3_4, + TimePeriods.TIME_PERIOD3_5, + TimePeriods.TIME_PERIOD3_6, + TimePeriods.TIME_PERIOD4_1, + TimePeriods.TIME_PERIOD4_2, + TimePeriods.TIME_PERIOD4_3, + TimePeriods.TIME_PERIOD4_4, + TimePeriods.TIME_PERIOD4_5, + TimePeriods.TIME_PERIOD4_6, + TimePeriods.TIME_PERIOD5_1, + TimePeriods.TIME_PERIOD5_2, + TimePeriods.TIME_PERIOD5_3, + TimePeriods.TIME_PERIOD5_4, + TimePeriods.TIME_PERIOD5_5, + TimePeriods.TIME_PERIOD5_6, + TimePeriods.TIME_PERIOD6_1, + TimePeriods.TIME_PERIOD6_2, + TimePeriods.TIME_PERIOD6_3, + TimePeriods.TIME_PERIOD6_4, + TimePeriods.TIME_PERIOD6_5, + TimePeriods.TIME_PERIOD6_6, + TimePeriods.TIME_AVERAGE1, + TimePeriods.TIME_AVERAGE2, + TimePeriods.TIME_AVERAGE3, + TimePeriods.TIME_AVERAGE4, + TimePeriods.TIME_AVERAGE5, + TimePeriods.TIME_AVERAGE6, + TimePeriods.TIME_AVERAGE_PRICE1_1, + TimePeriods.TIME_AVERAGE_PRICE1_2, + TimePeriods.TIME_AVERAGE_PRICE1_3, + TimePeriods.TIME_AVERAGE_PRICE1_4, + TimePeriods.TIME_AVERAGE_PRICE1_5, + TimePeriods.TIME_AVERAGE_PRICE1_6, + TimePeriods.TIME_AVERAGE_PRICE2_1, + TimePeriods.TIME_AVERAGE_PRICE2_2, + TimePeriods.TIME_AVERAGE_PRICE2_3, + TimePeriods.TIME_AVERAGE_PRICE2_4, + TimePeriods.TIME_AVERAGE_PRICE2_5, + TimePeriods.TIME_AVERAGE_PRICE2_6, + TimePeriods.TIME_AVERAGE_PRICE3_1, + TimePeriods.TIME_AVERAGE_PRICE3_2, + TimePeriods.TIME_AVERAGE_PRICE3_3, + TimePeriods.TIME_AVERAGE_PRICE3_4, + TimePeriods.TIME_AVERAGE_PRICE3_5, + TimePeriods.TIME_AVERAGE_PRICE3_6, + TimePeriods.TIME_AVERAGE_PRICE4_1, + TimePeriods.TIME_AVERAGE_PRICE4_2, + TimePeriods.TIME_AVERAGE_PRICE4_3, + TimePeriods.TIME_AVERAGE_PRICE4_4, + TimePeriods.TIME_AVERAGE_PRICE4_5, + TimePeriods.TIME_AVERAGE_PRICE4_6, + TimePeriods.TIME_AVERAGE_PRICE5_1, + TimePeriods.TIME_AVERAGE_PRICE5_2, + TimePeriods.TIME_AVERAGE_PRICE5_3, + TimePeriods.TIME_AVERAGE_PRICE5_4, + TimePeriods.TIME_AVERAGE_PRICE5_5, + TimePeriods.TIME_AVERAGE_PRICE5_6, + TimePeriods.TIME_AVERAGE_PRICE6_1, + TimePeriods.TIME_AVERAGE_PRICE6_2, + TimePeriods.TIME_AVERAGE_PRICE6_3, + TimePeriods.TIME_AVERAGE_PRICE6_4, + TimePeriods.TIME_AVERAGE_PRICE6_5, + TimePeriods.TIME_AVERAGE_PRICE6_6, + TimePeriods.TIME_AVERAGE_DESCRIPTION1, + TimePeriods.TIME_AVERAGE_DESCRIPTION2, + TimePeriods.TIME_AVERAGE_DESCRIPTION3, + TimePeriods.TIME_AVERAGE_DESCRIPTION4, + TimePeriods.TIME_AVERAGE_DESCRIPTION5, + TimePeriods.TIME_AVERAGE_DESCRIPTION6, + TimePeriods.TIME_NOTE_LABEL_1, + TimePeriods.TIME_NOTE_LABEL_2, + TimePeriods.TIME_NOTE_LABEL_3, + TimePeriods.TIME_NOTE_LABEL_4, + TimePeriods.TIME_NOTE_LABEL_5, + TimePeriods.TIME_NOTE_LABEL_6, + TimePeriods.TIME_NOTE_LABEL_7, + TimePeriods.TIME_NOTE_LABEL_8, + TimePeriods.TIME_NOTE_LABEL_9, + TimePeriods.TIME_NOTE_LABEL_10, + TimePeriods.TIME_NOTE_1, + TimePeriods.TIME_NOTE_2, + TimePeriods.TIME_NOTE_3, + TimePeriods.TIME_NOTE_4, + TimePeriods.TIME_NOTE_5, + TimePeriods.TIME_NOTE_6, + TimePeriods.TIME_NOTE_7, + TimePeriods.TIME_NOTE_8, + TimePeriods.TIME_NOTE_9, + TimePeriods.TIME_NOTE_10 + ); + + public static boolean check(TimePeriods key) { + int keyI = key.getIntValue(); + if (keyI < 0) { + return false; + } else { + return true; + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/psi/autodetect/JavaAutoDetectIndentTest.java b/java/java-tests/testSrc/com/intellij/psi/autodetect/JavaAutoDetectIndentTest.java index e3600a290bea..4a8214e2c5cc 100644 --- a/java/java-tests/testSrc/com/intellij/psi/autodetect/JavaAutoDetectIndentTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/autodetect/JavaAutoDetectIndentTest.java @@ -36,4 +36,15 @@ public class JavaAutoDetectIndentTest extends AbstractIndentAutoDetectionTest { public void testNotIndentedComment() { doTestIndentSize(3); } + + public void testContinuationIndents_DoNotCount() { + doTestIndentSize(4); + //actual indent is 2, and 4 is the default value + //todo: do not count brackets in string literals + } + + public void testContinuationIndents_InMethodParameters_DoNotCount() { + doTestIndentSize(4); + } + } diff --git a/platform/diff-api/src/com/intellij/diff/DiffContentFactory.java b/platform/diff-api/src/com/intellij/diff/DiffContentFactory.java index ffe4824fed78..98e5745c2b8d 100644 --- a/platform/diff-api/src/com/intellij/diff/DiffContentFactory.java +++ b/platform/diff-api/src/com/intellij/diff/DiffContentFactory.java @@ -52,6 +52,9 @@ public abstract class DiffContentFactory { @NotNull public abstract DocumentContent create(@Nullable Project project, @NotNull Document document); + @NotNull + public abstract DocumentContent create(@Nullable Project project, @NotNull Document document, @Nullable FileType fileType); + @NotNull public abstract DocumentContent create(@Nullable Project project, @NotNull Document document, @Nullable VirtualFile file); diff --git a/platform/diff-impl/src/com/intellij/diff/DiffContentFactoryImpl.java b/platform/diff-impl/src/com/intellij/diff/DiffContentFactoryImpl.java index f342f7a378d7..8acca83b1b90 100644 --- a/platform/diff-impl/src/com/intellij/diff/DiffContentFactoryImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/DiffContentFactoryImpl.java @@ -47,7 +47,7 @@ public class DiffContentFactoryImpl extends DiffContentFactory { @NotNull public static DiffContentFactoryImpl getInstanceImpl() { - return (DiffContentFactoryImpl)ServiceManager.getService(DiffContentFactory.class); + return (DiffContentFactoryImpl)DiffContentFactory.getInstance(); } @Override @@ -77,7 +77,14 @@ public class DiffContentFactoryImpl extends DiffContentFactory { @Override @NotNull public DocumentContent create(@Nullable Project project, @NotNull Document document) { + return create(project, document, (FileType)null); + } + + @Override + @NotNull + public DocumentContent create(@Nullable Project project, @NotNull Document document, @Nullable FileType fileType) { VirtualFile file = FileDocumentManager.getInstance().getFile(document); + if (file == null) return new DocumentContentImpl(document, fileType, null, null, null); return create(project, document, file); } diff --git a/platform/diff-impl/src/com/intellij/diff/DiffContextEx.java b/platform/diff-impl/src/com/intellij/diff/DiffContextEx.java index 026fa3201f0a..2e6550d7b9f0 100644 --- a/platform/diff-impl/src/com/intellij/diff/DiffContextEx.java +++ b/platform/diff-impl/src/com/intellij/diff/DiffContextEx.java @@ -16,5 +16,10 @@ package com.intellij.diff; public abstract class DiffContextEx extends DiffContext { + /* + * Reopen current DiffRequest. + * perform the same procedure as on switching between DiffRequests or between DiffViewers. + * this can be used, if some change in request or settings was made, and we need to reopen DiffViewer to apply them. + */ public abstract void reloadDiffRequest(); } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java index 560728a6f6a1..1474e012cda2 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java @@ -17,9 +17,12 @@ package com.intellij.diff.actions; import com.intellij.diff.DiffContentFactory; import com.intellij.diff.DiffRequestFactory; +import com.intellij.diff.contents.DiffContent; import com.intellij.diff.contents.DocumentContent; +import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.requests.DiffRequest; import com.intellij.diff.requests.SimpleDiffRequest; +import com.intellij.diff.tools.util.DiffDataKeys; import com.intellij.diff.util.DiffUserDataKeys; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; @@ -28,6 +31,8 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.UnknownFileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; @@ -49,6 +54,22 @@ public class CompareClipboardWithSelectionAction extends BaseShowDiffAction { return null; } + @Nullable + private static FileType getEditorFileType(@NotNull AnActionEvent e) { + DiffContent content = e.getData(DiffDataKeys.CURRENT_CONTENT); + if (content != null && content.getContentType() != null) return content.getContentType(); + + DiffRequest request = e.getData(DiffDataKeys.DIFF_REQUEST); + if (request != null && request instanceof ContentDiffRequest) { + for (DiffContent diffContent : ((ContentDiffRequest)request).getContents()) { + FileType type = diffContent.getContentType(); + if (type != null && type != UnknownFileType.INSTANCE) return type; + } + } + + return null; + } + @Override protected boolean isAvailable(@NotNull AnActionEvent e) { Editor editor = getEditor(e); @@ -60,9 +81,10 @@ public class CompareClipboardWithSelectionAction extends BaseShowDiffAction { protected DiffRequest getDiffRequest(@NotNull AnActionEvent e) { Project project = e.getRequiredData(CommonDataKeys.PROJECT); Editor editor = getEditor(e); + FileType editorFileType = getEditorFileType(e); assert editor != null; - DocumentContent content2 = createContent(project, editor); + DocumentContent content2 = createContent(project, editor, editorFileType); DocumentContent content1 = DiffContentFactory.getInstance().createClipboardContent(content2); String title1 = DiffBundle.message("diff.content.clipboard.content.title"); @@ -78,8 +100,8 @@ public class CompareClipboardWithSelectionAction extends BaseShowDiffAction { } @NotNull - private static DocumentContent createContent(@NotNull Project project, @NotNull Editor editor) { - DocumentContent content = DiffContentFactory.getInstance().create(project, editor.getDocument()); + private static DocumentContent createContent(@NotNull Project project, @NotNull Editor editor, @Nullable FileType type) { + DocumentContent content = DiffContentFactory.getInstance().create(project, editor.getDocument(), type); SelectionModel selectionModel = editor.getSelectionModel(); if (selectionModel.hasSelection()) { diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/FocusOppositePaneAction.java b/platform/diff-impl/src/com/intellij/diff/actions/impl/FocusOppositePaneAction.java index 84e99cc783b9..3415e681255f 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/impl/FocusOppositePaneAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/FocusOppositePaneAction.java @@ -15,18 +15,23 @@ */ package com.intellij.diff.actions.impl; -import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CustomShortcutSet; -import com.intellij.openapi.actionSystem.ShortcutSet; +import com.intellij.openapi.actionSystem.EmptyAction; import com.intellij.openapi.project.DumbAware; import org.jetbrains.annotations.NotNull; import javax.swing.*; public class FocusOppositePaneAction extends AnAction implements DumbAware { + protected final boolean myScrollToPosition; + public FocusOppositePaneAction() { + this(false); + } + + public FocusOppositePaneAction(boolean scrollToPosition) { + myScrollToPosition = scrollToPosition; setEnabledInModalContext(true); } @@ -35,8 +40,8 @@ public class FocusOppositePaneAction extends AnAction implements DumbAware { throw new UnsupportedOperationException(); } - public void setupAction(@NotNull JComponent component, @NotNull Disposable disposable) { - ShortcutSet shortcutSet = CustomShortcutSet.fromString("control TAB"); // TODO: allow to change shortcut - registerCustomShortcutSet(shortcutSet, component, disposable); + public void setupAction(@NotNull JComponent component) { + String action = myScrollToPosition ? "Diff.FocusOppositePaneAndScroll" : "Diff.FocusOppositePane"; + EmptyAction.setupAction(this, action, component); } } \ No newline at end of file diff --git a/platform/diff-impl/src/com/intellij/diff/contents/FileAwareDocumentContent.java b/platform/diff-impl/src/com/intellij/diff/contents/FileAwareDocumentContent.java index 463e2d327237..2a8b693a9755 100644 --- a/platform/diff-impl/src/com/intellij/diff/contents/FileAwareDocumentContent.java +++ b/platform/diff-impl/src/com/intellij/diff/contents/FileAwareDocumentContent.java @@ -11,7 +11,6 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vfs.CharsetToolkit; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.LineSeparator; import org.jetbrains.annotations.NotNull; @@ -21,22 +20,22 @@ import java.nio.charset.Charset; public class FileAwareDocumentContent extends DocumentContentImpl { @Nullable private final Project myProject; - @Nullable private final VirtualFile myLocalFile; + @Nullable private final VirtualFile myHighlightFile; public FileAwareDocumentContent(@Nullable Project project, @NotNull Document document, @Nullable FileType fileType, - @Nullable VirtualFile localFile, + @Nullable VirtualFile highlightFile, @Nullable LineSeparator separator, @Nullable Charset charset) { - super(document, fileType, localFile, separator, charset); + super(document, fileType, highlightFile, separator, charset); myProject = project; - myLocalFile = localFile; + myHighlightFile = highlightFile; } public OpenFileDescriptor getOpenFileDescriptor(int offset) { - if (myProject == null || myLocalFile == null) return null; - return new OpenFileDescriptor(myProject, myLocalFile, offset); + if (myProject == null || myHighlightFile == null) return null; + return new OpenFileDescriptor(myProject, myHighlightFile, offset); } @NotNull @@ -45,8 +44,8 @@ public class FileAwareDocumentContent extends DocumentContentImpl { } @NotNull - public static FileAwareDocumentContent create(@Nullable Project project, @NotNull String content, @NotNull VirtualFile file) { - return new Builder(project).init(file).create(content).build(); + public static FileAwareDocumentContent create(@Nullable Project project, @NotNull String content, @NotNull VirtualFile highlightFile) { + return new Builder(project).init(highlightFile).create(content).build(); } @NotNull @@ -55,15 +54,15 @@ public class FileAwareDocumentContent extends DocumentContentImpl { } @NotNull - public static FileAwareDocumentContent create(@Nullable Project project, @NotNull byte[] content, @NotNull VirtualFile file) { - return new Builder(project).init(file).create(content).build(); + public static FileAwareDocumentContent create(@Nullable Project project, @NotNull byte[] content, @NotNull VirtualFile highlightFile) { + return new Builder(project).init(highlightFile).create(content).build(); } private static class Builder { private final Project myProject; private Document myDocument; private FileType myFileType; - private VirtualFile myLocalFile; + private VirtualFile myHighlightFile; private LineSeparator mySeparator; private Charset myCharset; @@ -77,17 +76,18 @@ public class FileAwareDocumentContent extends DocumentContentImpl { @NotNull private Builder init(@NotNull FilePath path) { - myLocalFile = LocalFileSystem.getInstance().findFileByPath(path.getPath()); - myFileType = myLocalFile != null ? myLocalFile.getFileType() : path.getFileType(); - myCharset = myLocalFile != null ? myLocalFile.getCharset() : path.getCharset(myProject); + path.refresh(); + myHighlightFile = path.getVirtualFile(); + myFileType = path.getFileType(); + myCharset = path.getCharset(myProject); return this; } @NotNull - private Builder init(@NotNull VirtualFile file) { - myLocalFile = file; - myFileType = file.getFileType(); - myCharset = file.getCharset(); + private Builder init(@NotNull VirtualFile highlightFile) { + myHighlightFile = highlightFile; + myFileType = highlightFile.getFileType(); + myCharset = highlightFile.getCharset(); return this; } @@ -111,7 +111,7 @@ public class FileAwareDocumentContent extends DocumentContentImpl { @NotNull public FileAwareDocumentContent build() { if (FileTypes.UNKNOWN.equals(myFileType)) myFileType = PlainTextFileType.INSTANCE; - return new FileAwareDocumentContent(myProject, myDocument, myFileType, myLocalFile, mySeparator, myCharset); + return new FileAwareDocumentContent(myProject, myDocument, myFileType, myHighlightFile, mySeparator, myCharset); } } } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffViewer.java index 51fc0d7f4da7..f682a5ed86a6 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffViewer.java @@ -108,7 +108,7 @@ public class BinaryDiffViewer extends ListenerDiffViewerBase { myStatusPanel = new MyStatusPanel(); - new MyFocusOppositePaneAction().setupAction(myPanel, this); + new MyFocusOppositePaneAction().setupAction(myPanel); installEditorListeners(); diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java index 57774f6f6d99..97b302c7ad69 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java @@ -819,12 +819,12 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { return getTextSettings().isEnableSyncScroll(); } - public int transfer(@NotNull Side side, int line) { + public int transfer(@NotNull Side baseSide, int line) { if (myDiffChanges.isEmpty()) { return line; } - return super.transfer(side, line); + return super.transfer(baseSide, line); } @Override diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/BaseSyncScrollable.java b/platform/diff-impl/src/com/intellij/diff/tools/util/BaseSyncScrollable.java index f02380b50839..e546c5f298e0 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/BaseSyncScrollable.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/BaseSyncScrollable.java @@ -29,8 +29,8 @@ public abstract class BaseSyncScrollable implements SyncScrollSupport.SyncScroll */ protected abstract void processHelper(@NotNull ScrollHelper helper); - public int transfer(@NotNull Side side, int line) { - ScrollHelper helper = new ScrollHelper(side, line); + public int transfer(@NotNull Side baseSide, int line) { + ScrollHelper helper = new ScrollHelper(baseSide, line); processHelper(helper); int master1 = helper.getMaster1(); diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/DiffDataKeys.java b/platform/diff-impl/src/com/intellij/diff/tools/util/DiffDataKeys.java index e9c274e3ace5..94f2fe6c1537 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/DiffDataKeys.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/DiffDataKeys.java @@ -17,6 +17,7 @@ package com.intellij.diff.tools.util; import com.intellij.diff.DiffContext; import com.intellij.diff.FrameDiffTool; +import com.intellij.diff.contents.DiffContent; import com.intellij.diff.requests.DiffRequest; import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.editor.Editor; @@ -24,6 +25,7 @@ import com.intellij.openapi.fileEditor.OpenFileDescriptor; public interface DiffDataKeys { DataKey CURRENT_EDITOR = DataKey.create("diff_current_editor"); + DataKey CURRENT_CONTENT = DataKey.create("diff_current_content"); DataKey DIFF_REQUEST = DataKey.create("diff_request"); DataKey DIFF_CONTEXT = DataKey.create("diff_context"); diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/SyncScrollSupport.java b/platform/diff-impl/src/com/intellij/diff/tools/util/SyncScrollSupport.java index dbaffab0a4eb..68788e3b9030 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/SyncScrollSupport.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/SyncScrollSupport.java @@ -35,7 +35,7 @@ public class SyncScrollSupport { boolean isSyncScrollEnabled(); @CalledInAwt - int transfer(@NotNull Side side, int line); + int transfer(@NotNull Side baseSide, int line); } public static class TwosideSyncScrollSupport { @@ -73,6 +73,15 @@ public class SyncScrollSupport { myDuringSyncScroll = false; } } + + @NotNull + public SyncScrollable getScrollable() { + return myScrollable; + } + + public boolean isDuringSyncScroll() { + return myDuringSyncScroll; + } } public static class ThreesideSyncScrollSupport { diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffViewerBase.java b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffViewerBase.java index 2ecd2fbca6f8..28753c454b6c 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffViewerBase.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffViewerBase.java @@ -26,7 +26,6 @@ import com.intellij.diff.util.DiffUtil; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.actions.EditorActionUtil; import com.intellij.openapi.editor.event.EditorMouseEvent; import com.intellij.openapi.editor.ex.EditorEx; @@ -114,7 +113,7 @@ public abstract class TextDiffViewerBase extends ListenerDiffViewerBase { @NotNull protected List createEditorPopupActions() { return ContainerUtil.list( - ActionManager.getInstance().getAction("CompareClipboardWithSelection") // TODO: pass FileType to DataContext for highlighting + ActionManager.getInstance().getAction("CompareClipboardWithSelection") ); } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/threeside/ThreesideTextDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/util/threeside/ThreesideTextDiffViewer.java index 244f81e4a138..076134271e1d 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/threeside/ThreesideTextDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/threeside/ThreesideTextDiffViewer.java @@ -262,6 +262,11 @@ public abstract class ThreesideTextDiffViewer extends TextDiffViewerBase { return myCurrentSide.select(myEditors); } + @NotNull + public DocumentContent getCurrentContent() { + return myCurrentSide.select(myActualContents); + } + @NotNull @Override protected List getEditors() { @@ -306,10 +311,8 @@ public abstract class ThreesideTextDiffViewer extends TextDiffViewerBase { protected OpenFileDescriptor getOpenFileDescriptor() { EditorEx editor = getCurrentEditor(); - DocumentContent content = getCurrentSide().select(myActualContents); - int offset = editor.getCaretModel().getOffset(); - return content.getOpenFileDescriptor(offset); + return getCurrentContent().getOpenFileDescriptor(offset); } public static boolean canShowRequest(@NotNull DiffContext context, @NotNull DiffRequest request) { @@ -392,6 +395,9 @@ public abstract class ThreesideTextDiffViewer extends TextDiffViewerBase { if (DiffDataKeys.CURRENT_EDITOR.is(dataId)) { return getCurrentEditor(); } + else if (DiffDataKeys.CURRENT_CONTENT.is(dataId)) { + return getCurrentContent(); + } return super.getData(dataId); } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/twoside/TwosideTextDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/util/twoside/TwosideTextDiffViewer.java index 96689115da21..6ae251d9c390 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/twoside/TwosideTextDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/twoside/TwosideTextDiffViewer.java @@ -109,7 +109,8 @@ public abstract class TwosideTextDiffViewer extends TextDiffViewerBase { myPanel = new TwosideTextDiffPanel(this, myContentPanel, this, context); - new MyFocusOppositePaneAction().setupAction(myPanel, this); + new MyFocusOppositePaneAction(true).setupAction(myPanel); + new MyFocusOppositePaneAction(false).setupAction(myPanel); myEditorSettingsAction = new MySetEditorSettingsAction(); myEditorSettingsAction.applyDefaults(); @@ -301,6 +302,12 @@ public abstract class TwosideTextDiffViewer extends TextDiffViewerBase { return getCurrentSide().isLeft() ? myEditor1 : myEditor2; } + @NotNull + public DocumentContent getCurrentContent() { + //noinspection ConstantConditions + return getCurrentSide().isLeft() ? myActualContent1 : myActualContent2; + } + @Nullable protected EditorEx getEditor1() { return myEditor1; @@ -315,6 +322,14 @@ public abstract class TwosideTextDiffViewer extends TextDiffViewerBase { // Abstract // + @CalledInAwt + @NotNull + protected LogicalPosition transferPosition(@NotNull Side baseSide, @NotNull LogicalPosition position) { + if (mySyncScrollListener == null) return position; + int line = mySyncScrollListener.getScrollable().transfer(baseSide, position.line); + return new LogicalPosition(line, position.column); + } + @CalledInAwt protected void scrollToLine(@NotNull Side side, int line) { Editor editor = side.select(myEditor1, myEditor2); @@ -350,11 +365,8 @@ public abstract class TwosideTextDiffViewer extends TextDiffViewerBase { protected OpenFileDescriptor getOpenFileDescriptor() { EditorEx editor = getCurrentEditor(); - DocumentContent content = getCurrentSide().select(myActualContent1, myActualContent2); - assert content != null; - int offset = editor.getCaretModel().getOffset(); - return content.getOpenFileDescriptor(offset); + return getCurrentContent().getOpenFileDescriptor(offset); } public static boolean canShowRequest(@NotNull DiffContext context, @NotNull DiffRequest request) { @@ -388,10 +400,21 @@ public abstract class TwosideTextDiffViewer extends TextDiffViewerBase { // private class MyFocusOppositePaneAction extends FocusOppositePaneAction { + public MyFocusOppositePaneAction(boolean scrollToPosition) { + super(scrollToPosition); + } + @Override public void actionPerformed(@NotNull AnActionEvent e) { if (myEditor1 == null || myEditor2 == null) return; + if (myScrollToPosition) { + EditorEx currentEditor = myCurrentSide.select(myEditor1, myEditor2); + EditorEx targetEditor = myCurrentSide.other().select(myEditor1, myEditor2); + LogicalPosition position = transferPosition(myCurrentSide, currentEditor.getCaretModel().getLogicalPosition()); + targetEditor.getCaretModel().moveToLogicalPosition(position); + } + myCurrentSide = myCurrentSide.other(); myPanel.requestFocus(); getCurrentEditor().getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); @@ -423,6 +446,9 @@ public abstract class TwosideTextDiffViewer extends TextDiffViewerBase { if (DiffDataKeys.CURRENT_EDITOR.is(dataId)) { return getCurrentEditor(); } + else if (DiffDataKeys.CURRENT_CONTENT.is(dataId)) { + return getCurrentContent(); + } return super.getData(dataId); } diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java index f940fd7ed82d..290d7833903f 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java @@ -203,10 +203,7 @@ public class DiffUtil { if (editor == null) return; editor.getCaretModel().removeSecondaryCarets(); editor.getCaretModel().moveToLogicalPosition(position); - ScrollingModel scrollingModel = editor.getScrollingModel(); - scrollingModel.disableAnimation(); - scrollingModel.scrollToCaret(ScrollType.CENTER); - scrollingModel.enableAnimation(); + scrollToCaret(editor); } public static void scrollToLineAnimated(@Nullable final Editor editor, int line) { diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/ContinuationIndentDetector.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/ContinuationIndentDetector.java new file mode 100644 index 000000000000..6b27f04341e2 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/ContinuationIndentDetector.java @@ -0,0 +1,117 @@ +/* + * Copyright 2000-2015 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.psi.codeStyle.autodetect; + +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Stack; +import com.intellij.util.text.CharArrayUtil; +import org.jetbrains.annotations.NotNull; + +class ContinuationIndentDetector { + private Stack myOpenedBrackets = ContainerUtil.newStack(); + + private final CharSequence myText; + private final int myLength; + private boolean myIncorrectBracketsOrder = false; + + public ContinuationIndentDetector(@NotNull CharSequence text) { + myText = text; + myLength = text.length(); + } + + public void feedLineStartingAt(int startOffset) { + if (myIncorrectBracketsOrder) return; + + int lineEndOffset = CharArrayUtil.indexOf(myText, "\n", startOffset, myLength); + if (lineEndOffset < 0) lineEndOffset = myLength; + + for (int i = startOffset; i < lineEndOffset; i++) { + Bracket bracket = Bracket.forChar(myText.charAt(i)); + if (bracket == null) continue; + processBracket(bracket); + } + } + + private void processBracket(@NotNull Bracket bracket) { + if (bracket.isOpening()) { + myOpenedBrackets.add(bracket); + } + else { + if (!myOpenedBrackets.isEmpty() && bracket.isClosing(myOpenedBrackets.peek())) { + myOpenedBrackets.pop(); + } + else { + myIncorrectBracketsOrder = true; + } + } + } + + public boolean isContinuationIndent() { + if (myIncorrectBracketsOrder || myOpenedBrackets.isEmpty()) { + return false; + } + return myOpenedBrackets.peek() == Bracket.LPARENTH; + } + + + private enum Bracket { + LBRACE('{') { + @Override + boolean isOpening() { + return true; + } + }, + LPARENTH('(') { + @Override + boolean isOpening() { + return true; + } + }, + RBRACE('}') { + @Override + public boolean isClosing(Bracket bracket) { + return bracket == LBRACE; + } + }, + RPARENTH(')') { + @Override + public boolean isClosing(Bracket bracket) { + return bracket == LPARENTH; + } + }; + + private final char myChar; + + Bracket(char c) { + myChar = c; + } + + public boolean isClosing(Bracket bracket) { + return false; + } + + boolean isOpening() { + return false; + } + + static Bracket forChar(char c) { + for (Bracket bracket : Bracket.values()) { + if (bracket.myChar == c) return bracket; + } + return null; + } + } +} diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfo.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfo.java index d85a4cbcaa0e..2532a6df3629 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfo.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfo.java @@ -21,6 +21,7 @@ public class LineIndentInfo { public static final LineIndentInfo EMPTY_LINE = new LineIndentInfo(LineType.EMPTY_LINE, -1); public static final LineIndentInfo LINE_WITH_COMMENT = new LineIndentInfo(LineType.LINE_WITH_COMMENT, -1); public static final LineIndentInfo LINE_WITH_TABS = new LineIndentInfo(LineType.LINE_WITH_TABS, -1); + public static final LineIndentInfo LINE_WITH_CONTINUATION_INDENT = new LineIndentInfo(LineType.LINE_WITH_CONTINUATION_INDENT, -1); private final int myIndentSize; private final LineType myType; @@ -51,6 +52,7 @@ public class LineIndentInfo { EMPTY_LINE, LINE_WITH_COMMENT, LINE_WITH_TABS, - LINE_WITH_WHITESPACE_INDENT + LINE_WITH_WHITESPACE_INDENT, + LINE_WITH_CONTINUATION_INDENT } } diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfoBuilder.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfoBuilder.java index 6df9580e9e88..89fe8fa542c1 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfoBuilder.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfoBuilder.java @@ -31,10 +31,12 @@ public class LineIndentInfoBuilder { private final CharSequence myText; private final int myLength; private final Commenter myCommenter; + private ContinuationIndentDetector myContinuationIndentDetector; public LineIndentInfoBuilder(@NotNull CharSequence text, @Nullable Language language) { myText = text; myLength = text.length(); + myContinuationIndentDetector = new ContinuationIndentDetector(text); myCommenter = language != null ? LanguageCommenters.INSTANCE.forLanguage(language) : null; } @@ -68,11 +70,14 @@ public class LineIndentInfoBuilder { return LineIndentInfo.LINE_WITH_COMMENT; } else if (CharArrayUtil.indexOf(myText, "\t", lineStartOffset, textStartOffset) > 0) { + myContinuationIndentDetector.feedLineStartingAt(lineStartOffset); return LineIndentInfo.LINE_WITH_TABS; } else { - int indentSize = textStartOffset - lineStartOffset; - return LineIndentInfo.newWhiteSpaceIndent(indentSize); + boolean isContinuationIndent = myContinuationIndentDetector.isContinuationIndent(); + myContinuationIndentDetector.feedLineStartingAt(lineStartOffset); + return isContinuationIndent ? LineIndentInfo.LINE_WITH_CONTINUATION_INDENT + : LineIndentInfo.newWhiteSpaceIndent(textStartOffset - lineStartOffset); } } diff --git a/platform/lang-impl/testSources/com/intellij/psi/codeStyle/autodetect/ContinuationIndentDetectorTest.java b/platform/lang-impl/testSources/com/intellij/psi/codeStyle/autodetect/ContinuationIndentDetectorTest.java new file mode 100644 index 000000000000..4a7475a49f62 --- /dev/null +++ b/platform/lang-impl/testSources/com/intellij/psi/codeStyle/autodetect/ContinuationIndentDetectorTest.java @@ -0,0 +1,162 @@ +/* + * Copyright 2000-2015 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.psi.codeStyle.autodetect; + +import com.intellij.util.containers.ContainerUtil; +import junit.framework.TestCase; + +import java.util.List; +import java.util.Set; + + +public class ContinuationIndentDetectorTest extends TestCase { + private ContinuationIndentDetector myContinuationIndentDetector; + private List myLineStartOffsets; + + public void configure(String text) { + myContinuationIndentDetector = new ContinuationIndentDetector(text); + myLineStartOffsets = calculateLineStartOffsets(text); + } + + public void testContinuationIndentInsideParenth() { + configure( + "test(\n" + + " \"aaaaa\" + \n" + + " \"bbbbb\");\n" + + "int a = 2;" + ); + + doCheckLinesWithContinuationIndents(1, 2); + } + + public void testNoContinuationIndent_OnLineStartingWithRightParenth() { + configure( + "test(\n" + + " \"aaaaa\" + \n" + + " \"bbbbb\"\n" + + ");" + ); + + doCheckLinesWithContinuationIndents(1, 2, 3); + } + + public void testNoContinuationIndents_BetweenBraces() { + configure( + "import java.lang.Override;\n" + + "import java.lang.Runnable;\n" + + "\n" + + "class T {\n" + + " \n" + + " void test() {\n" + + " int a;\n" + + " int b;\n" + + " Runnable runnable = new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " System.out.println(\"AAA!\");\n" + + " }\n" + + " }\n" + + " }\n" + + " \n" + + "}" + ); + doCheckLinesWithContinuationIndents(); + } + + public void testMixedBraces() { + configure( + "import java.lang.Runnable;\n" + + "\n" + + "class R {\n" + + "\n" + + "\n" + + " void test() {\n" + + " kuu(new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + " },\n" + + " new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + " }\n" + + " );\n" + + " }\n" + + "\n" + + " void kuu(Runnable a, Runnable b) {\n" + + " }\n" + + "}" + ); + doCheckLinesWithContinuationIndents(11, 16); + } + + public void testClosingBracesAtLineStart() { + configure("class Test {\n" + + " public static void main(String[] args) {\n" + + " tree.put(\"Web Development\", Pair.create(PlatformImplIcons.WebDevelopment, Arrays.asList(\n" + + " \"HTML:HtmlTools\",\n" + + " \"com.intellij.css\",\n" + + " \"JavaScript:JavaScript,JSIntentionPowerPack\",\n" + + " \"com.jetbrains.restClient\"\n" + + " )));\n" + + " }\n" + + "}"); + doCheckLinesWithContinuationIndents(3, 4, 5, 6, 7); + } + + public void testInsideParenth() { + configure("@State(\n" + + " name = \"AndroidRemoteDataBaseManager\",\n" + + " storages = {\n" + + " @Storage(\n" + + " file = StoragePathMacros.APP_CONFIG + \"/androidRemoteDatabases.xml\"\n" + + " )}\n" + + ")\n" + + "class T {}"); + doCheckLinesWithContinuationIndents(1, 2, 4, 5, 6); + } + + private void doCheckLinesWithContinuationIndents(Integer... linesWithContinuationIndents) { + Set continuationLines = ContainerUtil.newHashSet(linesWithContinuationIndents); + + for (int currentLine = 0; currentLine < myLineStartOffsets.size(); currentLine++) { + Integer lineStartOffset = myLineStartOffsets.get(currentLine); + boolean isContinuation = myContinuationIndentDetector.isContinuationIndent(); + if (continuationLines.contains(currentLine)) { + assertTrue("Line " + currentLine + " should start with continuation indent", isContinuation); + } + else { + assertTrue("Line " + currentLine + " should not start with continuation indent" ,!isContinuation); + } + myContinuationIndentDetector.feedLineStartingAt(lineStartOffset); + } + } + + private List calculateLineStartOffsets(String text) { + List lineStartOffsets = ContainerUtil.newArrayList(); + lineStartOffsets.add(0); + + int lineStart = 0; + int lineFeed; + while ((lineFeed = text.indexOf('\n', lineStart)) > 0) { + lineStart = lineFeed + 1; + lineStartOffsets.add(lineStart); + } + + return lineStartOffsets; + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java b/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java index 2e4e9c85bb39..cf7900e5d167 100644 --- a/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java @@ -294,10 +294,8 @@ public class ContentManagerImpl implements ContentManager, PropertyChangeListene } int newSize = myContents.size(); - - ActionCallback result = new ActionCallback(); - if (newSize > 0 && trackSelection) { + ActionCallback result = new ActionCallback(); if (indexToSelect > -1) { final Content toSelect = mySelectionHistory.size() > 0 ? mySelectionHistory.get(0) : myContents.get(indexToSelect); if (!isSelected(toSelect)) { @@ -310,12 +308,12 @@ public class ContentManagerImpl implements ContentManager, PropertyChangeListene } } } + return result; } else { mySelection.clear(); + return ActionCallback.DONE; } - - return result; } finally { if (ApplicationManager.getApplication().isDispatchThread()) { diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 090327bf29ee..ba924d074f3c 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -1221,7 +1221,10 @@ action.VcsHistory.ShowAllAffected.description=Show all changes made in the chose action.AddFrameworkSupport.text=Add Framework Support... -action.Diff.FocusOppositePane.text=Select opposite pane in diff view +action.Diff.FocusOppositePane.text=Select Opposite Diff Pane +action.Diff.FocusOppositePane.description=Select opposite pane in diff view +action.Diff.FocusOppositePaneAndScroll.text=Select Position In Opposite Diff Pane +action.Diff.FocusOppositePaneAndScroll.description=Select the same position in opposite pane in diff view action.Diff.PrevChange.text=Compare Previous File action.Diff.NextChange.text=Compare Next File action.Diff.SelectedChange.text=Choose File To Compare diff --git a/platform/platform-resources/src/idea/Keymap_Default.xml b/platform/platform-resources/src/idea/Keymap_Default.xml index 5ce4479f0491..1e5154284f9e 100644 --- a/platform/platform-resources/src/idea/Keymap_Default.xml +++ b/platform/platform-resources/src/idea/Keymap_Default.xml @@ -547,6 +547,12 @@ + + + + + + diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index 30ed1acea257..339d402bca62 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -162,7 +162,9 @@ - + + + diff --git a/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java b/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java index 4dd45a7df4ba..172811192142 100644 --- a/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java +++ b/platform/testFramework/testSrc/com/intellij/openapi/keymap/KeymapsTestCase.java @@ -132,6 +132,8 @@ public abstract class KeymapsTestCase extends PlatformTestCase { { "shift control U", "ShelveChanges.UnshelveWithDialog", "EditorToggleCase"}, { "control E", "RecentFiles", "Vcs.ShowMessageHistory"}, { "control alt Z", "Vcs.RollbackChangedLines", "ChangesView.Revert"}, + { "control TAB", "Switcher", "Diff.FocusOppositePane"}, + { "shift control TAB", "Switcher", "Diff.FocusOppositePaneAndScroll"}, }); put("Mac OS X 10.5+", new String[][] { { "F5", "CopyElement", "Console.TableResult.Reload", "UML.ApplyCurrentLayout"}, diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java index 314c0dcf3f8a..2df8cad37e62 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java @@ -43,8 +43,6 @@ import java.util.List; public abstract class CacheChangeProcessor extends DiffRequestProcessor { private static final Logger LOG = Logger.getInstance(CacheChangeProcessor.class); - @NotNull private final Project myProject; - @NotNull private final SoftHardCacheMap> myRequestCache = new SoftHardCacheMap>(5, 5); @@ -54,12 +52,10 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor { public CacheChangeProcessor(@NotNull Project project) { super(project); - myProject = project; } public CacheChangeProcessor(@NotNull Project project, @NotNull String place) { super(project, place); - myProject = project; } // @@ -133,7 +129,7 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor { @NotNull @CalledInBackground private DiffRequest loadRequest(@NotNull Change change, @NotNull ProgressIndicator indicator) { - ChangeDiffRequestProducer presentable = ChangeDiffRequestProducer.create(myProject, change); + ChangeDiffRequestProducer presentable = ChangeDiffRequestProducer.create(getProject(), change); if (presentable == null) return new ErrorDiffRequest("Can't show diff"); try { return presentable.process(getContext(), indicator); @@ -162,6 +158,12 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor { myRequestCache.clear(); } + @NotNull + @Override + public Project getProject() { + return super.getProject(); + } + // // Navigation //