aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Jemerov <yole@jetbrains.com>2015-02-20 14:08:30 +0100
committerDmitry Jemerov <yole@jetbrains.com>2015-02-20 14:08:30 +0100
commit85a3ae7626810113816fd31a0e26d44d48308ed2 (patch)
tree837eae154a30f139449f560d5e1afebf113041ee
parentea1f4cc2987536c3ed3df5899e6cec2df890f1e6 (diff)
downloaddokka-85a3ae7626810113816fd31a0e26d44d48308ed2.tar.gz
dokka-85a3ae7626810113816fd31a0e26d44d48308ed2.tar.bz2
dokka-85a3ae7626810113816fd31a0e26d44d48308ed2.zip
support in-page anchors in locations
-rw-r--r--src/Formats/HtmlFormatService.kt4
-rw-r--r--src/Formats/MarkdownFormatService.kt4
-rw-r--r--src/Formats/StructuredFormatService.kt12
-rw-r--r--src/Kotlin/DocumentationBuilder.kt30
-rw-r--r--src/Locations/LocationService.kt9
-rw-r--r--src/Model/DocumentationReference.kt1
-rw-r--r--test/data/format/overloadsWithDescription.html3
-rw-r--r--test/data/format/overloadsWithDifferentDescriptions.html2
-rw-r--r--test/data/format/parameterAnchor.html17
-rw-r--r--test/data/format/parameterAnchor.kt6
-rw-r--r--test/src/TestAPI.kt3
-rw-r--r--test/src/format/HtmlFormatTest.kt6
12 files changed, 81 insertions, 16 deletions
diff --git a/src/Formats/HtmlFormatService.kt b/src/Formats/HtmlFormatService.kt
index 733425d7..d5331422 100644
--- a/src/Formats/HtmlFormatService.kt
+++ b/src/Formats/HtmlFormatService.kt
@@ -50,6 +50,10 @@ public open class HtmlFormatService(locationService: LocationService,
to.appendln("<br/>")
}
+ override fun appendAnchor(to: StringBuilder, anchor: String) {
+ to.appendln("<a name=\"${anchor.htmlEscape()}\"></a>")
+ }
+
override fun appendTable(to: StringBuilder, body: () -> Unit) {
to.appendln("<table>")
body()
diff --git a/src/Formats/MarkdownFormatService.kt b/src/Formats/MarkdownFormatService.kt
index 281ca21d..2bd12c53 100644
--- a/src/Formats/MarkdownFormatService.kt
+++ b/src/Formats/MarkdownFormatService.kt
@@ -59,6 +59,10 @@ public open class MarkdownFormatService(locationService: LocationService,
to.appendln(text)
}
+ override fun appendAnchor(to: StringBuilder, anchor: String) {
+ // no anchors in Markdown
+ }
+
override public fun appendParagraph(to: StringBuilder, text: String) {
to.appendln()
to.appendln(text)
diff --git a/src/Formats/StructuredFormatService.kt b/src/Formats/StructuredFormatService.kt
index 14eb490a..d2e2436b 100644
--- a/src/Formats/StructuredFormatService.kt
+++ b/src/Formats/StructuredFormatService.kt
@@ -16,6 +16,7 @@ public abstract class StructuredFormatService(locationService: LocationService,
abstract public fun appendParagraph(to: StringBuilder, text: String)
abstract public fun appendLine(to: StringBuilder, text: String)
public abstract fun appendLine(to: StringBuilder)
+ public abstract fun appendAnchor(to: StringBuilder, anchor: String)
public abstract fun appendTable(to: StringBuilder, body: () -> Unit)
public abstract fun appendTableHeader(to: StringBuilder, body: () -> Unit)
@@ -56,7 +57,7 @@ public abstract class StructuredFormatService(locationService: LocationService,
is ContentListItem -> append(formatListItem(formatText(location, content.children)))
is ContentNodeLink -> {
- val linkTo = location.relativePathTo(locationService.location(content.node))
+ val linkTo = locationHref(location, content.node)
val linkText = formatText(location, content.children)
append(formatLink(linkText, linkTo))
}
@@ -81,6 +82,14 @@ public abstract class StructuredFormatService(locationService: LocationService,
return FormatLink(to.name, locationService.relativePathToLocation(from, to))
}
+ fun locationHref(from: Location, to: DocumentationNode): String {
+ val topLevelPage = to.references(DocumentationReference.Kind.TopLevelPage).singleOrNull()?.to
+ if (topLevelPage != null) {
+ return from.relativePathTo(locationService.location(topLevelPage), to.name)
+ }
+ return from.relativePathTo(locationService.location(to))
+ }
+
fun appendDocumentation(location: Location, to: StringBuilder, overloads: Iterable<DocumentationNode>) {
val breakdownBySummary = overloads.groupByTo(LinkedHashMap()) { node -> node.content }
@@ -124,6 +133,7 @@ public abstract class StructuredFormatService(locationService: LocationService,
subjectSections.forEach {
val subjectName = it.subjectName
if (subjectName != null) {
+ appendAnchor(to, subjectName)
to.append(formatCode(subjectName)).append(" - ")
to.append(formatText(location, it))
appendLine(to)
diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt
index 0ad93801..861e0a7b 100644
--- a/src/Kotlin/DocumentationBuilder.kt
+++ b/src/Kotlin/DocumentationBuilder.kt
@@ -185,22 +185,34 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
appendSourceLink(sourceElement.getPsi(), options.sourceLinks)
}
- fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: DocumentationReference.Kind) {
+ fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: DocumentationReference.Kind): DocumentationNode? {
// do not include generated code
if (descriptor is CallableMemberDescriptor && descriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION)
- return
+ return null
if (options.includeNonPublic
|| descriptor !is MemberDescriptor
|| descriptor.getVisibility() in visibleToDocumentation) {
- append(descriptor.build(), kind)
+ val node = descriptor.build()
+ append(node, kind)
+ return node
}
+ return null
}
fun DocumentationNode.appendChildren(descriptors: Iterable<DeclarationDescriptor>, kind: DocumentationReference.Kind) {
descriptors.forEach { descriptor -> appendChild(descriptor, kind) }
}
+ fun DocumentationNode.appendInPageChildren(descriptors: Iterable<DeclarationDescriptor>, kind: DocumentationReference.Kind) {
+ descriptors.forEach { descriptor ->
+ val node = appendChild(descriptor, kind)
+ if (node != null) {
+ node.addReferenceTo(this, DocumentationReference.Kind.TopLevelPage)
+ }
+ }
+ }
+
fun DocumentationNode.getParentForPackageMember(descriptor: DeclarationDescriptor,
externalClassNodes: MutableMap<FqName, DocumentationNode>): DocumentationNode {
if (descriptor is CallableMemberDescriptor) {
@@ -263,7 +275,7 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
}
node.appendSupertypes(this)
if (getKind() != ClassKind.OBJECT && getKind() != ClassKind.ENUM_ENTRY) {
- node.appendChildren(getTypeConstructor().getParameters(), DocumentationReference.Kind.Detail)
+ node.appendInPageChildren(getTypeConstructor().getParameters(), DocumentationReference.Kind.Detail)
val constructorsToDocument = if (getKind() == ClassKind.ENUM_CLASS)
getConstructors().filter { it.getValueParameters().size() > 0 }
else
@@ -285,7 +297,7 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
fun ConstructorDescriptor.build(): DocumentationNode {
val node = DocumentationNode(this, Kind.Constructor)
- node.appendChildren(getValueParameters(), DocumentationReference.Kind.Detail)
+ node.appendInPageChildren(getValueParameters(), DocumentationReference.Kind.Detail)
register(this, node)
return node
}
@@ -305,9 +317,9 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
fun FunctionDescriptor.build(): DocumentationNode {
val node = DocumentationNode(this, if (inClassObject()) Kind.DefaultObjectFunction else Kind.Function)
- node.appendChildren(getTypeParameters(), DocumentationReference.Kind.Detail)
+ node.appendInPageChildren(getTypeParameters(), DocumentationReference.Kind.Detail)
getExtensionReceiverParameter()?.let { node.appendChild(it, DocumentationReference.Kind.Detail) }
- node.appendChildren(getValueParameters(), DocumentationReference.Kind.Detail)
+ node.appendInPageChildren(getValueParameters(), DocumentationReference.Kind.Detail)
node.appendType(getReturnType())
node.appendAnnotations(this)
node.appendSourceLink(getSource())
@@ -322,7 +334,7 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
val specialName = getName().asString().drop(1).takeWhile { it != '-' }
val node = DocumentationNode(specialName, doc, Kind.PropertyAccessor).withModifiers(this)
- node.appendChildren(getValueParameters(), DocumentationReference.Kind.Detail)
+ node.appendInPageChildren(getValueParameters(), DocumentationReference.Kind.Detail)
node.appendType(getReturnType())
register(this, node)
return node
@@ -330,7 +342,7 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati
fun PropertyDescriptor.build(): DocumentationNode {
val node = DocumentationNode(this, if (inClassObject()) Kind.DefaultObjectProperty else Kind.Property)
- node.appendChildren(getTypeParameters(), DocumentationReference.Kind.Detail)
+ node.appendInPageChildren(getTypeParameters(), DocumentationReference.Kind.Detail)
getExtensionReceiverParameter()?.let { node.appendChild(it, DocumentationReference.Kind.Detail) }
node.appendType(getReturnType())
node.appendAnnotations(this)
diff --git a/src/Locations/LocationService.kt b/src/Locations/LocationService.kt
index 96cd0c51..500b89f2 100644
--- a/src/Locations/LocationService.kt
+++ b/src/Locations/LocationService.kt
@@ -4,7 +4,7 @@ import java.io.File
public trait Location {
val path: String get
- fun relativePathTo(other: Location): String
+ fun relativePathTo(other: Location, anchor: String? = null): String
}
/**
@@ -19,12 +19,13 @@ public data class FileLocation(val file: File): Location {
override val path : String
get() = file.path
- override fun relativePathTo(other: Location): String {
+ override fun relativePathTo(other: Location, anchor: String?): String {
if (other !is FileLocation) {
throw IllegalArgumentException("$other is not a FileLocation")
}
val ownerFolder = file.getParentFile()!!
- return ownerFolder.getRelativePath(other.file).path
+ val relativePath = ownerFolder.getRelativePath(other.file).path
+ return if (anchor == null) relativePath else relativePath + "#" + anchor
}
}
@@ -62,5 +63,5 @@ public fun identifierToFilename(path: String): String {
* Returns relative location between two nodes. Used for relative links in documentation.
*/
fun LocationService.relativePathToLocation(owner: DocumentationNode, node: DocumentationNode): String {
- return location(owner).relativePathTo(location(node))
+ return location(owner).relativePathTo(location(node), null)
}
diff --git a/src/Model/DocumentationReference.kt b/src/Model/DocumentationReference.kt
index bd40f0f5..d7ad5f9e 100644
--- a/src/Model/DocumentationReference.kt
+++ b/src/Model/DocumentationReference.kt
@@ -11,6 +11,7 @@ public data class DocumentationReference(val from: DocumentationNode, val to: Do
Override
Annotation
Deprecation
+ TopLevelPage
}
}
diff --git a/test/data/format/overloadsWithDescription.html b/test/data/format/overloadsWithDescription.html
index b29ca658..db63b262 100644
--- a/test/data/format/overloadsWithDescription.html
+++ b/test/data/format/overloadsWithDescription.html
@@ -8,12 +8,13 @@
<h1>f</h1>
<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier">x</span><span class="symbol">: </span><span class="identifier">Int</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
<code><span class="keyword">fun </span><span class="identifier">f</span><span class="symbol">(</span><span class="identifier">x</span><span class="symbol">: </span><span class="identifier">String</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">Unit</span></code><br/>
-<p>Performs an action on <a href="test/f/x">x</a>.</p>
+<p>Performs an action on <a href="test/f#x">x</a>.</p>
<h3>Description</h3>
<p>This is a long description.</p>
<br/>
<br/>
<h3>Parameters</h3>
+<a name="x"></a>
<code>x</code> - the value to perform the action on.<br/>
<br/>
<br/>
diff --git a/test/data/format/overloadsWithDifferentDescriptions.html b/test/data/format/overloadsWithDifferentDescriptions.html
index 66f8e9a6..06431d15 100644
--- a/test/data/format/overloadsWithDifferentDescriptions.html
+++ b/test/data/format/overloadsWithDifferentDescriptions.html
@@ -13,6 +13,7 @@
<br/>
<br/>
<h3>Parameters</h3>
+<a name="x"></a>
<code>x</code> - the int value to perform the action on.<br/>
<br/>
<br/>
@@ -23,6 +24,7 @@
<br/>
<br/>
<h3>Parameters</h3>
+<a name="x"></a>
<code>x</code> - the string value to perform the action on.<br/>
<br/>
<br/>
diff --git a/test/data/format/parameterAnchor.html b/test/data/format/parameterAnchor.html
new file mode 100644
index 00000000..2b2fec08
--- /dev/null
+++ b/test/data/format/parameterAnchor.html
@@ -0,0 +1,17 @@
+<HTML>
+<HEAD>
+<title>test / processFiles</title>
+</HEAD>
+<BODY>
+<a href="test/index">test</a>&nbsp;/&nbsp;<a href="test/process-files">processFiles</a><br/>
+<br/>
+<h1>processFiles</h1>
+<code><span class="keyword">public</span> <span class="keyword">fun </span><span class="symbol">&lt;</span><span class="identifier">T</span><span class="symbol">&gt; </span><span class="identifier">processFiles</span><span class="symbol">(</span><span class="identifier">processor</span><span class="symbol">: </span><span class="symbol">(</span><span class="symbol">)</span> <span class="symbol">-&gt;</span> <span class="identifier">T</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">List</span><span class="symbol">&lt;</span><span class="identifier">T</span><span class="symbol">&gt;</span></code><br/>
+<p>Runs <a href="test/process-files#processor">processor</a> for each file and collects its results into single list</p>
+<h3>Parameters</h3>
+<a name="processor"></a>
+<code>processor</code> - function to receive context for symbol resolution and file for processing<br/>
+<br/>
+<br/>
+</BODY>
+</HTML>
diff --git a/test/data/format/parameterAnchor.kt b/test/data/format/parameterAnchor.kt
new file mode 100644
index 00000000..ae36ee4c
--- /dev/null
+++ b/test/data/format/parameterAnchor.kt
@@ -0,0 +1,6 @@
+/**
+ * Runs [processor] for each file and collects its results into single list
+ * @param processor function to receive context for symbol resolution and file for processing
+ */
+public fun processFiles<T>(processor: () -> T): List<T> {
+}
diff --git a/test/src/TestAPI.kt b/test/src/TestAPI.kt
index 0b4c2084..285ffa28 100644
--- a/test/src/TestAPI.kt
+++ b/test/src/TestAPI.kt
@@ -100,7 +100,8 @@ fun ContentNode.toTestString(): String {
}
class InMemoryLocation(override val path: String): Location {
- override fun relativePathTo(other: Location): String = other.path
+ override fun relativePathTo(other: Location, anchor: String?): String =
+ if (anchor != null) other.path + "#" + anchor else other.path
}
object InMemoryLocationService: LocationService {
diff --git a/test/src/format/HtmlFormatTest.kt b/test/src/format/HtmlFormatTest.kt
index 6fd7696a..9d4d30da 100644
--- a/test/src/format/HtmlFormatTest.kt
+++ b/test/src/format/HtmlFormatTest.kt
@@ -87,4 +87,10 @@ public class HtmlFormatTest {
htmlService.appendNodes(tempLocation, output, model.members.single().members.filter { it.name == "Bar"} )
}
}
+
+ Test fun parameterAnchor() {
+ verifyOutput("test/data/format/parameterAnchor.kt", ".html") { model, output ->
+ htmlService.appendNodes(tempLocation, output, model.members.single().members)
+ }
+ }
}