aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIlya Ryzhenkov <orangy@jetbrains.com>2014-10-03 22:51:44 +0400
committerIlya Ryzhenkov <orangy@jetbrains.com>2014-10-03 22:51:44 +0400
commit71cd87e239ba4ba846eb5da04e45a451b8a840cb (patch)
treea95a0c385c72b0ba20b2b775a460cc87bc51531c /src
parentb642b7c35e63729303094483dc2d176ec5ce7a7d (diff)
downloaddokka-71cd87e239ba4ba846eb5da04e45a451b8a840cb.tar.gz
dokka-71cd87e239ba4ba846eb5da04e45a451b8a840cb.tar.bz2
dokka-71cd87e239ba4ba846eb5da04e45a451b8a840cb.zip
Resolve links in docs.
Diffstat (limited to 'src')
-rw-r--r--src/Formats/HtmlFormatService.kt4
-rw-r--r--src/Formats/MarkdownFormatService.kt6
-rw-r--r--src/Formats/StructuredFormatService.kt5
-rw-r--r--src/Kotlin/ContentBuilder.kt30
-rw-r--r--src/Kotlin/CrossReferences.kt44
-rw-r--r--src/Kotlin/DocumentationContext.kt2
-rw-r--r--src/Kotlin/ResolveReferences.kt83
-rw-r--r--src/Languages/JavaLanguageService.kt25
-rw-r--r--src/Languages/KotlinLanguageService.kt29
-rw-r--r--src/Languages/LanguageService.kt17
-rw-r--r--src/Markdown/markdown.bnf6
-rw-r--r--src/Model/Content.kt4
12 files changed, 169 insertions, 86 deletions
diff --git a/src/Formats/HtmlFormatService.kt b/src/Formats/HtmlFormatService.kt
index 06b41518..20cd4f83 100644
--- a/src/Formats/HtmlFormatService.kt
+++ b/src/Formats/HtmlFormatService.kt
@@ -81,6 +81,10 @@ public open class HtmlFormatService(locationService: LocationService,
return "<a href=\"${location.path}\">${text}</a>"
}
+ override fun formatLink(text: String, href: String): String {
+ return "<a href=\"${href}\">${text}</a>"
+ }
+
override fun formatBold(text: String): String {
return "<b>${text}</b>"
}
diff --git a/src/Formats/MarkdownFormatService.kt b/src/Formats/MarkdownFormatService.kt
index cb1d713c..bbe0d7be 100644
--- a/src/Formats/MarkdownFormatService.kt
+++ b/src/Formats/MarkdownFormatService.kt
@@ -35,7 +35,11 @@ public open class MarkdownFormatService(locationService: LocationService,
}
override public fun formatLink(text: String, location: Location): String {
- return "[${text}](${location.path})"
+ return "[$text](${location.path})"
+ }
+
+ override fun formatLink(text: String, href: String): String {
+ return "[$text]($href)"
}
override public fun appendLine(to: StringBuilder) {
diff --git a/src/Formats/StructuredFormatService.kt b/src/Formats/StructuredFormatService.kt
index b974dcf8..df11b835 100644
--- a/src/Formats/StructuredFormatService.kt
+++ b/src/Formats/StructuredFormatService.kt
@@ -25,6 +25,7 @@ public abstract class StructuredFormatService(val locationService: LocationServi
public abstract fun formatKeyword(text: String): String
public abstract fun formatIdentifier(text: String): String
public abstract fun formatLink(text: String, location: Location): String
+ public abstract fun formatLink(text: String, href: String): String
public open fun formatLink(link: FormatLink): String = formatLink(formatText(link.text), link.location)
public abstract fun formatBold(text: String): String
public abstract fun formatCode(code: String): String
@@ -47,6 +48,10 @@ public abstract class StructuredFormatService(val locationService: LocationServi
val linkText = formatText(location, content.children)
append(formatLink(linkText, linkTo))
}
+ is ContentExternalLink -> {
+ val linkText = formatText(location, content.children)
+ append(formatLink(linkText, content.href))
+ }
else -> append(formatText(location, content.children))
}
}.toString()
diff --git a/src/Kotlin/ContentBuilder.kt b/src/Kotlin/ContentBuilder.kt
index 78bd7eaf..389b2732 100644
--- a/src/Kotlin/ContentBuilder.kt
+++ b/src/Kotlin/ContentBuilder.kt
@@ -15,50 +15,60 @@ public fun MarkdownTree.toContent(): Content {
MarkdownElementTypes.BULLET_LIST -> {
nodeStack.push(ContentList())
processChildren()
- parent.children.add(nodeStack.pop())
+ parent.append(nodeStack.pop())
}
MarkdownElementTypes.ORDERED_LIST -> {
nodeStack.push(ContentList()) // TODO: add list kind
processChildren()
- parent.children.add(nodeStack.pop())
+ parent.append(nodeStack.pop())
}
MarkdownElementTypes.HORIZONTAL_RULE -> {
}
MarkdownElementTypes.LIST_BLOCK -> {
nodeStack.push(ContentBlock())
processChildren()
- parent.children.add(nodeStack.pop())
+ parent.append(nodeStack.pop())
}
MarkdownElementTypes.EMPH -> {
nodeStack.push(ContentEmphasis())
processChildren()
- parent.children.add(nodeStack.pop())
+ parent.append(nodeStack.pop())
}
MarkdownElementTypes.STRONG -> {
nodeStack.push(ContentStrong())
processChildren()
- parent.children.add(nodeStack.pop())
+ parent.append(nodeStack.pop())
}
MarkdownElementTypes.ANONYMOUS_SECTION -> {
nodeStack.push(ContentSection(""))
processChildren()
- parent.children.add(nodeStack.pop())
+ parent.append(nodeStack.pop())
}
MarkdownElementTypes.NAMED_SECTION -> {
val label = findChildByType(node, MarkdownElementTypes.SECTION_NAME)?.let { getNodeText(it) } ?: ""
nodeStack.push(ContentSection(label))
processChildren()
- parent.children.add(nodeStack.pop())
+ parent.append(nodeStack.pop())
+ }
+ MarkdownElementTypes.LINK -> {
+ val target = findChildByType(node, MarkdownElementTypes.TARGET)?.let { getNodeText(it) } ?: ""
+ val href = findChildByType(node, MarkdownElementTypes.HREF)?.let { getNodeText(it) }
+ val link = if (href != null)
+ ContentExternalLink(href)
+ else
+ ContentNameLink(target)
+ link.append(ContentText(target))
+ parent.append(link)
}
MarkdownElementTypes.PLAIN_TEXT -> {
nodeStack.push(ContentText(nodeText))
processChildren()
- parent.children.add(nodeStack.pop())
+ parent.append(nodeStack.pop())
}
MarkdownElementTypes.END_LINE -> {
nodeStack.push(ContentText(nodeText))
processChildren()
- parent.children.add(nodeStack.pop())
+ parent.append(nodeStack.pop())
}
MarkdownElementTypes.BLANK_LINE -> {
processChildren()
@@ -66,7 +76,7 @@ public fun MarkdownTree.toContent(): Content {
MarkdownElementTypes.PARA -> {
nodeStack.push(ContentBlock())
processChildren()
- parent.children.add(nodeStack.pop())
+ parent.append(nodeStack.pop())
}
else -> {
processChildren()
diff --git a/src/Kotlin/CrossReferences.kt b/src/Kotlin/CrossReferences.kt
deleted file mode 100644
index c06b81d4..00000000
--- a/src/Kotlin/CrossReferences.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.jetbrains.dokka
-
-/**
- * Generates cross-references for documentation such as extensions for a type
- *
- * $receiver: [DocumentationContext] for node/descriptor resolutions
- * $node: [DocumentationNode] to visit
- */
-public fun DocumentationContext.buildCrossReferences(node: DocumentationNode) {
- node.details(DocumentationNode.Kind.Receiver).forEach { detail ->
- val receiverType = detail.detail(DocumentationNode.Kind.Type)
- val descriptor = relations[receiverType]
- if (descriptor != null) {
- val typeNode = descriptorToNode[descriptor]
- // if typeNode is null, extension is to external type like in a library
- // should we create dummy node here?
- typeNode?.addReferenceTo(node, DocumentationReference.Kind.Extension)
- }
- }
- node.details(DocumentationNode.Kind.Supertype).forEach { detail ->
- val descriptor = relations[detail]
- if (descriptor != null) {
- val typeNode = descriptorToNode[descriptor]
- typeNode?.addReferenceTo(node, DocumentationReference.Kind.Inheritor)
- }
- }
- node.details.forEach { detail ->
- val descriptor = relations[detail]
- if (descriptor != null) {
- val typeNode = descriptorToNode[descriptor]
- if (typeNode != null) {
- detail.addReferenceTo(typeNode, DocumentationReference.Kind.Link)
- }
- }
- }
-
- for (child in node.members) {
- buildCrossReferences(child)
- }
- for (child in node.details) {
- buildCrossReferences(child)
- }
-}
-
diff --git a/src/Kotlin/DocumentationContext.kt b/src/Kotlin/DocumentationContext.kt
index 1fada8b3..649543ac 100644
--- a/src/Kotlin/DocumentationContext.kt
+++ b/src/Kotlin/DocumentationContext.kt
@@ -54,7 +54,7 @@ fun BindingContext.createDocumentationModule(name: String,
pkg!!.accept(DocumentationBuildingVisitor(this, options, visitor), documentationModule)
}
- context.buildCrossReferences(documentationModule)
+ context.resolveReferences(documentationModule)
// TODO: Uncomment for resolve verification
// checkResolveChildren(documentationModule)
diff --git a/src/Kotlin/ResolveReferences.kt b/src/Kotlin/ResolveReferences.kt
new file mode 100644
index 00000000..90e23ffb
--- /dev/null
+++ b/src/Kotlin/ResolveReferences.kt
@@ -0,0 +1,83 @@
+package org.jetbrains.dokka
+
+import org.jetbrains.jet.lang.resolve.name.Name
+
+/**
+ * Generates cross-references for documentation such as extensions for a type, inheritors, etc
+ *
+ * $receiver: [DocumentationContext] for node/descriptor resolutions
+ * $node: [DocumentationNode] to visit
+ */
+public fun DocumentationContext.resolveReferences(node: DocumentationNode) {
+ node.details(DocumentationNode.Kind.Receiver).forEach { detail ->
+ val receiverType = detail.detail(DocumentationNode.Kind.Type)
+ val descriptor = relations[receiverType]
+ if (descriptor != null) {
+ val typeNode = descriptorToNode[descriptor]
+ // if typeNode is null, extension is to external type like in a library
+ // should we create dummy node here?
+ typeNode?.addReferenceTo(node, DocumentationReference.Kind.Extension)
+ }
+ }
+ node.details(DocumentationNode.Kind.Supertype).forEach { detail ->
+ val descriptor = relations[detail]
+ if (descriptor != null) {
+ val typeNode = descriptorToNode[descriptor]
+ typeNode?.addReferenceTo(node, DocumentationReference.Kind.Inheritor)
+ }
+ }
+ node.details.forEach { detail ->
+ val descriptor = relations[detail]
+ if (descriptor != null) {
+ val typeNode = descriptorToNode[descriptor]
+ if (typeNode != null) {
+ detail.addReferenceTo(typeNode, DocumentationReference.Kind.Link)
+ }
+ }
+ }
+
+ resolveContentLinks(node, node.doc)
+
+ for (child in node.members) {
+ resolveReferences(child)
+ }
+ for (child in node.details) {
+ resolveReferences(child)
+ }
+}
+
+fun DocumentationContext.resolveContentLinks(node : DocumentationNode, content: ContentNode) {
+ val snapshot = content.children.toList()
+ for (child in snapshot) {
+ if (child is ContentNameLink) {
+ val scope = getResolutionScope(node)
+ val symbolName = child.name
+ val symbol =
+ scope.getLocalVariable(Name.guess(symbolName)) ?:
+ scope.getProperties(Name.guess(symbolName)).firstOrNull() ?:
+ scope.getFunctions(Name.guess(symbolName)).firstOrNull() ?:
+ scope.getClassifier(Name.guess(symbolName))
+
+ if (symbol != null) {
+ val targetNode = descriptorToNode[symbol]
+ if (targetNode != null) {
+ // we have a doc node for the symbol
+ val index = content.children.indexOf(child)
+ content.children.remove(index)
+ val contentLink = ContentNodeLink(targetNode)
+ contentLink.children.add(ContentIdentifier(symbolName))
+ //contentLink.children.addAll(child.children)
+ content.children.add(index, contentLink)
+ } else {
+ // we don't have a doc node for the symbol, render as identifier
+ val index = content.children.indexOf(child)
+ content.children.remove(index)
+ val contentLink = ContentIdentifier(symbolName)
+ contentLink.children.addAll(child.children)
+ content.children.add(index, contentLink)
+ }
+ }
+ }
+ resolveContentLinks(node, child)
+ }
+} \ No newline at end of file
diff --git a/src/Languages/JavaLanguageService.kt b/src/Languages/JavaLanguageService.kt
index 5d2b48f1..8cc54d4a 100644
--- a/src/Languages/JavaLanguageService.kt
+++ b/src/Languages/JavaLanguageService.kt
@@ -2,7 +2,10 @@ package org.jetbrains.dokka
import org.jetbrains.dokka.DocumentationNode.*
-class JavaLanguageService : LanguageService {
+/**
+ * Implements [LanguageService] and provides rendering of symbols in Java language
+ */
+public class JavaLanguageService : LanguageService {
override fun render(node: DocumentationNode): ContentNode {
return ContentText(when (node.kind) {
Kind.Package -> renderPackage(node)
@@ -30,11 +33,11 @@ class JavaLanguageService : LanguageService {
}
}
- fun renderPackage(node: DocumentationNode): String {
+ private fun renderPackage(node: DocumentationNode): String {
return "package ${node.name}"
}
- fun renderModifier(node: DocumentationNode): String {
+ private fun renderModifier(node: DocumentationNode): String {
return when (node.name) {
"open" -> ""
"internal" -> ""
@@ -42,7 +45,7 @@ class JavaLanguageService : LanguageService {
}
}
- fun renderType(node: DocumentationNode): String {
+ private fun renderType(node: DocumentationNode): String {
return when (node.name) {
"Unit" -> "void"
"Int" -> "int"
@@ -56,7 +59,7 @@ class JavaLanguageService : LanguageService {
}
}
- fun renderTypeParameter(node: DocumentationNode): String {
+ private fun renderTypeParameter(node: DocumentationNode): String {
val constraints = node.details(Kind.UpperBound)
return if (constraints.none())
node.name
@@ -65,11 +68,11 @@ class JavaLanguageService : LanguageService {
}
}
- fun renderParameter(node: DocumentationNode): String {
+ private fun renderParameter(node: DocumentationNode): String {
return "${renderType(node.detail(Kind.Type))} ${node.name}"
}
- fun renderTypeParametersForNode(node: DocumentationNode): String {
+ private fun renderTypeParametersForNode(node: DocumentationNode): String {
return StringBuilder {
val typeParameters = node.details(Kind.TypeParameter)
if (typeParameters.any()) {
@@ -80,14 +83,14 @@ class JavaLanguageService : LanguageService {
}.toString()
}
- fun renderModifiersForNode(node: DocumentationNode): String {
+ private fun renderModifiersForNode(node: DocumentationNode): String {
val modifiers = node.details(Kind.Modifier).map { renderModifier(it) }.filter { it != "" }
if (modifiers.none())
return ""
return modifiers.join(" ", postfix = " ")
}
- fun renderClass(node: DocumentationNode): String {
+ private fun renderClass(node: DocumentationNode): String {
return StringBuilder {
when (node.kind) {
Kind.Class -> append("class ")
@@ -103,7 +106,7 @@ class JavaLanguageService : LanguageService {
}.toString()
}
- fun renderFunction(node: DocumentationNode): String {
+ private fun renderFunction(node: DocumentationNode): String {
return StringBuilder {
when (node.kind) {
Kind.Constructor -> append(node.owner?.name)
@@ -127,7 +130,7 @@ class JavaLanguageService : LanguageService {
}.toString()
}
- fun renderProperty(node: DocumentationNode): String {
+ private fun renderProperty(node: DocumentationNode): String {
return StringBuilder {
when (node.kind) {
Kind.Property -> append("val ")
diff --git a/src/Languages/KotlinLanguageService.kt b/src/Languages/KotlinLanguageService.kt
index 46b58574..f806dd19 100644
--- a/src/Languages/KotlinLanguageService.kt
+++ b/src/Languages/KotlinLanguageService.kt
@@ -2,6 +2,9 @@ package org.jetbrains.dokka
import org.jetbrains.dokka.DocumentationNode.*
+/**
+ * Implements [LanguageService] and provides rendering of symbols in Kotlin language
+ */
class KotlinLanguageService : LanguageService {
override fun render(node: DocumentationNode): ContentNode {
return content {
@@ -33,13 +36,13 @@ class KotlinLanguageService : LanguageService {
}
}
- fun ContentNode.renderPackage(node: DocumentationNode) {
+ private fun ContentNode.renderPackage(node: DocumentationNode) {
keyword("package")
text(" ")
identifier(node.name)
}
- fun ContentNode.renderList(nodes: List<DocumentationNode>, separator: String = ", ", renderItem: (DocumentationNode) -> Unit) {
+ private fun ContentNode.renderList(nodes: List<DocumentationNode>, separator: String = ", ", renderItem: (DocumentationNode) -> Unit) {
if (nodes.none())
return
renderItem(nodes.first())
@@ -49,7 +52,7 @@ class KotlinLanguageService : LanguageService {
}
}
- fun ContentNode.renderLinked(node: DocumentationNode, body: ContentNode.(DocumentationNode)->Unit) {
+ private fun ContentNode.renderLinked(node: DocumentationNode, body: ContentNode.(DocumentationNode)->Unit) {
val to = node.links.firstOrNull()
if (to == null)
body(node)
@@ -59,7 +62,7 @@ class KotlinLanguageService : LanguageService {
}
}
- fun ContentNode.renderType(node: DocumentationNode) {
+ private fun ContentNode.renderType(node: DocumentationNode) {
val typeArguments = node.details(Kind.Type)
if (node.name == "Function${typeArguments.count() - 1}") {
// lambda
@@ -99,7 +102,7 @@ class KotlinLanguageService : LanguageService {
}
}
- fun ContentNode.renderModifier(node: DocumentationNode) {
+ private fun ContentNode.renderModifier(node: DocumentationNode) {
when (node.name) {
"final", "internal" -> {
}
@@ -107,7 +110,7 @@ class KotlinLanguageService : LanguageService {
}
}
- fun ContentNode.renderTypeParameter(node: DocumentationNode) {
+ private fun ContentNode.renderTypeParameter(node: DocumentationNode) {
val constraints = node.details(Kind.UpperBound)
identifier(node.name)
if (constraints.any()) {
@@ -118,14 +121,14 @@ class KotlinLanguageService : LanguageService {
}
}
- fun ContentNode.renderParameter(node: DocumentationNode) {
+ private fun ContentNode.renderParameter(node: DocumentationNode) {
identifier(node.name)
symbol(": ")
val parameterType = node.detail(Kind.Type)
renderType(parameterType)
}
- fun ContentNode.renderTypeParametersForNode(node: DocumentationNode) {
+ private fun ContentNode.renderTypeParametersForNode(node: DocumentationNode) {
val typeParameters = node.details(Kind.TypeParameter)
if (typeParameters.any()) {
symbol("<")
@@ -136,7 +139,7 @@ class KotlinLanguageService : LanguageService {
}
}
- fun ContentNode.renderSupertypesForNode(node: DocumentationNode) {
+ private fun ContentNode.renderSupertypesForNode(node: DocumentationNode) {
val supertypes = node.details(Kind.Supertype)
if (supertypes.any()) {
symbol(" : ")
@@ -146,7 +149,7 @@ class KotlinLanguageService : LanguageService {
}
}
- fun ContentNode.renderModifiersForNode(node: DocumentationNode) {
+ private fun ContentNode.renderModifiersForNode(node: DocumentationNode) {
val modifiers = node.details(Kind.Modifier)
for (it in modifiers) {
if (node.kind == Kind.Interface && it.name == "abstract")
@@ -156,7 +159,7 @@ class KotlinLanguageService : LanguageService {
}
}
- fun ContentNode.renderClass(node: DocumentationNode) {
+ private fun ContentNode.renderClass(node: DocumentationNode) {
renderModifiersForNode(node)
when (node.kind) {
Kind.Class -> keyword("class ")
@@ -172,7 +175,7 @@ class KotlinLanguageService : LanguageService {
renderSupertypesForNode(node)
}
- fun ContentNode.renderFunction(node: DocumentationNode) {
+ private fun ContentNode.renderFunction(node: DocumentationNode) {
renderModifiersForNode(node)
when (node.kind) {
Kind.Constructor -> identifier(node.owner!!.name)
@@ -200,7 +203,7 @@ class KotlinLanguageService : LanguageService {
}
}
- fun ContentNode.renderProperty(node: DocumentationNode) {
+ private fun ContentNode.renderProperty(node: DocumentationNode) {
renderModifiersForNode(node)
when (node.kind) {
Kind.Property -> keyword("val ")
diff --git a/src/Languages/LanguageService.kt b/src/Languages/LanguageService.kt
index 26217d41..bf55ac2c 100644
--- a/src/Languages/LanguageService.kt
+++ b/src/Languages/LanguageService.kt
@@ -1,7 +1,24 @@
package org.jetbrains.dokka
+/**
+ * Provides facility for rendering [DocumentationNode] as a language-dependent declaration
+ */
trait LanguageService {
+ /**
+ * Renders [node] as a class, function, property or other signature
+ * $node: A [DocumentationNode] to render
+ * $returns: [ContentNode] which is a root for a rich content tree suitable for formatting with [FormatService]
+ */
fun render(node: DocumentationNode): ContentNode
+
+ /**
+ * Renders [node] as a named representation in the target language
+ *
+ * See also [google](http://google.com)
+ *
+ * $node: A [DocumentationNode] to render
+ * $returns: [String] which is a string representation of the node
+ */
fun renderName(node: DocumentationNode) : String
}
diff --git a/src/Markdown/markdown.bnf b/src/Markdown/markdown.bnf
index d26b18a6..d6fd2ed2 100644
--- a/src/Markdown/markdown.bnf
+++ b/src/Markdown/markdown.bnf
@@ -86,8 +86,6 @@ Strong ::= StrongStar | StrongUnderscore
StrongStar ::= '**' !Whitespace (!'**' Inline)+ '**'
StrongUnderscore ::= '__' !Whitespace (!'__' Inline)+ '__'
-Link ::= HrefLink | ReferenceLink
-private ReferenceLink ::= '[' Target ']'
-private HrefLink ::= '[' Target ']' '(' Href ')'
+Link ::= '[' Target ']' ('(' Href ')')?
Target ::= Word+
-Href ::= Word+ \ No newline at end of file
+Href ::= (Word | Number | ':' | '/')+ \ No newline at end of file
diff --git a/src/Model/Content.kt b/src/Model/Content.kt
index 4b92a958..27adfe59 100644
--- a/src/Model/Content.kt
+++ b/src/Model/Content.kt
@@ -9,9 +9,8 @@ public abstract class ContentNode {
val empty = ContentEmpty
}
- fun append(node : ContentNode) : ContentNode {
+ fun append(node : ContentNode) {
children.add(node)
- return this
}
fun isEmpty() = children.isEmpty()
@@ -26,6 +25,7 @@ public class ContentIdentifier(val text: String) : ContentNode()
public class ContentSymbol(val text: String) : ContentNode()
public class ContentEmphasis() : ContentBlock()
public class ContentNodeLink(val node : DocumentationNode) : ContentBlock()
+public class ContentNameLink(val name : String) : ContentBlock()
public class ContentExternalLink(val href : String) : ContentBlock()
public class ContentStrong() : ContentBlock()
public class ContentList() : ContentBlock()