Fix for KT-11032 Samples not rendered in Quick Doc
Now samples included as code blocks into quick doc
This commit is contained in:
@@ -17,14 +17,22 @@
|
||||
package org.jetbrains.kotlin.idea.kdoc
|
||||
|
||||
import com.intellij.codeInsight.documentation.DocumentationManagerUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.intellij.markdown.IElementType
|
||||
import org.intellij.markdown.MarkdownElementTypes
|
||||
import org.intellij.markdown.MarkdownTokenTypes
|
||||
import org.intellij.markdown.ast.ASTNode
|
||||
import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor
|
||||
import org.intellij.markdown.parser.MarkdownParser
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.util.wrapTag
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
|
||||
import org.jetbrains.kotlin.psi.KtBlockExpression
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
||||
|
||||
object KDocRenderer {
|
||||
fun renderKDoc(docComment: KDocTag): String {
|
||||
@@ -47,10 +55,67 @@ object KDocRenderer {
|
||||
renderTag(docComment.findTagByName("since"), "Since", result)
|
||||
|
||||
renderSeeAlso(docComment, result)
|
||||
|
||||
val sampleTags = docComment.findTagsByName("sample").filter { it.getSubjectLink() != null }
|
||||
renderSamplesList(sampleTags, result)
|
||||
}
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
private fun KDocLink.createHyperlink(to: StringBuilder) {
|
||||
DocumentationManagerUtil.createHyperlink(to, getLinkText(), getLinkText(), false)
|
||||
}
|
||||
|
||||
private fun KDocLink.getTargetElement(): PsiElement? {
|
||||
return this.getChildrenOfType<KDocName>().last().mainReference.resolve()
|
||||
}
|
||||
|
||||
private fun PsiElement.extractExampleText() = when (this) {
|
||||
is KtDeclarationWithBody -> {
|
||||
val bodyExpression = bodyExpression
|
||||
when (bodyExpression) {
|
||||
is KtBlockExpression -> bodyExpression.text.removeSurrounding("{", "}")
|
||||
else -> bodyExpression!!.text
|
||||
}
|
||||
}
|
||||
else -> text
|
||||
}
|
||||
|
||||
private fun trimCommonIndent(text: String): String {
|
||||
fun String.leadingIndent() = indexOfFirst { !it.isWhitespace() }
|
||||
|
||||
val lines = text.split('\n')
|
||||
val minIndent = lines.filter { it.trim().isNotEmpty() }.map(String::leadingIndent).min() ?: 0
|
||||
return lines.map { it.drop(minIndent) }.joinToString("\n")
|
||||
}
|
||||
|
||||
|
||||
private fun renderSamplesList(sampleTags: List<KDocTag>, to: StringBuilder) {
|
||||
if (sampleTags.isEmpty()) return
|
||||
to.apply {
|
||||
wrapTag("dl") {
|
||||
append("<dt><b>Samples:</b></dt>")
|
||||
sampleTags.forEach {
|
||||
wrapTag("dd") {
|
||||
it.getSubjectLink()?.let { subjectLink ->
|
||||
subjectLink.createHyperlink(to)
|
||||
val target = subjectLink.getTargetElement()
|
||||
wrapTag("pre") {
|
||||
wrapTag("code") {
|
||||
if (target == null)
|
||||
to.append("// Unresolved")
|
||||
else {
|
||||
to.append(trimCommonIndent(target.extractExampleText()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderSeeAlso(docComment: KDocSection, to: StringBuilder) {
|
||||
val seeTags = docComment.findTagsByName("see")
|
||||
if (seeTags.isEmpty()) return
|
||||
@@ -99,7 +164,8 @@ object KDocRenderer {
|
||||
val maybeSingleParagraph = markdownNode.children.filter { it.type != MarkdownTokenTypes.EOL }.singleOrNull()
|
||||
if (maybeSingleParagraph != null && !allowSingleParagraph) {
|
||||
return maybeSingleParagraph.children.joinToString("") { it.toHtml() }
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return markdownNode.toHtml()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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 org.jetbrains.kotlin.idea.util
|
||||
|
||||
|
||||
inline fun StringBuilder.wrap(prefix: String, postfix: String, crossinline body: () -> Unit) {
|
||||
append(prefix)
|
||||
body()
|
||||
append(postfix)
|
||||
}
|
||||
|
||||
inline fun StringBuilder.wrapTag(tag: String, crossinline body: () -> Unit) {
|
||||
wrap("<$tag>", "</$tag>", body)
|
||||
}
|
||||
|
||||
inline fun StringBuilder.wrapTag(tag: String, params: String, crossinline body: () -> Unit) {
|
||||
wrap("<$tag $params>", "</$tag>", body)
|
||||
}
|
||||
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package magic
|
||||
|
||||
object Samples {
|
||||
fun sampleMagic() {
|
||||
castTextSpell("[asd] [dse] [asz]")
|
||||
}
|
||||
}
|
||||
|
||||
fun sampleScroll() {
|
||||
val reader = Scroll("[asd] [dse] [asz]").reader()
|
||||
castTextSpell(reader.readAll())
|
||||
}
|
||||
|
||||
/**
|
||||
* @sample Samples.sampleMagic
|
||||
* @sample sampleScroll
|
||||
*/
|
||||
fun <caret>castTextSpell(spell: String) {
|
||||
throw SecurityException("Magic prohibited outside Hogwarts")
|
||||
}
|
||||
|
||||
//INFO: <b>public</b> <b>fun</b> castTextSpell(spell: String): Unit <i>defined in</i> magic<br/>
|
||||
//INFO: <dl><dt><b>Samples:</b></dt><dd><a href="psi_element://Samples.sampleMagic"><code>Samples.sampleMagic</code></a><pre><code>
|
||||
//INFO: castTextSpell("[asd] [dse] [asz]")
|
||||
//INFO: </code></pre></dd><dd><a href="psi_element://sampleScroll"><code>sampleScroll</code></a><pre><code>
|
||||
//INFO: val reader = Scroll("[asd] [dse] [asz]").reader()
|
||||
//INFO: castTextSpell(reader.readAll())
|
||||
//INFO: </code></pre></dd></dl>
|
||||
+6
@@ -204,6 +204,12 @@ public class QuickDocProviderTestGenerated extends AbstractQuickDocProviderTest
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Samples.kt")
|
||||
public void testSamples() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/quickDoc/Samples.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TopLevelMethodFromJava.java")
|
||||
public void testTopLevelMethodFromJava() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/quickDoc/TopLevelMethodFromJava.java");
|
||||
|
||||
Reference in New Issue
Block a user