aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Jemerov <yole@jetbrains.com>2015-01-14 18:46:36 +0100
committerDmitry Jemerov <yole@jetbrains.com>2015-01-14 18:46:36 +0100
commit6146fa8b996a7d74f58ce1c926c114bc54bda0d1 (patch)
tree6ccba7e186e1e0de734fc9744274c982d396c0cd
parent60e610ebdd86663bedf113d2235ac3c8364171d0 (diff)
downloaddokka-6146fa8b996a7d74f58ce1c926c114bc54bda0d1.tar.gz
dokka-6146fa8b996a7d74f58ce1c926c114bc54bda0d1.tar.bz2
dokka-6146fa8b996a7d74f58ce1c926c114bc54bda0d1.zip
generate source links in the documentation
-rw-r--r--src/Formats/StructuredFormatService.kt8
-rw-r--r--src/Kotlin/DocumentationBuilder.kt42
-rw-r--r--src/Model/DocumentationNode.kt2
-rw-r--r--src/main.kt28
4 files changed, 76 insertions, 4 deletions
diff --git a/src/Formats/StructuredFormatService.kt b/src/Formats/StructuredFormatService.kt
index bfb69d1d..458fda35 100644
--- a/src/Formats/StructuredFormatService.kt
+++ b/src/Formats/StructuredFormatService.kt
@@ -121,6 +121,7 @@ public abstract class StructuredFormatService(val locationService: LocationServi
appendBlockCode(to, formatText(location, languageService.render(it)))
it.appendOverrides(to)
it.appendDeprecation(to)
+ it.appendSourceLink(to)
}
appendLine(to, summary)
appendLine(to)
@@ -148,6 +149,13 @@ public abstract class StructuredFormatService(val locationService: LocationServi
}
}
+ private fun DocumentationNode.appendSourceLink(to: StringBuilder) {
+ val sourceUrl = details(DocumentationNode.Kind.SourceUrl).firstOrNull()
+ if (sourceUrl != null) {
+ appendLine(to, formatLink("Source", sourceUrl.name))
+ }
+ }
+
fun appendLocation(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
val breakdownByName = nodes.groupBy { node -> node.name }
for ((name, items) in breakdownByName) {
diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt
index 0b978370..4dc81437 100644
--- a/src/Kotlin/DocumentationBuilder.kt
+++ b/src/Kotlin/DocumentationBuilder.kt
@@ -12,8 +12,14 @@ 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
-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 +148,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 +268,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 +300,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 +324,7 @@ 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())
getGetter()?.let {
if (!it.isDefault())
node.appendChild(it, DocumentationReference.Kind.Member)
diff --git a/src/Model/DocumentationNode.kt b/src/Model/DocumentationNode.kt
index 6e707cce..a666b486 100644
--- a/src/Model/DocumentationNode.kt
+++ b/src/Model/DocumentationNode.kt
@@ -97,6 +97,8 @@ public open class DocumentationNode(val name: String,
Annotation
Value
+
+ SourceUrl
}
}
diff --git a/src/main.kt b/src/main.kt
index 24853be5..abe8eda9 100644
--- a/src/main.kt
+++ b/src/main.kt
@@ -6,7 +6,6 @@ import org.jetbrains.kotlin.cli.common.messages.*
import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.name.FqName
class DokkaArguments {
@@ -14,6 +13,10 @@ class DokkaArguments {
ValueDescription("<path>")
public var src: String = ""
+ Argument(value = "srcLink", description = "Mapping between a source directory and a Web site for browsing the code")
+ ValueDescription("<path>=<url>[#lineSuffix]")
+ public var srcLink: String = ""
+
Argument(value = "include", description = "Markdown files to load (allows many paths separated by the system path separator)")
ValueDescription("<path>")
public var include: String = ""
@@ -40,6 +43,15 @@ class DokkaArguments {
}
+class SourceLinkDefinition(val path: String, val url: String, val lineSuffix: String?)
+
+private fun parseSourceLinkDefinition(srcLink: String): SourceLinkDefinition {
+ val urlAndLine = srcLink.substringAfter("=")
+ return SourceLinkDefinition(File(srcLink.substringBefore("=")).getAbsolutePath(),
+ urlAndLine.substringBefore("#"),
+ urlAndLine.substringAfter("#", "").let { if (it.isEmpty()) null else "#" + it })
+}
+
public fun main(args: Array<String>) {
val arguments = DokkaArguments()
val freeArgs: List<String> = Args.parse(arguments, args) ?: listOf()
@@ -47,6 +59,15 @@ public fun main(args: Array<String>) {
val samples = if (arguments.samples.isNotEmpty()) arguments.samples.split(File.pathSeparatorChar).toList() else listOf()
val includes = if (arguments.include.isNotEmpty()) arguments.include.split(File.pathSeparatorChar).toList() else listOf()
+ val sourceLinks = if (arguments.srcLink.isNotEmpty() && arguments.srcLink.contains("="))
+ listOf(parseSourceLinkDefinition(arguments.srcLink))
+ else {
+ if (arguments.srcLink.isNotEmpty()) {
+ println("Warning: Invalid -srcLink syntax. Expected: <path>=<url>[#lineSuffix]. No source links will be generated.")
+ }
+ listOf()
+ }
+
val environment = AnalysisEnvironment(MessageCollectorPlainTextToStream.PLAIN_TEXT_TO_SYSTEM_ERR) {
addClasspath(PathUtil.getJdkClassesRoots())
// addClasspath(PathUtil.getKotlinPathsForCompiler().getRuntimePath())
@@ -79,7 +100,7 @@ public fun main(args: Array<String>) {
}
}
val fragments = fragmentFiles.map { session.getPackageFragment(it.getPackageFqName()) }.filterNotNull().distinct()
- val options = DocumentationOptions()
+ val options = DocumentationOptions(false, sourceLinks)
val documentationBuilder = DocumentationBuilder(session, options)
with(documentationBuilder) {
@@ -133,4 +154,5 @@ public fun main(args: Array<String>) {
println()
println("Done.")
Disposer.dispose(environment)
-} \ No newline at end of file
+}
+