diff options
author | Dmitry Jemerov <yole@jetbrains.com> | 2015-02-20 17:01:26 +0100 |
---|---|---|
committer | Dmitry Jemerov <yole@jetbrains.com> | 2015-02-20 17:01:26 +0100 |
commit | bfe53b9ea3359baee1785c2f6291bb5408597e28 (patch) | |
tree | 07678730112e424224b7be8ca2758cb382fc2028 | |
parent | 69c3638e173d1b08e02af0d7723c27cb025cea7d (diff) | |
download | dokka-bfe53b9ea3359baee1785c2f6291bb5408597e28.tar.gz dokka-bfe53b9ea3359baee1785c2f6291bb5408597e28.tar.bz2 dokka-bfe53b9ea3359baee1785c2f6291bb5408597e28.zip |
resolve content links to declaration descriptors immediately during markdown to content tree conversion; remove separate phase for resolving links in content
-rw-r--r-- | src/Formats/HtmlFormatService.kt | 2 | ||||
-rw-r--r-- | src/Kotlin/ContentBuilder.kt | 12 | ||||
-rw-r--r-- | src/Kotlin/DocumentationBuilder.kt | 73 | ||||
-rw-r--r-- | src/Model/Content.kt | 22 | ||||
-rw-r--r-- | src/main.kt | 6 |
5 files changed, 48 insertions, 67 deletions
diff --git a/src/Formats/HtmlFormatService.kt b/src/Formats/HtmlFormatService.kt index d5331422..751c5d5b 100644 --- a/src/Formats/HtmlFormatService.kt +++ b/src/Formats/HtmlFormatService.kt @@ -134,7 +134,7 @@ public open class HtmlFormatService(locationService: LocationService, } override fun appendOutlineHeader(location: Location, node: DocumentationNode, to: StringBuilder) { - val link = ContentNodeLink(node) + val link = ContentNodeDirectLink(node) link.append(languageService.render(node, LanguageService.RenderMode.FULL)) val signature = formatText(location, link) to.appendln("<a href=\"${location.path}\">${signature}</a><br/>") diff --git a/src/Kotlin/ContentBuilder.kt b/src/Kotlin/ContentBuilder.kt index 6bb32f31..de5ac956 100644 --- a/src/Kotlin/ContentBuilder.kt +++ b/src/Kotlin/ContentBuilder.kt @@ -10,13 +10,13 @@ import org.intellij.markdown.* import org.jetbrains.kotlin.psi.JetDeclarationWithBody import org.jetbrains.kotlin.psi.JetBlockExpression -public fun buildContent(tree: MarkdownNode): Content { +public fun buildContent(tree: MarkdownNode, linkResolver: (String) -> ContentBlock): Content { val result = Content() - buildContentTo(tree, result) + buildContentTo(tree, result, linkResolver) return result } -public fun buildContentTo(tree: MarkdownNode, target: ContentBlock) { +public fun buildContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) { // println(tree.toTestString()) val nodeStack = ArrayDeque<ContentBlock>() nodeStack.push(target) @@ -77,7 +77,7 @@ public fun buildContentTo(tree: MarkdownNode, target: ContentBlock) { MarkdownElementTypes.SHORT_REFERENCE_LINK -> { val label = node.child(MarkdownElementTypes.LINK_LABEL)?.child(MarkdownTokenTypes.TEXT) if (label != null) { - val link = ContentExternalLink(label.text) + val link = linkResolver(label.text) link.append(ContentText(label.text)) parent.append(link) } @@ -123,10 +123,10 @@ public fun buildContentTo(tree: MarkdownNode, target: ContentBlock) { private fun keepWhitespace(node: ContentNode) = node is ContentParagraph || node is ContentSection -public fun buildInlineContentTo(tree: MarkdownNode, target: ContentBlock) { +public fun buildInlineContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) { val inlineContent = tree.children.singleOrNull { it.type == MarkdownElementTypes.PARAGRAPH }?.children ?: listOf(tree) inlineContent.forEach { - buildContentTo(it, target) + buildContentTo(it, target, linkResolver) } } diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt index e02b57db..5d9857a7 100644 --- a/src/Kotlin/DocumentationBuilder.kt +++ b/src/Kotlin/DocumentationBuilder.kt @@ -40,7 +40,6 @@ class PendingLink(val lazyNodeFrom: () -> DocumentationNode?, class DocumentationBuilder(val session: ResolveSession, val options: DocumentationOptions, val logger: DokkaLogger) { val visibleToDocumentation = setOf(Visibilities.INTERNAL, Visibilities.PROTECTED, Visibilities.PUBLIC) val descriptorToNode = hashMapOf<DeclarationDescriptor, DocumentationNode>() - val nodeToDescriptor = hashMapOf<DocumentationNode, DeclarationDescriptor>() val links = arrayListOf<PendingLink>() fun parseDocumentation(descriptor: DeclarationDescriptor): Content { @@ -55,7 +54,7 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati } val tree = parseMarkdown(kdocText) //println(tree.toTestString()) - val content = buildContent(tree) + val content = buildContent(tree, { href -> resolveContentLink(descriptor, href) }) if (kdoc is KDocSection) { val tags = kdoc.getTags() tags.forEach { @@ -63,12 +62,12 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati "sample" -> content.append(functionBody(descriptor, it.getSubjectName())) "see" -> - content.addTagToSeeAlso(it) + content.addTagToSeeAlso(descriptor, it) else -> { val section = content.addSection(javadocSectionDisplayName(it.getName()), it.getSubjectName()) val sectionContent = it.getContent() val markdownNode = parseMarkdown(sectionContent) - buildInlineContentTo(markdownNode, section) + buildInlineContentTo(markdownNode, section, { href -> resolveContentLink(descriptor, href) }) } } } @@ -76,13 +75,27 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati return content } + fun resolveContentLink(descriptor: DeclarationDescriptor, href: String): ContentBlock { + val symbols = resolveKDocLink(session, descriptor, null, href.split('.').toList()) + // don't include unresolved links in generated doc + // assume that if an href doesn't contain '/', it's not an attempt to reference an external file + if (symbols.isNotEmpty()) { + val symbol = symbols.first() + return ContentNodeLazyLink(href, {() -> descriptorToNode[symbol] }) + } + if ("/" in href) { + return ContentExternalLink(href) + } + return ContentExternalLink("#") + } + fun KDocSection.getTags(): Array<KDocTag> = PsiTreeUtil.getChildrenOfType(this, javaClass<KDocTag>()) ?: array() - private fun Content.addTagToSeeAlso(seeTag: KDocTag) { + private fun Content.addTagToSeeAlso(descriptor: DeclarationDescriptor, seeTag: KDocTag) { val subjectName = seeTag.getSubjectName() if (subjectName != null) { val seeSection = findSectionByTag("See Also") ?: addSection("See Also", null) - val link = ContentExternalLink(subjectName) + val link = resolveContentLink(descriptor, subjectName) link.append(ContentText(subjectName)) val para = ContentParagraph() para.append(link) @@ -102,7 +115,6 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati fun register(descriptor: DeclarationDescriptor, node: DocumentationNode) { descriptorToNode.put(descriptor, node) - nodeToDescriptor.put(node, descriptor) } fun DocumentationNode<T>(descriptor: T, kind: Kind): DocumentationNode where T : DeclarationDescriptor, T : Named { @@ -484,7 +496,7 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati * $receiver: [DocumentationContext] for node/descriptor resolutions * $node: [DocumentationNode] to visit */ - public fun resolveReferences(node: DocumentationModule) { + public fun resolveReferences() { for (link in links) { val fromNode = link.lazyNodeFrom() val toNode = link.lazyNodeTo() @@ -492,50 +504,5 @@ class DocumentationBuilder(val session: ResolveSession, val options: Documentati fromNode.addReferenceTo(toNode, link.kind) } } - resolveContentReferences(node) - } - - private fun resolveContentReferences(node: DocumentationNode) { - resolveContentLinks(node, node.content) - for (section in node.content.sections) { - resolveContentLinks(node, section) - } - - for (child in node.members) { - resolveContentReferences(child) - } - for (child in node.details) { - resolveContentReferences(child) - } - } - - fun getDescriptorForNode(node: DocumentationNode): DeclarationDescriptor { - val descriptor = nodeToDescriptor[node] ?: throw IllegalArgumentException("Node is not known to this context") - return descriptor - } - - fun resolveContentLinks(node: DocumentationNode, content: ContentBlock) { - val resolvedContentChildren = content.children.map { resolveContentLink(node, it) } - content.children.clear() - content.children.addAll(resolvedContentChildren) - } - - private fun resolveContentLink(node: DocumentationNode, content: ContentNode): ContentNode { - if (content is ContentExternalLink) { - val referenceText = content.href - val symbols = resolveKDocLink(session, getDescriptorForNode(node), null, referenceText.split('.').toList()) - // don't include unresolved links in generated doc - // assume that if an href doesn't contain '/', it's not an attempt to reference an external file - if (symbols.isNotEmpty() || "/" !in referenceText) { - val targetNode = if (symbols.isEmpty()) null else descriptorToNode[symbols.first()] - val contentLink = if (targetNode != null) ContentNodeLink(targetNode) else ContentExternalLink("#") - contentLink.children.addAll(content.children.map { resolveContentLink(node, it) }) - return contentLink - } - } - if (content is ContentBlock) { - resolveContentLinks(node, content) - } - return content } } diff --git a/src/Model/Content.kt b/src/Model/Content.kt index 9864ee42..01d7b206 100644 --- a/src/Model/Content.kt +++ b/src/Model/Content.kt @@ -38,12 +38,26 @@ public class ContentStrikethrough() : ContentBlock() public class ContentCode() : ContentBlock() public class ContentBlockCode() : ContentBlock() -public class ContentNodeLink(val node : DocumentationNode) : ContentBlock() { +public abstract class ContentNodeLink() : ContentBlock() { + abstract val node: DocumentationNode +} + +public class ContentNodeDirectLink(override val node: DocumentationNode): ContentNodeLink() { + override fun equals(other: Any?): Boolean = + super.equals(other) && other is ContentNodeDirectLink && node.name == other.node.name + + override fun hashCode(): Int = + children.hashCode() * 31 + node.name.hashCode() +} + +public class ContentNodeLazyLink(val linkText: String, val lazyNode: () -> DocumentationNode): ContentNodeLink() { + override val node: DocumentationNode get() = lazyNode() + override fun equals(other: Any?): Boolean = - super.equals(other) && other is ContentNodeLink && node.name == other.node.name + super.equals(other) && other is ContentNodeLazyLink && linkText == other.linkText override fun hashCode(): Int = - children.hashCode() * 31 + node.name.hashCode() + children.hashCode() * 31 + linkText.hashCode() } public class ContentExternalLink(val href : String) : ContentBlock() { @@ -77,7 +91,7 @@ fun ContentBlock.symbol(value: String) = append(ContentSymbol(value)) fun ContentBlock.identifier(value: String) = append(ContentIdentifier(value)) fun ContentBlock.link(to: DocumentationNode, body: ContentBlock.() -> Unit) { - val block = ContentNodeLink(to) + val block = ContentNodeDirectLink(to) block.body() append(block) } diff --git a/src/main.kt b/src/main.kt index 63495d46..44c435d2 100644 --- a/src/main.kt +++ b/src/main.kt @@ -195,12 +195,13 @@ fun buildDocumentationModule(environment: AnalysisEnvironment, val fragments = fragmentFiles.map { session.getPackageFragment(it.getPackageFqName()) }.filterNotNull().distinct() val moduleContent = Content() + val documentationBuilder = DocumentationBuilder(session, options, logger) for (include in includes) { val file = File(include) if (file.exists()) { val text = file.readText() val tree = parseMarkdown(text) - val content = buildContent(tree) + val content = buildContent(tree, {href -> documentationBuilder.resolveContentLink(fragments.first(), href)}) moduleContent.children.addAll(content.children) } else { logger.warn("Include file $file was not found.") @@ -208,10 +209,9 @@ fun buildDocumentationModule(environment: AnalysisEnvironment, } val documentationModule = DocumentationModule(moduleName, moduleContent) - val documentationBuilder = DocumentationBuilder(session, options, logger) with(documentationBuilder) { documentationModule.appendFragments(fragments) - documentationBuilder.resolveReferences(documentationModule) + documentationBuilder.resolveReferences() } val javaFiles = environment.getJavaSourceFiles().filter(filesToDocumentFilter) |