Skip to content
Browse files

allow kdoc to link to the online source code in a source code repo (s…

…uch as github)
  • Loading branch information...
1 parent 37fcffc commit 43261a7172b0531282abda8f678a7ab362af9bf7 @jstrachan jstrachan committed Apr 13, 2012
View
3 libraries/docs/apidoc/pom.xml
@@ -50,7 +50,8 @@
<ignorePackage>junit</ignorePackage>
<ignorePackage>org</ignorePackage>
</ignorePackages>
-
+ <sourceRootHref>https://github.com/JetBrains/kotlin/tree/master</sourceRootHref>
+ <projectRootDir>${project-root}</projectRootDir>
</configuration>
<executions>
View
18 libraries/tools/kdoc-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/doc/KDocMojo.java
@@ -119,6 +119,20 @@
private String version;
/**
+ * The HTTP link to source code
+ *
+ * @parameter expression="${sourceRootHref}"
+ */
+ private String sourceRootHref;
+
+ /**
+ * The root project directory used to deduce relative file names when linking to source code
+ *
+ * @parameter expression="${projectRootDir}" default-value="${project.basedir}"
+ */
+ private String projectRootDir;
+
+ /**
* Whether warnings should be generated if no comments could be found for classes, functions and properties being documented
*
* @parameter expression="${warnNoComments}" default-value="true"
@@ -150,10 +164,14 @@ protected void configureCompilerArguments(CompilerArguments arguments) throws Mo
docConfig.setTitle(title);
docConfig.setVersion(version);
docConfig.setWarnNoComments(warnNoComments);
+ docConfig.setSourceRootHref(sourceRootHref);
+ docConfig.setProjectRootDir(projectRootDir);
getLog().info("API docs output to: " + docConfig.getDocOutputDir());
getLog().info("classpath: " + classpath);
getLog().info("title: " + title);
getLog().info("sources: " + sources);
+ getLog().info("sourceRootHref: " + sourceRootHref);
+ getLog().info("projectRootDir: " + projectRootDir);
getLog().info("API docs ignore packages: " + ignorePackages);
}
else {
View
10 libraries/tools/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/KDocConfig.kt
@@ -42,6 +42,16 @@ class KDocConfig() {
public var warnNoComments: Boolean = true
/**
+ * Returns the HTTP URL of the root directory of source code that we should link to
+ */
+ public var sourceRootHref: String? = null
+
+ /**
+ * The root project directory used to deduce relative file names when linking to source code
+ */
+ public var projectRootDir: String? = null
+
+ /**
* Returns true if protected functions and properties should be documented
*/
public var includeProtected: Boolean = true
View
95 libraries/tools/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/model/KotlinModel.kt
@@ -39,6 +39,10 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiDirectory
import org.jetbrains.jet.lang.descriptors.Visibilities
+import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils
+import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils.LineAndColumn
+import com.intellij.psi.PsiFileSystemItem
+import java.io.File
/**
@@ -190,6 +194,25 @@ class KModel(var context: BindingContext, val config: KDocConfig) {
public val version: String
get() = config.version
+ private var _projectRootDir: String? = null
+
+ /**
+ * Returns the root project directory for calculating relative source links
+ */
+ fun projectRootDir(): String {
+ if (_projectRootDir == null) {
+ val rootDir = config.projectRootDir
+ _projectRootDir = if (rootDir == null) {
+ warning("KDocConfig does not have a projectRootDir defined so we cannot generate relative source Hrefs")
+ ""
+ } else {
+ File(rootDir).getCanonicalPath() ?: ""
+ }
+ }
+ return _projectRootDir ?: ""
+ }
+
+
/** Loads the model from the given set of source files */
fun load(sources: List<JetFile?>): Unit {
val allNamespaces = HashSet<NamespaceDescriptor>()
@@ -344,12 +367,30 @@ class KModel(var context: BindingContext, val config: KDocConfig) {
return null
}
+ fun locationFor(descriptor: DeclarationDescriptor): LineAndColumn? {
+ val psiElement = getPsiElement(descriptor)
+ if (psiElement != null) {
+ val document = psiElement.getContainingFile()?.getViewProvider()?.getDocument()
+ if (document != null) {
+ val offset = psiElement.getTextOffset()
+ return DiagnosticUtils.offsetToLineAndColumn(document, offset)
+ }
+ }
+ return null
+ }
fun fileFor(descriptor: DeclarationDescriptor): String? {
val psiElement = getPsiElement(descriptor)
return psiElement?.getContainingFile()?.getName()
}
+ fun filePath(descriptor: DeclarationDescriptor): String? {
+ val psiElement = getPsiElement(descriptor)
+ val file = psiElement?.getContainingFile()
+ return filePath(file)
+ }
+
+
protected fun getPsiElement(descriptor: DeclarationDescriptor): PsiElement? {
return try {
BindingContextUtils.descriptorToDeclaration(context, descriptor)
@@ -446,6 +487,17 @@ class KModel(var context: BindingContext, val config: KDocConfig) {
return null
}
+ protected fun filePath(file: PsiFileSystemItem?): String? {
+ if (file != null) {
+ var dir = file.getParent()
+ if (dir != null) {
+ val parentName = filePath(dir) ?: ""
+ return parentName + "/" + file.getName()
+ }
+ }
+ return null
+ }
+
/**
* Extracts the block of code within { .. } tokens or returning null if it can't be found
*/
@@ -704,6 +756,39 @@ abstract class KAnnotated(val model: KModel, val declarationDescriptor: Declarat
val file = model.fileFor(declarationDescriptor)
return model.wikiConvert(wikiDescription, TemplateLinkRenderer(this, template), file)
}
+
+ fun isLinkToSourceRepo(): Boolean {
+ return model.config.sourceRootHref != null
+ }
+
+ fun sourceLink(): String {
+ val file = model.filePath(declarationDescriptor)
+ if (file != null) {
+ // lets remove the root project directory
+ val rootDir = model.projectRootDir()
+ val canonicalFile = File(file).getCanonicalPath() ?: ""
+ val relativeFile = if (rootDir != null && canonicalFile.startsWith(rootDir))
+ canonicalFile.substring(rootDir.length()) else canonicalFile
+ return sourceLinkFor(relativeFile!!)
+ }
+ return ""
+ }
+
+ protected fun sourceLinkFor(filePath: String, lineLinkText: String = "#L"): String {
+ val root = model.config.sourceRootHref!!
+ val cleanRoot = root.trimTrailing("/")
+ val cleanPath = filePath.trimLeading("/")
+ return "$cleanRoot/$cleanPath$lineLinkText$sourceLine"
+
+ }
+
+ fun location(): LineAndColumn? = model.locationFor(declarationDescriptor)
+
+ val sourceLine: Int
+ get() {
+ val loc = location()
+ return if (loc != null) loc.getLine() else 1
+ }
}
abstract class KNamed(val name: String, model: KModel, declarationDescriptor: DeclarationDescriptor): KAnnotated(model, declarationDescriptor), Comparable<KNamed> {
@@ -772,6 +857,10 @@ class KPackage(model: KModel, val descriptor: NamespaceDescriptor,
return if (answer.length == 0) "" else answer + "/"
}
+
+
+
+
// TODO generates java.lang.NoSuchMethodError: kotlin.util.namespace.hashMap(Ljet/TypeInfo;Ljet/TypeInfo;)Ljava/util/HashMap;
//val classes = sortedMap<String,KClass>()
public val classMap: SortedMap<String, KClass> = TreeMap<String, KClass>()
@@ -838,8 +927,7 @@ class KClass(val pkg: KPackage, val descriptor: ClassDescriptor,
var since: String = "",
var authors: List<String> = arrayList<String>(),
var baseClasses: List<KType> = arrayList<KType>(),
- var nestedClasses: List<KClass> = arrayList<KClass>(),
- var sourceLine: Int = 2): KClassOrPackage(pkg.model, descriptor), Comparable<KClass> {
+ var nestedClasses: List<KClass> = arrayList<KClass>()): KClassOrPackage(pkg.model, descriptor), Comparable<KClass> {
public override fun compareTo(other: KClass): Int = name.compareTo(other.name)
@@ -921,8 +1009,7 @@ class KFunction(val descriptor: CallableDescriptor, val owner: KClassOrPackage,
var modifiers: List<String> = arrayList<String>(),
var typeParameters: List<KTypeParameter> = arrayList<KTypeParameter>(),
var exceptions: List<KClass> = arrayList<KClass>(),
- var annotations: List<KAnnotation> = arrayList<KAnnotation>(),
- var sourceLine: Int = 2): KAnnotated(owner.model, descriptor), Comparable<KFunction> {
+ var annotations: List<KAnnotation> = arrayList<KAnnotation>()): KAnnotated(owner.model, descriptor), Comparable<KFunction> {
public val parameterTypeText: String = parameters.map{ it.aType.name }.makeString(", ")
View
71 libraries/tools/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/KDocTemplate.kt
@@ -54,30 +54,61 @@ abstract class KDocTemplate() : TextTemplate() {
}
open fun sourceHref(klass: KClass): String {
- val pkg = klass.pkg
- return if (pkg.local) {
- "${pkg.nameAsRelativePath}src-html/${klass.nameAsPath}.html#line.${klass.sourceLine}"
+ if (klass.isLinkToSourceRepo()) {
+ return klass.sourceLink()
} else {
- href(klass)
+ val pkg = klass.pkg
+ return if (pkg.local) {
+ "${pkg.nameAsRelativePath}src-html/${klass.nameAsPath}.html#line.${klass.sourceLine}"
+ } else {
+ href(klass)
+ }
}
}
open fun sourceHref(f: KFunction): String {
- val owner = f.owner
- return if (owner is KClass) {
- val pkg = owner.pkg
- if (pkg.local) {
- "${rootHref(pkg)}src-html/${owner.simpleName}.html#line.${f.sourceLine}"
- } else {
- href(f)
- }
- } else if (owner is KPackage) {
- if (owner.local) {
- // TODO how to find the function in a package???
- "${rootHref(owner)}src-html/namespace.html#line.${f.sourceLine}"
- } else {
- href(owner)
- }
- } else href(f)
+ if (f.isLinkToSourceRepo()) {
+ return f.sourceLink()
+ } else {
+ val owner = f.owner
+ return if (owner is KClass) {
+ val pkg = owner.pkg
+ if (pkg.local) {
+ "${rootHref(pkg)}src-html/${owner.simpleName}.html#line.${f.sourceLine}"
+ } else {
+ href(f)
+ }
+ } else if (owner is KPackage) {
+ if (owner.local) {
+ // TODO how to find the function in a package???
+ "${rootHref(owner)}src-html/namespace.html#line.${f.sourceLine}"
+ } else {
+ href(owner)
+ }
+ } else href(f)
+ }
+ }
+
+ open fun sourceHref(f: KProperty): String {
+ if (f.isLinkToSourceRepo()) {
+ return f.sourceLink()
+ } else {
+ val owner = f.owner
+ return if (owner is KClass) {
+ val pkg = owner.pkg
+ if (pkg.local) {
+ "${rootHref(pkg)}src-html/${owner.simpleName}.html#line.${f.sourceLine}"
+ } else {
+ href(f)
+ }
+ } else if (owner is KPackage) {
+ if (owner.local) {
+ // TODO how to find the function in a package???
+ "${rootHref(owner)}src-html/namespace.html#line.${f.sourceLine}"
+ } else {
+ href(owner)
+ }
+ } else href(f)
+ }
}
open fun link(c: KClass, fullName: Boolean = false): String {
View
2 ...s/tools/kdoc/src/main/kotlin/org/jetbrains/kotlin/doc/templates/PackageTemplateSupport.kt
@@ -207,7 +207,7 @@ abstract class PackageTemplateSupport(open val pkg: KPackage) : KDocTemplate() {
}
*/
println("""</CODE></FONT></TD>""")
- print("""<TD><CODE><B><A HREF="${href(property)}">${property.name}</A></B>: """)
+ print("""<TD><CODE><B><A HREF="${sourceHref(property)}">${property.name}</A></B>: """)
print(link(property.returnType))
//printParameters(property)
println("""</CODE>""")

0 comments on commit 43261a7

Please sign in to comment.
Something went wrong with that request. Please try again.