Add intention for converting to block comment and vise versa

So #KT-23137 Fixed
This commit is contained in:
Toshiaki Kameyama
2018-04-19 11:12:29 +03:00
committed by Mikhail Glukhikh
parent 3351b00870
commit e58d9c5507
45 changed files with 488 additions and 0 deletions
@@ -153,6 +153,10 @@ fun PsiElement.getPrevSiblingIgnoringWhitespaceAndComments(withItself: Boolean =
return siblings(withItself = withItself, forward = false).filter { it !is PsiWhiteSpace && it !is PsiComment }.firstOrNull()
}
fun PsiElement.getPrevSiblingIgnoringWhitespace(withItself: Boolean = false): PsiElement? {
return siblings(withItself = withItself, forward = false).filter { it !is PsiWhiteSpace }.firstOrNull()
}
inline fun <reified T : PsiElement> T.nextSiblingOfSameType() = PsiTreeUtil.getNextSiblingOfType(this, T::class.java)
inline fun <reified T : PsiElement> T.prevSiblingOfSameType() = PsiTreeUtil.getPrevSiblingOfType(this, T::class.java)
@@ -0,0 +1,3 @@
<spot>// comment1
// comment2</spot>
val foo = 1
@@ -0,0 +1,5 @@
<spot>/*
comment1
comment2
*/</spot>
val foo = 1
@@ -0,0 +1,5 @@
<html>
<body>
This intention replaces a block comment with one or more end-of-line comments.
</body>
</html>
@@ -0,0 +1,5 @@
<spot>/*
comment1
comment2
*/</spot>
val foo = 1
@@ -0,0 +1,3 @@
<spot>// comment1
// comment2</spot>
val foo = 1
@@ -0,0 +1,5 @@
<html>
<body>
This intention replaces one or more end-of-line comments with a block comment.
</body>
</html>
+10
View File
@@ -1582,6 +1582,16 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertLineCommentToBlockCommentIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertBlockCommentToLineCommentIntention</className>
<category>Kotlin</category>
</intentionAction>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
displayName="Object literal can be converted to lambda"
groupPath="Kotlin"
+10
View File
@@ -1582,6 +1582,16 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertLineCommentToBlockCommentIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertBlockCommentToLineCommentIntention</className>
<category>Kotlin</category>
</intentionAction>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
displayName="Object literal can be converted to lambda"
groupPath="Kotlin"
+10
View File
@@ -1582,6 +1582,16 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertLineCommentToBlockCommentIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertBlockCommentToLineCommentIntention</className>
<category>Kotlin</category>
</intentionAction>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
displayName="Object literal can be converted to lambda"
groupPath="Kotlin"
+10
View File
@@ -1583,6 +1583,16 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertLineCommentToBlockCommentIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertBlockCommentToLineCommentIntention</className>
<category>Kotlin</category>
</intentionAction>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
displayName="Object literal can be converted to lambda"
groupPath="Kotlin"
+10
View File
@@ -1582,6 +1582,16 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertLineCommentToBlockCommentIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertBlockCommentToLineCommentIntention</className>
<category>Kotlin</category>
</intentionAction>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
displayName="Object literal can be converted to lambda"
groupPath="Kotlin"
+10
View File
@@ -1582,6 +1582,16 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertLineCommentToBlockCommentIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertBlockCommentToLineCommentIntention</className>
<category>Kotlin</category>
</intentionAction>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
displayName="Object literal can be converted to lambda"
groupPath="Kotlin"
@@ -0,0 +1,49 @@
/*
* 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 com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtPsiFactory
class ConvertBlockCommentToLineCommentIntention : SelfTargetingIntention<PsiComment>(
PsiComment::class.java, "Replace with end of line comment"
) {
override fun isApplicableTo(element: PsiComment, caretOffset: Int): Boolean {
return element.isBlockComment()
}
override fun applyTo(element: PsiComment, editor: Editor?) {
val psiFactory = KtPsiFactory(element)
val prevSibling = element.prevSibling
val indent = if (prevSibling is PsiWhiteSpace) {
val space = prevSibling.text.reversed().takeWhile { it == ' ' || it == '\t' }
psiFactory.createWhiteSpace("\n$space")
} else {
psiFactory.createNewLine()
}
val comments = element.text
.substring(2, element.text.length - 2)
.trim()
.split("\n")
.reversed()
val lastIndex = comments.size - 1
val parent = element.parent
comments.forEachIndexed { index, comment ->
val commentText = comment.trim().let { if (it.isEmpty()) "//" else "// $it" }
parent.addAfter(psiFactory.createComment(commentText), element)
if (index != lastIndex) parent.addAfter(indent, element)
}
element.delete()
}
}
private fun PsiElement.isBlockComment() = node.elementType == KtTokens.BLOCK_COMMENT
@@ -0,0 +1,67 @@
/*
* 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 com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespace
import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespace
class ConvertLineCommentToBlockCommentIntention : SelfTargetingIntention<PsiComment>(
PsiComment::class.java, "Replace with block comment"
) {
override fun isApplicableTo(element: PsiComment, caretOffset: Int): Boolean {
return element.isEndOfLineComment()
}
override fun applyTo(element: PsiComment, editor: Editor?) {
var firstComment = element
while (true) {
firstComment = firstComment.prevComment() ?: break
}
val indent = (firstComment.prevSibling as? PsiWhiteSpace)?.text?.reversed()?.takeWhile { it == ' ' || it == '\t' } ?: ""
val comments = mutableListOf(firstComment)
var nextComment = firstComment
while (true) {
nextComment = nextComment.nextComment() ?: break
comments.add(nextComment)
}
val blockComment = if (comments.size == 1)
"/* ${comments.first().commentText()} */"
else
comments.joinToString(separator = "\n", prefix = "/*\n", postfix = "\n$indent*/") {
"$indent${it.commentText()}"
}
comments.drop(1).forEach {
(it.prevSibling as? PsiWhiteSpace)?.delete()
it.delete()
}
firstComment.replace(KtPsiFactory(element).createComment(blockComment))
}
}
private fun PsiElement.isEndOfLineComment() = node.elementType == KtTokens.EOL_COMMENT
private fun PsiComment.commentText() = text.substring(2).replace("/*", "/ *").replace("*/", "* /").trim()
private fun PsiComment.nextComment(): PsiComment? {
return (getNextSiblingIgnoringWhitespace() as? PsiComment)?.takeIf { it.isEndOfLineComment() }
}
private fun PsiComment.prevComment(): PsiComment? {
return (getPrevSiblingIgnoringWhitespace() as? PsiComment)?.takeIf { it.isEndOfLineComment() }
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.intentions.ConvertBlockCommentToLineCommentIntention
@@ -0,0 +1,3 @@
fun test() {
val foo = 1 /* comment */<caret>
}
@@ -0,0 +1,3 @@
fun test() {
val foo = 1 // comment
}
@@ -0,0 +1,3 @@
fun test() {
/* comment */<caret> val foo = 1
}
@@ -0,0 +1,4 @@
fun test() {
// comment
val foo = 1
}
@@ -0,0 +1,11 @@
fun test() {
/*
comment1
comment2
comment3
*/<caret>
val foo = 1
}
@@ -0,0 +1,8 @@
fun test() {
// comment1
//
// comment2
//
// comment3
val foo = 1
}
@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
fun test() {
/**
* comment
*/<caret>
val foo = 1
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
fun test() {
// comment<caret>
val foo = 1
}
@@ -0,0 +1,9 @@
fun foo() {}
/*
comment
*/<caret>
fun bar() {}
@@ -0,0 +1,7 @@
fun foo() {}
// comment
fun bar() {}
@@ -0,0 +1,7 @@
fun test() {
/*
comment1
comment2
*/<caret>
val foo = 1
}
@@ -0,0 +1,5 @@
fun test() {
// comment1
// comment2
val foo = 1
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.intentions.ConvertLineCommentToBlockCommentIntention
@@ -0,0 +1,4 @@
fun test() {
val foo = 1 // comment1<caret>
// comment2
}
@@ -0,0 +1,4 @@
fun test() {
val foo = 1 /* comment1 */
// comment2
}
@@ -0,0 +1,12 @@
fun test() {
// comment1
//
// comment2<caret>
//
// comment3
val foo = 1
}
@@ -0,0 +1,10 @@
fun test() {
/*
comment1
comment2
comment3
*/
val foo = 1
}
@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
fun test() {
/*
comment
*/<caret>
val foo = 1
}
@@ -0,0 +1,5 @@
fun test(): Int {
// /* comment<caret>
val foo = 1
return foo
}
@@ -0,0 +1,5 @@
fun test(): Int {
/* / * comment */
val foo = 1
return foo
}
@@ -0,0 +1,5 @@
fun test2(): Int {
// comment */<caret>
val foo = 1
return foo
}
@@ -0,0 +1,5 @@
fun test2(): Int {
/* comment * / */
val foo = 1
return foo
}
@@ -0,0 +1,9 @@
fun foo() {}
// comment1
// comment2
// comment3<caret>
fun bar() {}
@@ -0,0 +1,11 @@
fun foo() {}
/*
comment1
comment2
comment3
*/
fun bar() {}
@@ -0,0 +1,6 @@
fun test() {
val foo = 1
// comment1<caret>
val bar = 1
}
@@ -0,0 +1,6 @@
fun test() {
val foo = 1
/* comment1 */
val bar = 1
}
@@ -0,0 +1,8 @@
fun test() {
val foo = 1
// comment1
// comment2<caret>
// comment3
val bar = 1
}
@@ -0,0 +1,10 @@
fun test() {
val foo = 1
/*
comment1
comment2
comment3
*/
val bar = 1
}
@@ -4210,6 +4210,54 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
@TestMetadata("idea/testData/intentions/convertBlockCommentToLineComment")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ConvertBlockCommentToLineComment extends AbstractIntentionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
@TestMetadata("afterStatement.kt")
public void testAfterStatement() throws Exception {
runTest("idea/testData/intentions/convertBlockCommentToLineComment/afterStatement.kt");
}
public void testAllFilesPresentInConvertBlockCommentToLineComment() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertBlockCommentToLineComment"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("beforeStatement.kt")
public void testBeforeStatement() throws Exception {
runTest("idea/testData/intentions/convertBlockCommentToLineComment/beforeStatement.kt");
}
@TestMetadata("blankLine.kt")
public void testBlankLine() throws Exception {
runTest("idea/testData/intentions/convertBlockCommentToLineComment/blankLine.kt");
}
@TestMetadata("docComment.kt")
public void testDocComment() throws Exception {
runTest("idea/testData/intentions/convertBlockCommentToLineComment/docComment.kt");
}
@TestMetadata("endOflineComment.kt")
public void testEndOflineComment() throws Exception {
runTest("idea/testData/intentions/convertBlockCommentToLineComment/endOflineComment.kt");
}
@TestMetadata("newLinesBetweenCommentAndDeclaration.kt")
public void testNewLinesBetweenCommentAndDeclaration() throws Exception {
runTest("idea/testData/intentions/convertBlockCommentToLineComment/newLinesBetweenCommentAndDeclaration.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("idea/testData/intentions/convertBlockCommentToLineComment/simple.kt");
}
}
@TestMetadata("idea/testData/intentions/convertCamelCaseTestFunctionToSpaced")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -5127,6 +5175,59 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
@TestMetadata("idea/testData/intentions/convertLineCommentToBlockComment")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ConvertLineCommentToBlockComment extends AbstractIntentionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
@TestMetadata("afterStatement.kt")
public void testAfterStatement() throws Exception {
runTest("idea/testData/intentions/convertLineCommentToBlockComment/afterStatement.kt");
}
public void testAllFilesPresentInConvertLineCommentToBlockComment() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertLineCommentToBlockComment"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("blankLine.kt")
public void testBlankLine() throws Exception {
runTest("idea/testData/intentions/convertLineCommentToBlockComment/blankLine.kt");
}
@TestMetadata("blockComment.kt")
public void testBlockComment() throws Exception {
runTest("idea/testData/intentions/convertLineCommentToBlockComment/blockComment.kt");
}
@TestMetadata("includeBlockComment.kt")
public void testIncludeBlockComment() throws Exception {
runTest("idea/testData/intentions/convertLineCommentToBlockComment/includeBlockComment.kt");
}
@TestMetadata("includeBlockComment2.kt")
public void testIncludeBlockComment2() throws Exception {
runTest("idea/testData/intentions/convertLineCommentToBlockComment/includeBlockComment2.kt");
}
@TestMetadata("newLinesBetweenCommentAndDeclaration.kt")
public void testNewLinesBetweenCommentAndDeclaration() throws Exception {
runTest("idea/testData/intentions/convertLineCommentToBlockComment/newLinesBetweenCommentAndDeclaration.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("idea/testData/intentions/convertLineCommentToBlockComment/simple.kt");
}
@TestMetadata("simple2.kt")
public void testSimple2() throws Exception {
runTest("idea/testData/intentions/convertLineCommentToBlockComment/simple2.kt");
}
}
@TestMetadata("idea/testData/intentions/convertNegatedBooleanSequence")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)