From 9bef9021315a1885ac8f3a736223f03961310d60 Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Mon, 24 Mar 2014 19:46:26 +0400 Subject: [PATCH] #452: introduce method separators --- src/META-INF/plugin.xml | 1 + .../marker/ErlangMethodSeparatorProvider.java | 82 +++++++++++++++++++ testData/marker/methodSeparators/comment.erl | 3 + .../methodSeparators/commentAndSpec.erl | 4 + .../commentSpecAndComment.erl | 5 ++ testData/marker/methodSeparators/function.erl | 2 + testData/marker/methodSeparators/spec.erl | 3 + .../methodSeparators/specAndComment.erl | 4 + .../methodSeparators/specOfOtherFunction.erl | 3 + .../marker/methodSeparators/twoFunctions.erl | 5 ++ .../ErlangMethodSeparatorProviderTest.java | 78 ++++++++++++++++++ 11 files changed, 190 insertions(+) create mode 100644 src/org/intellij/erlang/marker/ErlangMethodSeparatorProvider.java create mode 100644 testData/marker/methodSeparators/comment.erl create mode 100644 testData/marker/methodSeparators/commentAndSpec.erl create mode 100644 testData/marker/methodSeparators/commentSpecAndComment.erl create mode 100644 testData/marker/methodSeparators/function.erl create mode 100644 testData/marker/methodSeparators/spec.erl create mode 100644 testData/marker/methodSeparators/specAndComment.erl create mode 100644 testData/marker/methodSeparators/specOfOtherFunction.erl create mode 100644 testData/marker/methodSeparators/twoFunctions.erl create mode 100644 tests/org/intellij/erlang/marker/ErlangMethodSeparatorProviderTest.java diff --git a/src/META-INF/plugin.xml b/src/META-INF/plugin.xml index 6f6bbed1a..21cdbb0ce 100755 --- a/src/META-INF/plugin.xml +++ b/src/META-INF/plugin.xml @@ -115,6 +115,7 @@ + diff --git a/src/org/intellij/erlang/marker/ErlangMethodSeparatorProvider.java b/src/org/intellij/erlang/marker/ErlangMethodSeparatorProvider.java new file mode 100644 index 000000000..32a8dcad6 --- /dev/null +++ b/src/org/intellij/erlang/marker/ErlangMethodSeparatorProvider.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012-2014 Sergey Ignatov + * + * 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 org.intellij.erlang.marker; + +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings; +import com.intellij.codeInsight.daemon.LineMarkerInfo; +import com.intellij.codeInsight.daemon.LineMarkerProvider; +import com.intellij.codeInsight.daemon.impl.LineMarkersPass; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.util.PsiTreeUtil; +import org.intellij.erlang.psi.*; +import org.intellij.erlang.psi.impl.ErlangPsiImplUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; + +public class ErlangMethodSeparatorProvider implements LineMarkerProvider { + private final DaemonCodeAnalyzerSettings myDaemonSettings; + private final EditorColorsManager myColorsManager; + + public ErlangMethodSeparatorProvider(DaemonCodeAnalyzerSettings daemonSettings, EditorColorsManager colorsManager) { + myDaemonSettings = daemonSettings; + myColorsManager = colorsManager; + } + + @Nullable + @Override + public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement function) { + if (myDaemonSettings.SHOW_METHOD_SEPARATORS && function instanceof ErlangFunction) { + PsiElement anchor = findAnchorElementForMethodSeparator((ErlangFunction) function); + return LineMarkersPass.createMethodSeparatorLineMarker(anchor, myColorsManager); + } + return null; + } + + @Override + public void collectSlowLineMarkers(@NotNull List elements, @NotNull Collection result) { + } + + private static PsiElement findAnchorElementForMethodSeparator(ErlangFunction function) { + ErlangAttribute specAttribute = getSpecAttributeForFunction(function); + PsiElement leftmostPossibleAnchor = function; + PsiElement leftmostElement = function; + while ((leftmostElement = leftmostElement.getPrevSibling()) != null) { + if (leftmostElement instanceof PsiComment || leftmostElement == specAttribute) { + leftmostPossibleAnchor = leftmostElement; + } + else if (!(leftmostElement instanceof PsiWhiteSpace)) break; + } + return leftmostPossibleAnchor; + } + + @Nullable + private static ErlangAttribute getSpecAttributeForFunction(ErlangFunction function) { + ErlangSpecification spec = ErlangPsiImplUtil.getSpecification(function); + ErlangFunTypeSigs signature = ErlangPsiImplUtil.getSignature(spec); + ErlangSpecFun specFun = signature != null ? signature.getSpecFun() : null; + PsiReference reference = specFun != null ? specFun.getReference() : null; + boolean isSpecForPassedFunction = reference != null && reference.isReferenceTo(function); + return isSpecForPassedFunction ? PsiTreeUtil.getParentOfType(spec, ErlangAttribute.class) : null; + } +} diff --git a/testData/marker/methodSeparators/comment.erl b/testData/marker/methodSeparators/comment.erl new file mode 100644 index 000000000..8a3c509ef --- /dev/null +++ b/testData/marker/methodSeparators/comment.erl @@ -0,0 +1,3 @@ +% comment +foo() -> + ok. \ No newline at end of file diff --git a/testData/marker/methodSeparators/commentAndSpec.erl b/testData/marker/methodSeparators/commentAndSpec.erl new file mode 100644 index 000000000..9546e19af --- /dev/null +++ b/testData/marker/methodSeparators/commentAndSpec.erl @@ -0,0 +1,4 @@ +% comment +-spec foo() -> ok. +foo() -> + ok. \ No newline at end of file diff --git a/testData/marker/methodSeparators/commentSpecAndComment.erl b/testData/marker/methodSeparators/commentSpecAndComment.erl new file mode 100644 index 000000000..c53082c73 --- /dev/null +++ b/testData/marker/methodSeparators/commentSpecAndComment.erl @@ -0,0 +1,5 @@ +% comment +-spec foo() -> ok. +% comment +foo() -> + ok. \ No newline at end of file diff --git a/testData/marker/methodSeparators/function.erl b/testData/marker/methodSeparators/function.erl new file mode 100644 index 000000000..db7300110 --- /dev/null +++ b/testData/marker/methodSeparators/function.erl @@ -0,0 +1,2 @@ +foo() -> + ok. \ No newline at end of file diff --git a/testData/marker/methodSeparators/spec.erl b/testData/marker/methodSeparators/spec.erl new file mode 100644 index 000000000..b3ce17fc7 --- /dev/null +++ b/testData/marker/methodSeparators/spec.erl @@ -0,0 +1,3 @@ +-spec foo() -> ok. +foo() -> + ok. \ No newline at end of file diff --git a/testData/marker/methodSeparators/specAndComment.erl b/testData/marker/methodSeparators/specAndComment.erl new file mode 100644 index 000000000..627732f05 --- /dev/null +++ b/testData/marker/methodSeparators/specAndComment.erl @@ -0,0 +1,4 @@ +-spec foo() -> ok. +% comment +foo() -> + ok. \ No newline at end of file diff --git a/testData/marker/methodSeparators/specOfOtherFunction.erl b/testData/marker/methodSeparators/specOfOtherFunction.erl new file mode 100644 index 000000000..4a3b5d451 --- /dev/null +++ b/testData/marker/methodSeparators/specOfOtherFunction.erl @@ -0,0 +1,3 @@ +-spec bar() -> ok. +foo() -> + ok. \ No newline at end of file diff --git a/testData/marker/methodSeparators/twoFunctions.erl b/testData/marker/methodSeparators/twoFunctions.erl new file mode 100644 index 000000000..e829373d1 --- /dev/null +++ b/testData/marker/methodSeparators/twoFunctions.erl @@ -0,0 +1,5 @@ +foo() -> + ok. + +bar() -> + ok. \ No newline at end of file diff --git a/tests/org/intellij/erlang/marker/ErlangMethodSeparatorProviderTest.java b/tests/org/intellij/erlang/marker/ErlangMethodSeparatorProviderTest.java new file mode 100644 index 000000000..e7c5ddc6e --- /dev/null +++ b/tests/org/intellij/erlang/marker/ErlangMethodSeparatorProviderTest.java @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2014 Sergey Ignatov + * + * 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 org.intellij.erlang.marker; + +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings; +import com.intellij.codeInsight.daemon.LineMarkerInfo; +import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl; +import org.intellij.erlang.utils.ErlangLightPlatformCodeInsightFixtureTestCase; + +import java.util.List; + +public class ErlangMethodSeparatorProviderTest extends ErlangLightPlatformCodeInsightFixtureTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + setShowMethodSeparatorsEnabled(true); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + setShowMethodSeparatorsEnabled(false); + } + + @Override + protected String getTestDataPath() { + return "testData/marker/methodSeparators/"; + } + + @Override + protected boolean isWriteActionRequired() { + return false; + } + + private static void setShowMethodSeparatorsEnabled(boolean b) { + DaemonCodeAnalyzerSettings settings = DaemonCodeAnalyzerSettings.getInstance(); + settings.SHOW_METHOD_SEPARATORS = b; + } + + protected void doTest(Integer ... expectedLineMarkers) { + myFixture.configureByFile(getTestName(true) + ".erl"); + myFixture.doHighlighting(); + assertSameElements(getMarkedLineNumbers(), expectedLineMarkers); + } + + private Integer[] getMarkedLineNumbers() { + List lineMarkers = DaemonCodeAnalyzerImpl.getLineMarkers(myFixture.getEditor().getDocument(), myFixture.getProject()); + assertNotNull(lineMarkers); + Integer[] markedLineNumbers = new Integer[lineMarkers.size()]; + for (int i = 0; i < lineMarkers.size(); i++) { + markedLineNumbers[i] = myFixture.getEditor().getDocument().getLineNumber(lineMarkers.get(i).startOffset); + } + return markedLineNumbers; + } + + public void testFunction() throws Exception { doTest(0); } + public void testTwoFunctions() throws Exception { doTest(0, 3); } + public void testSpec() throws Exception { doTest(0); } + public void testComment() throws Exception { doTest(0); } + public void testSpecAndComment() throws Exception { doTest(0); } + public void testCommentAndSpec() throws Exception { doTest(0); } + public void testCommentSpecAndComment() throws Exception { doTest(0); } + public void testSpecOfOtherFunction() throws Exception { doTest(1); } +}