From 86c10b635ae6183da34ec5eae52310c99340e1c8 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 3 Jan 2018 17:22:27 +0100 Subject: [PATCH] Initial implementation of method separators #KT-13029 Fixed --- .../kotlin/test/InTextDirectivesUtils.java | 18 +++------ .../markers/KotlinLineMarkerProvider.kt | 36 +++++++++++++++--- .../lineMarker/MethodSeparators.kt | 37 +++++++++++++++++++ .../codeInsight/AbstractLineMarkersTest.kt | 22 +++++------ .../codeInsight/LineMarkersTestGenerated.java | 6 +++ 5 files changed, 88 insertions(+), 31 deletions(-) create mode 100644 idea/testData/codeInsight/lineMarker/MethodSeparators.kt diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/InTextDirectivesUtils.java b/compiler/tests-common/tests/org/jetbrains/kotlin/test/InTextDirectivesUtils.java index 26e9047b74e..c99ca3c8f74 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/InTextDirectivesUtils.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/InTextDirectivesUtils.java @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 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. + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.test; @@ -115,6 +104,9 @@ public final class InTextDirectivesUtils { @NotNull public static List findLinesWithPrefixesRemoved(String fileText, boolean trim, String... prefixes) { + if (prefixes.length == 0) { + throw new IllegalArgumentException("Please specify the prefixes to check"); + } List result = new ArrayList<>(); List cleanedPrefixes = cleanDirectivesFromComments(Arrays.asList(prefixes)); diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt index 2dde3396bdd..b102fb0a77a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt @@ -6,24 +6,26 @@ package org.jetbrains.kotlin.idea.highlighter.markers import com.intellij.codeHighlighting.Pass -import com.intellij.codeInsight.daemon.GutterIconNavigationHandler -import com.intellij.codeInsight.daemon.LineMarkerInfo -import com.intellij.codeInsight.daemon.LineMarkerProvider -import com.intellij.codeInsight.daemon.NavigateAction +import com.intellij.codeInsight.daemon.* import com.intellij.codeInsight.daemon.impl.LineMarkerNavigator import com.intellij.codeInsight.daemon.impl.MarkerType import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask import com.intellij.icons.AllIcons import com.intellij.openapi.actionSystem.IdeActions +import com.intellij.openapi.editor.colors.CodeInsightColors +import com.intellij.openapi.editor.colors.EditorColorsManager import com.intellij.openapi.editor.markup.GutterIconRenderer +import com.intellij.openapi.editor.markup.SeparatorPlacement import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.DumbService +import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.NavigatablePsiElement import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.search.searches.ClassInheritorsSearch +import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor @@ -42,6 +44,7 @@ import org.jetbrains.kotlin.idea.search.declarationsSearch.toPossiblyFakeLightMe import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespaceAndComments import java.awt.event.MouseEvent import java.util.* import javax.swing.Icon @@ -49,10 +52,33 @@ import javax.swing.ListCellRenderer class KotlinLineMarkerProvider : LineMarkerProvider { override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo? { - // all Kotlin markers are added in slow marker pass + if (DaemonCodeAnalyzerSettings.getInstance().SHOW_METHOD_SEPARATORS) { + if (element.canHaveSeparator()) { + val prevSibling = element.getPrevSiblingIgnoringWhitespaceAndComments() + if (prevSibling.canHaveSeparator() && + (element.wantsSeparator() || prevSibling?.wantsSeparator() == true)) { + return createLineSeparatorByElement(element) + } + } + } + return null } + private fun PsiElement?.canHaveSeparator() = + this is KtFunction || this is KtClassInitializer || (this is KtProperty && !isLocal) + + private fun PsiElement.wantsSeparator() = StringUtil.getLineBreakCount(text) > 0 + + private fun createLineSeparatorByElement(element: PsiElement): LineMarkerInfo { + val anchor = PsiTreeUtil.getDeepestFirst(element) + + val info = LineMarkerInfo(anchor, anchor.textRange, null, Pass.LINE_MARKERS, null, null, GutterIconRenderer.Alignment.RIGHT) + info.separatorColor = EditorColorsManager.getInstance().globalScheme.getColor(CodeInsightColors.METHOD_SEPARATORS_COLOR) + info.separatorPlacement = SeparatorPlacement.TOP + return info + } + override fun collectSlowLineMarkers(elements: List, result: MutableCollection>) { if (elements.isEmpty()) return diff --git a/idea/testData/codeInsight/lineMarker/MethodSeparators.kt b/idea/testData/codeInsight/lineMarker/MethodSeparators.kt new file mode 100644 index 00000000000..189f9f80b15 --- /dev/null +++ b/idea/testData/codeInsight/lineMarker/MethodSeparators.kt @@ -0,0 +1,37 @@ +// METHOD_SEPARATORS + +class Foo { + object BarObj { + } + + fun bar() { + + } + + fun baz() { + class FooLocal { + } + + fun fooLocal() { + } + + fun barLocal() { + } + + val xLocal = run { + "x" + } + } + + val x = 0 + + val y: Int + get() = 0 + + val z = run { + "abc" + } + + fun quux() {} + fun xyzzy() {} +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt index e01bb167751..ef0459c12f5 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt @@ -1,21 +1,11 @@ /* - * Copyright 2010-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. + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.idea.codeInsight +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings import com.intellij.codeInsight.daemon.LineMarkerInfo import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl import com.intellij.openapi.util.io.FileUtil @@ -33,6 +23,7 @@ import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor import org.jetbrains.kotlin.idea.test.PluginTestCaseBase import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.TagsTestDataUtil import org.jetbrains.kotlin.test.util.renderAsGotoImplementation @@ -53,6 +44,10 @@ abstract class AbstractLineMarkersTest : KotlinLightCodeInsightFixtureTestCase() val fileText = FileUtil.loadFile(File(path)) try { ConfigLibraryUtil.configureLibrariesByDirective(myFixture.module, PlatformTestUtil.getCommunityPath(), fileText) + if (InTextDirectivesUtils.findStringWithPrefixes(fileText,"METHOD_SEPARATORS") != null) { + DaemonCodeAnalyzerSettings.getInstance().SHOW_METHOD_SEPARATORS = true + } + myFixture.configureByFile(path) val project = myFixture.project @@ -98,6 +93,7 @@ abstract class AbstractLineMarkersTest : KotlinLightCodeInsightFixtureTestCase() } finally { ConfigLibraryUtil.unconfigureLibrariesByDirective(myModule, fileText) + DaemonCodeAnalyzerSettings.getInstance().SHOW_METHOD_SEPARATORS = false } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/LineMarkersTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/LineMarkersTestGenerated.java index 8dda7fa1e9f..94223ffa300 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/LineMarkersTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/LineMarkersTestGenerated.java @@ -25,6 +25,12 @@ public class LineMarkersTestGenerated extends AbstractLineMarkersTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/codeInsight/lineMarker"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("MethodSeparators.kt") + public void testMethodSeparators() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/lineMarker/MethodSeparators.kt"); + doTest(fileName); + } + @TestMetadata("idea/testData/codeInsight/lineMarker/overrideImplement") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)