Add intentions to put arguments / parameters on one line #KT-23266 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
96581f1ecb
commit
03902030ed
@@ -0,0 +1,3 @@
|
||||
fun foo() {
|
||||
bar(<spot>1, "abcd", false</spot>)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo() {
|
||||
bar(
|
||||
<spot>1,
|
||||
"abcd",
|
||||
false</spot>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention formats a function call placing all arguments on a single line.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo(<spot>param1: String, param2: Int, param3: Any</spot>) {
|
||||
bar()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(
|
||||
<spot>param1: String,
|
||||
param2: Int,
|
||||
param3: Any</spot>
|
||||
) {
|
||||
bar()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention formats parameters of a declaration placing all parameters on a single line.
|
||||
</body>
|
||||
</html>
|
||||
@@ -1572,6 +1572,16 @@
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.JoinParameterListIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.JoinArgumentListIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
|
||||
displayName="Object literal can be converted to lambda"
|
||||
groupPath="Kotlin"
|
||||
|
||||
@@ -29,9 +29,9 @@ import org.jetbrains.kotlin.psi.psiUtil.siblings
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
|
||||
abstract class AbstractChopListIntention<TList : KtElement, TElement : KtElement>(
|
||||
private val listClass: Class<TList>,
|
||||
private val elementClass: Class<TElement>,
|
||||
text: String
|
||||
private val listClass: Class<TList>,
|
||||
private val elementClass: Class<TElement>,
|
||||
text: String
|
||||
) : SelfTargetingOffsetIndependentIntention<TList>(listClass, text), LowPriorityAction {
|
||||
|
||||
override fun isApplicableTo(element: TList): Boolean {
|
||||
@@ -41,20 +41,20 @@ abstract class AbstractChopListIntention<TList : KtElement, TElement : KtElement
|
||||
return true
|
||||
}
|
||||
|
||||
override fun applyTo(list: TList, editor: Editor?) {
|
||||
val project = list.project
|
||||
override fun applyTo(element: TList, editor: Editor?) {
|
||||
val project = element.project
|
||||
val document = editor!!.document
|
||||
val startOffset = list.startOffset
|
||||
val startOffset = element.startOffset
|
||||
|
||||
val elements = list.elements()
|
||||
val elements = element.elements()
|
||||
if (!hasLineBreakAfter(elements.last())) {
|
||||
val rpar = list.allChildren.lastOrNull { it.node.elementType == KtTokens.RPAR }
|
||||
val rpar = element.allChildren.lastOrNull { it.node.elementType == KtTokens.RPAR }
|
||||
rpar?.startOffset?.let { document.insertString(it, "\n") }
|
||||
}
|
||||
|
||||
for (element in elements.asReversed()) {
|
||||
if (!hasLineBreakBefore(element)) {
|
||||
document.insertString(element.startOffset, "\n")
|
||||
for (e in elements.asReversed()) {
|
||||
if (!hasLineBreakBefore(e)) {
|
||||
document.insertString(e.startOffset, "\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,35 +65,43 @@ abstract class AbstractChopListIntention<TList : KtElement, TElement : KtElement
|
||||
CodeStyleManager.getInstance(project).adjustLineIndent(psiFile, newList.textRange)
|
||||
}
|
||||
|
||||
private fun hasLineBreakAfter(element: TElement): Boolean {
|
||||
return element
|
||||
.siblings(withItself = false)
|
||||
.takeWhile { !elementClass.isInstance(it) }
|
||||
.any { it is PsiWhiteSpace && it.textContains('\n') }
|
||||
protected fun hasLineBreakAfter(element: TElement): Boolean {
|
||||
return nextBreak(element) != null
|
||||
}
|
||||
|
||||
private fun hasLineBreakBefore(element: TElement): Boolean {
|
||||
protected fun nextBreak(element: TElement): PsiWhiteSpace? {
|
||||
return element
|
||||
.siblings(withItself = false, forward = false)
|
||||
.takeWhile { !elementClass.isInstance(it) }
|
||||
.any { it is PsiWhiteSpace && it.textContains('\n') }
|
||||
.siblings(withItself = false)
|
||||
.takeWhile { !elementClass.isInstance(it) }
|
||||
.firstOrNull { it is PsiWhiteSpace && it.textContains('\n') } as? PsiWhiteSpace
|
||||
}
|
||||
|
||||
private fun TList.elements(): List<TElement> {
|
||||
protected fun hasLineBreakBefore(element: TElement): Boolean {
|
||||
return prevBreak(element) != null
|
||||
}
|
||||
|
||||
protected fun prevBreak(element: TElement): PsiWhiteSpace? {
|
||||
return element
|
||||
.siblings(withItself = false, forward = false)
|
||||
.takeWhile { !elementClass.isInstance(it) }
|
||||
.firstOrNull { it is PsiWhiteSpace && it.textContains('\n') } as? PsiWhiteSpace
|
||||
}
|
||||
|
||||
protected fun TList.elements(): List<TElement> {
|
||||
return allChildren
|
||||
.filter { elementClass.isInstance(it) }
|
||||
.map {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
it as TElement
|
||||
}
|
||||
.toList()
|
||||
.filter { elementClass.isInstance(it) }
|
||||
.map {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
it as TElement
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
|
||||
class ChopParameterListIntention : AbstractChopListIntention<KtParameterList, KtParameter>(
|
||||
KtParameterList::class.java,
|
||||
KtParameter::class.java,
|
||||
"Put parameters on separate lines"
|
||||
KtParameterList::class.java,
|
||||
KtParameter::class.java,
|
||||
"Put parameters on separate lines"
|
||||
) {
|
||||
override fun isApplicableTo(element: KtParameterList): Boolean {
|
||||
if (element.parent is KtFunctionLiteral) return false
|
||||
@@ -102,7 +110,7 @@ class ChopParameterListIntention : AbstractChopListIntention<KtParameterList, Kt
|
||||
}
|
||||
|
||||
class ChopArgumentListIntention : AbstractChopListIntention<KtValueArgumentList, KtValueArgument>(
|
||||
KtValueArgumentList::class.java,
|
||||
KtValueArgument::class.java,
|
||||
"Put arguments on separate lines"
|
||||
KtValueArgumentList::class.java,
|
||||
KtValueArgument::class.java,
|
||||
"Put arguments on separate lines"
|
||||
)
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2010-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.intentions
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
abstract class AbstractJoinListIntention<TList : KtElement, TElement : KtElement>(
|
||||
listClass: Class<TList>,
|
||||
elementClass: Class<TElement>,
|
||||
text: String
|
||||
) : AbstractChopListIntention<TList, TElement>(listClass, elementClass, text) {
|
||||
|
||||
override fun isApplicableTo(element: TList): Boolean {
|
||||
val elements = element.elements()
|
||||
if (elements.isEmpty()) return false
|
||||
return hasLineBreakBefore(elements.first()) || elements.any { hasLineBreakAfter(it) }
|
||||
}
|
||||
|
||||
override fun applyTo(element: TList, editor: Editor?) {
|
||||
val elements = element.elements()
|
||||
prevBreak(elements.first())?.delete()
|
||||
elements.forEach { nextBreak(it)?.delete() }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class JoinParameterListIntention : AbstractJoinListIntention<KtParameterList, KtParameter>(
|
||||
KtParameterList::class.java,
|
||||
KtParameter::class.java,
|
||||
"Put parameters on one line"
|
||||
) {
|
||||
override fun isApplicableTo(element: KtParameterList): Boolean {
|
||||
if (element.parent is KtFunctionLiteral) return false
|
||||
return super.isApplicableTo(element)
|
||||
}
|
||||
}
|
||||
|
||||
class JoinArgumentListIntention : AbstractJoinListIntention<KtValueArgumentList, KtValueArgument>(
|
||||
KtValueArgumentList::class.java,
|
||||
KtValueArgument::class.java,
|
||||
"Put arguments on one line"
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.intentions.JoinArgumentListIntention
|
||||
@@ -0,0 +1,6 @@
|
||||
fun foo(a: Int = 1, b: Int = 1, c: Int = 1) {}
|
||||
|
||||
fun bar(a: Int, b: Int, c: Int) {
|
||||
foo(<caret>
|
||||
a, b, c)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(a: Int = 1, b: Int = 1, c: Int = 1) {}
|
||||
|
||||
fun bar(a: Int, b: Int, c: Int) {
|
||||
foo(a, b, c)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// INTENTION_TEXT: "Put arguments on one line"
|
||||
|
||||
fun foo(a: Int = 1, b: Int = 1, c: Int = 1) {}
|
||||
|
||||
fun bar(a: Int, b: Int, c: Int) {
|
||||
foo(
|
||||
a,
|
||||
b,<caret>
|
||||
c
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// INTENTION_TEXT: "Put arguments on one line"
|
||||
|
||||
fun foo(a: Int = 1, b: Int = 1, c: Int = 1) {}
|
||||
|
||||
fun bar(a: Int, b: Int, c: Int) {
|
||||
foo(a, b, c)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
fun foo(a: Int = 1, b: Int = 1, c: Int = 1) {}
|
||||
|
||||
fun bar(a: Int, b: Int, c: Int) {
|
||||
foo(<caret>)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
fun foo(a: Int = 1, b: Int = 1, c: Int = 1) {}
|
||||
|
||||
fun bar(a: Int, b: Int, c: Int) {
|
||||
foo(a, b, c<caret>)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(a: Int = 1, b: Int = 1, c: Int = 1) {}
|
||||
|
||||
fun bar(a: Int, b: Int, c: Int) {
|
||||
foo(<caret>
|
||||
a
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(a: Int = 1, b: Int = 1, c: Int = 1) {}
|
||||
|
||||
fun bar(a: Int, b: Int, c: Int) {
|
||||
foo(a)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.intentions.JoinParameterListIntention
|
||||
@@ -0,0 +1,2 @@
|
||||
fun test(<caret>
|
||||
a: Int, b: Int, c: Int) {}
|
||||
+1
@@ -0,0 +1 @@
|
||||
fun test(a: Int, b: Int, c: Int) {}
|
||||
@@ -0,0 +1,7 @@
|
||||
// INTENTION_TEXT: "Put parameters on one line"
|
||||
|
||||
fun test(
|
||||
a: Int,
|
||||
b: Int,<caret>
|
||||
c: Int
|
||||
) {}
|
||||
@@ -0,0 +1,3 @@
|
||||
// INTENTION_TEXT: "Put parameters on one line"
|
||||
|
||||
fun test(a: Int, b: Int, c: Int) {}
|
||||
@@ -0,0 +1,3 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
fun test(a: Int, b: Int, c: Int<caret>) {}
|
||||
@@ -0,0 +1,3 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
fun test(<caret>) {}
|
||||
@@ -0,0 +1,3 @@
|
||||
fun test(<caret>
|
||||
a: Int
|
||||
) {}
|
||||
@@ -0,0 +1 @@
|
||||
fun test(a: Int) {}
|
||||
@@ -10048,6 +10048,45 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/joinArgumentList")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class JoinArgumentList extends AbstractIntentionTest {
|
||||
public void testAllFilesPresentInJoinArgumentList() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/joinArgumentList"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("hasLineBreakBeforeFirstArg.kt")
|
||||
public void testHasLineBreakBeforeFirstArg() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinArgumentList/hasLineBreakBeforeFirstArg.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("hasLineBreaks.kt")
|
||||
public void testHasLineBreaks() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinArgumentList/hasLineBreaks.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noArg.kt")
|
||||
public void testNoArg() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinArgumentList/noArg.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noLineBreak.kt")
|
||||
public void testNoLineBreak() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinArgumentList/noLineBreak.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("oneArg.kt")
|
||||
public void testOneArg() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinArgumentList/oneArg.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/joinDeclarationAndAssignment")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -10201,6 +10240,45 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/joinParameterList")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class JoinParameterList extends AbstractIntentionTest {
|
||||
public void testAllFilesPresentInJoinParameterList() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/joinParameterList"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("hasLineBreakBeforeFirstParam.kt")
|
||||
public void testHasLineBreakBeforeFirstParam() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinParameterList/hasLineBreakBeforeFirstParam.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("hasLineBreaks.kt")
|
||||
public void testHasLineBreaks() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinParameterList/hasLineBreaks.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noLineBreak.kt")
|
||||
public void testNoLineBreak() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinParameterList/noLineBreak.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noParam.kt")
|
||||
public void testNoParam() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinParameterList/noParam.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("oneParam.kt")
|
||||
public void testOneParam() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinParameterList/oneParam.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/loopToCallChain")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user