diff options
author | Dmitry Jemerov <yole@jetbrains.com> | 2015-02-20 14:08:30 +0100 |
---|---|---|
committer | Dmitry Jemerov <yole@jetbrains.com> | 2015-02-20 14:08:30 +0100 |
commit | 85a3ae7626810113816fd31a0e26d44d48308ed2 (patch) | |
tree | 837eae154a30f139449f560d5e1afebf113041ee | |
parent | ea1f4cc2987536c3ed3df5899e6cec2df890f1e6 (diff) | |
download | dokka-85a3ae7626810113816fd31a0e26d44d48308ed2.tar.gz dokka-85a3ae7626810113816fd31a0e26d44d48308ed2.tar.bz2 dokka-85a3ae7626810113816fd31a0e26d44d48308ed2.zip |
support in-page anchors in locations
-rw-r--r-- | src/Formats/HtmlFormatService.kt | 4 | ||||
-rw-r--r-- | src/Formats/MarkdownFormatService.kt | 4 | ||||
-rw-r--r-- | src/Formats/StructuredFormatService.kt | 12 | ||||
-rw-r--r-- | src/Kotlin/DocumentationBuilder.kt | 30 | ||||
-rw-r--r-- | src/Locations/LocationService.kt | 9 | ||||
-rw-r--r-- | src/Model/DocumentationReference.kt | 1 | ||||
-rw-r--r-- | test/data/format/overloadsWithDescription.html | 3 | ||||
-rw-r--r-- | test/data/format/overloadsWithDifferentDescriptions.html | 2 | ||||
-rw-r--r-- | test/data/format/parameterAnchor.html | 17 | ||||
-rw-r--r-- | test/data/format/parameterAnchor.kt | 6 | ||||
-rw-r--r-- | test/src/TestAPI.kt | 3 | ||||
-rw-r--r-- | test/src/format/HtmlFormatTest.kt | 6 |
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> / <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"><</span><span class="identifier">T</span><span class="symbol">> </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">-></span> <span class="identifier">T</span><span class="symbol">)</span><span class="symbol">: </span><span class="identifier">List</span><span class="symbol"><</span><span class="identifier">T</span><span class="symbol">></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) + } + } } |