aboutsummaryrefslogtreecommitdiff
path: root/src/Kotlin
diff options
context:
space:
mode:
Diffstat (limited to 'src/Kotlin')
-rw-r--r--src/Kotlin/DocumentationBuilder.kt57
-rw-r--r--src/Kotlin/KotlinLanguageService.kt12
2 files changed, 66 insertions, 3 deletions
diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt
index 0b978370..6403f14c 100644
--- a/src/Kotlin/DocumentationBuilder.kt
+++ b/src/Kotlin/DocumentationBuilder.kt
@@ -12,8 +12,16 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
+import org.jetbrains.kotlin.resolve.source.getPsi
+import java.io.File
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.psi.PsiNameIdentifierOwner
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.resolve.source.getPsi
+import org.jetbrains.kotlin.psi.JetParameter
-public data class DocumentationOptions(val includeNonPublic: Boolean = false)
+public data class DocumentationOptions(val includeNonPublic: Boolean = false,
+ val sourceLinks: List<SourceLinkDefinition>)
private fun isSamePackage(descriptor1: DeclarationDescriptor, descriptor2: DeclarationDescriptor): Boolean {
val package1 = DescriptorUtils.getParentOfType(descriptor1, javaClass<PackageFragmentDescriptor>())
@@ -142,6 +150,36 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
}
}
+ fun DocumentationNode.appendSourceLink(sourceElement: SourceElement) {
+ val psi = getTargetElement(sourceElement)
+ val path = psi?.getContainingFile()?.getVirtualFile()?.getPath()
+ if (path == null) {
+ return
+ }
+ val absPath = File(path).getAbsolutePath()
+ val linkDef = findSourceLinkDefinition(absPath)
+ if (linkDef != null) {
+ var url = linkDef.url + path.substring(linkDef.path.length())
+ if (linkDef.lineSuffix != null) {
+ val doc = PsiDocumentManager.getInstance(psi!!.getProject()).getDocument(psi.getContainingFile())
+ if (doc != null) {
+ // IJ uses 0-based line-numbers; external source browsers use 1-based
+ val line = doc.getLineNumber(psi.getTextRange().getStartOffset()) + 1
+ url += linkDef.lineSuffix + line.toString()
+ }
+ }
+ append(DocumentationNode(url, Content.Empty, DocumentationNode.Kind.SourceUrl),
+ DocumentationReference.Kind.Detail);
+ }
+ }
+
+ private fun getTargetElement(sourceElement: SourceElement): PsiElement? {
+ val psi = sourceElement.getPsi()
+ return if (psi is PsiNameIdentifierOwner) psi.getNameIdentifier() else psi
+ }
+
+ fun findSourceLinkDefinition(path: String) = options.sourceLinks.firstOrNull { path.startsWith(it.path) }
+
fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: DocumentationReference.Kind) {
// do not include generated code
if (descriptor is CallableMemberDescriptor && descriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION)
@@ -232,6 +270,7 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
DocumentationReference.Kind.Member)
}
node.appendAnnotations(this)
+ node.appendSourceLink(getSource())
register(this, node)
return node
}
@@ -263,6 +302,8 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
node.appendChildren(getValueParameters(), DocumentationReference.Kind.Detail)
node.appendType(getReturnType())
node.appendAnnotations(this)
+ node.appendSourceLink(getSource())
+
register(this, node)
return node
@@ -285,6 +326,11 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
getExtensionReceiverParameter()?.let { node.appendChild(it, DocumentationReference.Kind.Detail) }
node.appendType(getReturnType())
node.appendAnnotations(this)
+ node.appendSourceLink(getSource())
+ if (isVar()) {
+ node.append(DocumentationNode("var", Content.Empty, DocumentationNode.Kind.Modifier),
+ DocumentationReference.Kind.Detail)
+ }
getGetter()?.let {
if (!it.isDefault())
node.appendChild(it, DocumentationReference.Kind.Member)
@@ -307,6 +353,15 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
} else {
node.appendType(getType())
}
+ if (hasDefaultValue()) {
+ val psi = getSource().getPsi() as? JetParameter
+ if (psi != null) {
+ val defaultValueText = psi.getDefaultValue()?.getText()
+ if (defaultValueText != null) {
+ node.append(DocumentationNode(defaultValueText, Content.Empty, Kind.Value), DocumentationReference.Kind.Detail)
+ }
+ }
+ }
node.appendAnnotations(this)
register(this, node)
return node
diff --git a/src/Kotlin/KotlinLanguageService.kt b/src/Kotlin/KotlinLanguageService.kt
index f598a38e..b7723285 100644
--- a/src/Kotlin/KotlinLanguageService.kt
+++ b/src/Kotlin/KotlinLanguageService.kt
@@ -109,7 +109,7 @@ class KotlinLanguageService : LanguageService {
private fun ContentNode.renderModifier(node: DocumentationNode) {
when (node.name) {
- "final", "internal" -> {}
+ "final", "internal", "var" -> {}
else -> {
keyword(node.name)
text(" ")
@@ -134,6 +134,11 @@ class KotlinLanguageService : LanguageService {
symbol(": ")
val parameterType = node.detail(DocumentationNode.Kind.Type)
renderType(parameterType)
+ val valueNode = node.details(DocumentationNode.Kind.Value).firstOrNull()
+ if (valueNode != null) {
+ symbol(" = ")
+ text(valueNode.name)
+ }
}
private fun ContentNode.renderTypeParametersForNode(node: DocumentationNode) {
@@ -245,7 +250,7 @@ class KotlinLanguageService : LanguageService {
renderAnnotationsForNode(node)
when (node.kind) {
DocumentationNode.Kind.Property,
- DocumentationNode.Kind.ClassObjectProperty -> keyword("val ")
+ DocumentationNode.Kind.ClassObjectProperty -> keyword("${node.getPropertyKeyword()} ")
else -> throw IllegalArgumentException("Node $node is not a property")
}
renderTypeParametersForNode(node)
@@ -260,6 +265,9 @@ class KotlinLanguageService : LanguageService {
renderType(node.detail(DocumentationNode.Kind.Type))
}
+ fun DocumentationNode.getPropertyKeyword() =
+ if (details(DocumentationNode.Kind.Modifier).any { it.name == "var" }) "var" else "val"
+
fun ContentNode.identifierOrDeprecated(node: DocumentationNode) {
if (node.deprecation != null) {
val strike = ContentStrikethrough()