allow kdoc to link to the online source code in a source code repo (such as github)
This commit is contained in:
@@ -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>
|
||||
|
||||
+18
@@ -118,6 +118,20 @@ public class KDocMojo extends KotlinCompileMojoBase {
|
||||
*/
|
||||
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
|
||||
*
|
||||
@@ -150,10 +164,14 @@ public class KDocMojo extends KotlinCompileMojoBase {
|
||||
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 {
|
||||
|
||||
@@ -41,6 +41,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
|
||||
*/
|
||||
|
||||
@@ -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(", ")
|
||||
|
||||
|
||||
+51
-20
@@ -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 {
|
||||
|
||||
Vendored
+1
-1
@@ -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>""")
|
||||
|
||||
Reference in New Issue
Block a user