Merge pull request #552 from JetBrains/rr/yole/kdoc-generate
structured rendering of doc comments in quick documentation dialog
This commit is contained in:
@@ -45,11 +45,12 @@ public enum KDocKnownTag {
|
||||
|
||||
public static KDocKnownTag findByTagName(String tagName) {
|
||||
if (tagName.startsWith("@")) {
|
||||
try {
|
||||
return valueOf(tagName.substring(1).toUpperCase());
|
||||
}
|
||||
catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
tagName = tagName.substring(1);
|
||||
}
|
||||
try {
|
||||
return valueOf(tagName.toUpperCase());
|
||||
}
|
||||
catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+9
-6
@@ -14,13 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kdoc.psi.impl;
|
||||
package org.jetbrains.kotlin.kdoc.psi.impl
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.intellij.lang.ASTNode
|
||||
|
||||
public class KDocLink extends KDocElementImpl {
|
||||
public KDocLink(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
public class KDocLink(node: ASTNode) : KDocElementImpl(node) {
|
||||
fun getLinkText(): String {
|
||||
val text = getText()
|
||||
if (text.startsWith('[') && text.endsWith(']')) {
|
||||
return text.substring(1, text.length() - 1)
|
||||
}
|
||||
return text
|
||||
}
|
||||
}
|
||||
+13
-6
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kdoc.psi.impl;
|
||||
package org.jetbrains.kotlin.kdoc.psi.impl
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
|
||||
/**
|
||||
* The part of a doc comment which describes a single class, method or property
|
||||
@@ -25,8 +25,15 @@ import org.jetbrains.annotations.NotNull;
|
||||
* can have sections for the class itself, its primary constructor and each of the
|
||||
* properties defined in the primary constructor.
|
||||
*/
|
||||
public class KDocSection extends KDocTag {
|
||||
public KDocSection(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
public class KDocSection(node: ASTNode) : KDocTag(node) {
|
||||
public fun findTagsByName(name: String): List<KDocTag> {
|
||||
val tags = PsiTreeUtil.getChildrenOfType<KDocTag>(this, javaClass<KDocTag>())
|
||||
if (tags == null) {
|
||||
return listOf()
|
||||
}
|
||||
return tags.filter { it.getName() == name }
|
||||
}
|
||||
|
||||
public fun findTagByName(name: String): KDocTag?
|
||||
= findTagsByName(name).firstOrNull()
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kdoc.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.kdoc.lexer.KDocTokens;
|
||||
import org.jetbrains.kotlin.kdoc.parser.KDocElementTypes;
|
||||
|
||||
public class KDocTag extends KDocElementImpl {
|
||||
public KDocTag(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
boolean contentStarted = false;
|
||||
boolean afterAsterisk = false;
|
||||
boolean startsWithTagName = false;
|
||||
|
||||
ASTNode[] children = getNode().getChildren(null);
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
ASTNode node = children[i];
|
||||
IElementType type = node.getElementType();
|
||||
if (i == 0 && type == KDocTokens.TAG_NAME) {
|
||||
startsWithTagName = true;
|
||||
}
|
||||
if (KDocTokens.CONTENT_TOKENS.contains(type) || type == KDocElementTypes.KDOC_LINK) {
|
||||
contentStarted = true;
|
||||
builder.append(afterAsterisk ? StringUtil.trimLeading(node.getText()) : node.getText());
|
||||
afterAsterisk = false;
|
||||
}
|
||||
|
||||
if (type == KDocTokens.LEADING_ASTERISK) {
|
||||
afterAsterisk = true;
|
||||
}
|
||||
|
||||
if (type == TokenType.WHITE_SPACE) {
|
||||
if (i == 1 && startsWithTagName) {
|
||||
builder.append(node.getText());
|
||||
}
|
||||
else if (contentStarted) {
|
||||
builder.append(StringUtil.repeat("\n", StringUtil.countNewLines(node.getText())));
|
||||
}
|
||||
}
|
||||
|
||||
if (type == KDocElementTypes.KDOC_TAG) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public String getContentWithTags() {
|
||||
StringBuilder content = new StringBuilder(getContent());
|
||||
KDocTag[] subTags = PsiTreeUtil.getChildrenOfType(this, KDocTag.class);
|
||||
if (subTags != null) {
|
||||
for (KDocTag tag : subTags) {
|
||||
content.append(tag.getContentWithTags()).append("\n");
|
||||
}
|
||||
}
|
||||
return content.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kdoc.psi.impl
|
||||
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.TokenType
|
||||
import org.jetbrains.kotlin.kdoc.lexer.KDocTokens
|
||||
import org.jetbrains.kotlin.kdoc.parser.KDocElementTypes
|
||||
import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
|
||||
|
||||
public open class KDocTag(node: ASTNode) : KDocElementImpl(node) {
|
||||
|
||||
/**
|
||||
* Returns the name of this tag, not including the leading @ character.
|
||||
*
|
||||
* @return tag name or null if this tag represents the default section of a doc comment
|
||||
* or the code has a syntax error.
|
||||
*/
|
||||
override fun getName(): String? {
|
||||
val tagName = findChildByType(KDocTokens.TAG_NAME)
|
||||
if (tagName != null) {
|
||||
return tagName.getText().substring(1)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the entity documented by this tag (for example, the name of the parameter
|
||||
* for the @param tag), or null if this tag does not document any specific entity.
|
||||
*/
|
||||
public fun getSubjectName(): String? {
|
||||
val children = childrenAfterTagName()
|
||||
if (hasSubject(children)) {
|
||||
return (children.firstOrNull()?.getPsi() as? KDocLink)?.getLinkText()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun hasSubject(contentChildren: List<ASTNode>): Boolean {
|
||||
val name = getName()
|
||||
val knownTag = if (name != null) KDocKnownTag.findByTagName(name) else null
|
||||
if (knownTag?.isReferenceRequired() ?: false) {
|
||||
return contentChildren.firstOrNull()?.getElementType() == KDocElementTypes.KDOC_LINK;
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun childrenAfterTagName(): List<ASTNode> =
|
||||
getNode().getChildren(null)
|
||||
.dropWhile { it.getElementType() == KDocTokens.TAG_NAME }
|
||||
.dropWhile { it.getElementType() == TokenType.WHITE_SPACE }
|
||||
|
||||
public fun getContent(): String {
|
||||
val builder = StringBuilder()
|
||||
|
||||
var contentStarted = false
|
||||
var afterAsterisk = false
|
||||
|
||||
var children = childrenAfterTagName()
|
||||
if (hasSubject(children)) {
|
||||
children = children.drop(1)
|
||||
}
|
||||
for (node in children) {
|
||||
val type = node.getElementType()
|
||||
if (KDocTokens.CONTENT_TOKENS.contains(type) || type == KDocElementTypes.KDOC_LINK) {
|
||||
contentStarted = true
|
||||
builder.append(if (afterAsterisk) StringUtil.trimLeading(node.getText()) else node.getText())
|
||||
afterAsterisk = false
|
||||
}
|
||||
if (type == KDocTokens.LEADING_ASTERISK) {
|
||||
afterAsterisk = true
|
||||
}
|
||||
if (type == TokenType.WHITE_SPACE && contentStarted) {
|
||||
builder.append(StringUtil.repeat("\n", StringUtil.countNewLines(node.getText())))
|
||||
}
|
||||
if (type == KDocElementTypes.KDOC_TAG) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user