diff options
Diffstat (limited to 'src')
24 files changed, 624 insertions, 658 deletions
diff --git a/src/Analysis/AnalysisEnvironment.kt b/src/Analysis/AnalysisEnvironment.kt index 1d51b8a2..3c7f6767 100644 --- a/src/Analysis/AnalysisEnvironment.kt +++ b/src/Analysis/AnalysisEnvironment.kt @@ -11,6 +11,7 @@ import org.jetbrains.jet.cli.common.* import org.jetbrains.jet.cli.jvm.* import com.intellij.openapi.util.* import org.jetbrains.jet.lang.descriptors.ModuleDescriptor +import org.jetbrains.jet.lang.resolve.lazy.ResolveSession /** * Kotlin as a service entry point @@ -30,27 +31,28 @@ public class AnalysisEnvironment(val messageCollector: MessageCollector, body: A * Executes [processor] when analysis is complete. * $processor is a function to receive compiler environment, module and context for symbol resolution */ - public fun withContext<T>(processor: (JetCoreEnvironment, ModuleDescriptor, BindingContext) -> T): T { + public fun withContext<T>(processor: (JetCoreEnvironment, ResolveSession) -> T): T { val environment = JetCoreEnvironment.createForProduction(this, configuration) - val exhaust = environment.analyze() - return processor(environment, exhaust.getModuleDescriptor(), exhaust.getBindingContext()) + val resolveSession = environment.analyze() + resolveSession.forceResolveAll() + return processor(environment, resolveSession) } /** * Executes [processor] when analysis is complete. * $processor is a function to receive compiler module and context for symbol resolution */ - public fun withContext<T>(processor: (ModuleDescriptor, BindingContext) -> T): T { - return withContext { environment, module, context -> processor(module, context) } + public fun withContext<T>(processor: (ResolveSession) -> T): T { + return withContext { environment, session -> processor(session) } } /** * Streams files into [processor] and returns a stream of its results * $processor is a function to receive context for symbol resolution and file for processing */ - public fun streamFiles<T>(processor: (BindingContext, JetFile) -> T): Stream<T> { - return withContext { environment, module, context -> - environment.getSourceFiles().stream().map { file -> processor(context, file) } + public fun streamFiles<T>(processor: (ResolveSession, JetFile) -> T): Stream<T> { + return withContext { environment, session -> + environment.getSourceFiles().stream().map { file -> processor(session, file) } } } @@ -58,19 +60,9 @@ public class AnalysisEnvironment(val messageCollector: MessageCollector, body: A * Runs [processor] for each file and collects its results into single list * $processor is a function to receive context for symbol resolution and file for processing */ - public fun processFiles<T>(processor: (BindingContext, JetFile) -> T): List<T> { - return withContext { environment, module, context -> - environment.getSourceFiles().map { file -> processor(context, file) } - } - } - - /** - * Runs [processor] for each file and collects its results into single list - * $processor is a function to receive context for symbol resolution, module and file for processing - */ - public fun processFiles<T>(processor: (BindingContext, ModuleDescriptor, JetFile) -> T): List<T> { - return withContext { environment, module, context -> - environment.getSourceFiles().map { file -> processor(context, module, file) } + public fun processFiles<T>(processor: (ResolveSession, JetFile) -> T): List<T> { + return withContext { environment, session -> + environment.getSourceFiles().map { file -> processor(session, file) } } } @@ -78,9 +70,9 @@ public class AnalysisEnvironment(val messageCollector: MessageCollector, body: A * Runs [processor] for each file and collects its results into single list * $processor is a function to receive context for symbol resolution and file for processing */ - public fun processFilesFlat<T>(processor: (BindingContext, JetFile) -> List<T>): List<T> { - return withContext { environment, module, context -> - environment.getSourceFiles().flatMap { file -> processor(context, file) } + public fun processFilesFlat<T>(processor: (ResolveSession, JetFile) -> List<T>): List<T> { + return withContext { environment, session -> + environment.getSourceFiles().flatMap { file -> processor(session, file) } } } diff --git a/src/Analysis/CommentsAPI.kt b/src/Analysis/CommentsAPI.kt index a17b6aa4..2407de76 100644 --- a/src/Analysis/CommentsAPI.kt +++ b/src/Analysis/CommentsAPI.kt @@ -5,8 +5,8 @@ import org.jetbrains.jet.lang.resolve.* import org.jetbrains.jet.kdoc.psi.api.* import org.jetbrains.jet.lang.psi.* -fun BindingContext.getDocumentationElements(descriptor: DeclarationDescriptor): List<KDoc> { - val psiElement = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) +fun DeclarationDescriptor.getDocumentationElements(): List<KDoc> { + val psiElement = DescriptorToSourceUtils.descriptorToDeclaration(this) if (psiElement == null) return listOf() diff --git a/src/Analysis/CompilerAPI.kt b/src/Analysis/CompilerAPI.kt index 03d4dde6..8216c549 100644 --- a/src/Analysis/CompilerAPI.kt +++ b/src/Analysis/CompilerAPI.kt @@ -1,19 +1,19 @@ package org.jetbrains.dokka import org.jetbrains.jet.cli.common.arguments.* -import org.jetbrains.jet.cli.common.messages.* -import org.jetbrains.jet.cli.jvm.* import org.jetbrains.jet.cli.jvm.compiler.* import org.jetbrains.jet.utils.* import java.io.* import org.jetbrains.jet.lang.resolve.java.* -import com.google.common.base.* -import com.intellij.psi.* import org.jetbrains.jet.lang.resolve.* import org.jetbrains.jet.lang.psi.* import org.jetbrains.jet.analyzer.* import org.jetbrains.jet.lang.descriptors.* import org.jetbrains.jet.lang.resolve.scopes.* +import org.jetbrains.jet.context.GlobalContext +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.jet.lang.resolve.name.Name +import org.jetbrains.jet.lang.resolve.lazy.ResolveSession private fun getAnnotationsPath(paths: KotlinPaths, arguments: K2JVMCompilerArguments): MutableList<File> { val annotationsPath = arrayListOf<File>() @@ -27,21 +27,24 @@ private fun getAnnotationsPath(paths: KotlinPaths, arguments: K2JVMCompilerArgum return annotationsPath } -fun JetCoreEnvironment.analyze(): AnalyzeExhaust { +fun JetCoreEnvironment.analyze(): ResolveSession { + val globalContext = GlobalContext() val project = getProject() val sourceFiles = getSourceFiles() - val support = CliLightClassGenerationSupport.getInstanceForCli(project)!! - val sharedTrace = support.getTrace() - val sharedModule = support.newModule() - val exhaust = TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(project, sourceFiles, sharedTrace, - Predicates.alwaysFalse<PsiFile>(), - sharedModule, - null, - null) - return exhaust -} -fun BindingContext.getPackageFragment(file: JetFile): PackageFragmentDescriptor? = get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, file) + val module = object : ModuleInfo { + override val name: Name = Name.special("<module>") + override fun dependencies(): List<ModuleInfo> = listOf(this) + } + val resolverForProject = JvmAnalyzerFacade.setupResolverForProject( + globalContext, + project, + listOf(module), + { ModuleContent(sourceFiles, GlobalSearchScope.allScope(project)) }, + JvmPlatformParameters { module } + ) + return resolverForProject.resolverForModule(module).lazyResolveSession +} fun DeclarationDescriptor.isUserCode() = when (this) { @@ -117,7 +120,7 @@ public fun getPropertyInnerScope(outerScope: JetScope, descriptor: PropertyDescr return propertyScope } -fun BindingContext.getResolutionScope(descriptor: DeclarationDescriptor): JetScope { +fun getResolutionScope(descriptor: DeclarationDescriptor): JetScope { when (descriptor) { is PackageFragmentDescriptor -> return getPackageInnerScope(descriptor) diff --git a/src/Formats/HtmlFormatService.kt b/src/Formats/HtmlFormatService.kt index 20cd4f83..c337b69b 100644 --- a/src/Formats/HtmlFormatService.kt +++ b/src/Formats/HtmlFormatService.kt @@ -20,15 +20,15 @@ public open class HtmlFormatService(locationService: LocationService, } override fun appendBlockCode(to: StringBuilder, line: String) { - to.appendln("<code>") - to.appendln(line) - to.appendln("</code>") + to.append("<pre><code>") + to.append(line) + to.append("</code></pre>") } override fun appendBlockCode(to: StringBuilder, lines: Iterable<String>) { - to.appendln("<code>") - to.appendln(lines.join("\n")) - to.appendln("</code>") + to.append("<pre><code>") + to.append(lines.join("\n")) + to.append("</code></pre>") } override fun appendHeader(to: StringBuilder, text: String, level: Int) { @@ -85,8 +85,12 @@ public open class HtmlFormatService(locationService: LocationService, return "<a href=\"${href}\">${text}</a>" } - override fun formatBold(text: String): String { - return "<b>${text}</b>" + override fun formatStrong(text: String): String { + return "<strong>${text}</strong>" + } + + override fun formatEmphasis(text: String): String { + return "<emph>${text}</emph>" } override fun formatCode(code: String): String { diff --git a/src/Formats/KotlinWebsiteFormatService.kt b/src/Formats/KotlinWebsiteFormatService.kt index 8170b5a9..e694e222 100644 --- a/src/Formats/KotlinWebsiteFormatService.kt +++ b/src/Formats/KotlinWebsiteFormatService.kt @@ -29,10 +29,6 @@ public class KotlinWebsiteFormatService(locationService: LocationService, return "<a href=\"${href}\">${text}</a>" } - override fun appendText(to: StringBuilder, text: String) { - to.appendln("<p markdown=\"1\">${text}</p>") - } - override fun appendTable(to: StringBuilder, body: () -> Unit) { to.appendln("<table class=\"api-docs-table\">") body() diff --git a/src/Formats/MarkdownFormatService.kt b/src/Formats/MarkdownFormatService.kt index a835a673..8f9699c2 100644 --- a/src/Formats/MarkdownFormatService.kt +++ b/src/Formats/MarkdownFormatService.kt @@ -30,10 +30,14 @@ public open class MarkdownFormatService(locationService: LocationService, return "`$code`" } - override public fun formatBold(text: String): String { + override public fun formatStrong(text: String): String { return "**$text**" } + override fun formatEmphasis(text: String): String { + return "*$text*" + } + override public fun formatLink(text: String, location: Location): String { return "[$text](${location.path})" } @@ -51,7 +55,9 @@ public open class MarkdownFormatService(locationService: LocationService, } override public fun appendText(to: StringBuilder, text: String) { - to.append(text) + to.appendln() + to.appendln(text) + to.appendln() } override public fun appendHeader(to: StringBuilder, text: String, level: Int) { diff --git a/src/Formats/StructuredFormatService.kt b/src/Formats/StructuredFormatService.kt index df11b835..280aa6b5 100644 --- a/src/Formats/StructuredFormatService.kt +++ b/src/Formats/StructuredFormatService.kt @@ -27,7 +27,8 @@ public abstract class StructuredFormatService(val locationService: LocationServi 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 formatStrong(text: String): String + public abstract fun formatEmphasis(text: String): String public abstract fun formatCode(code: String): String public abstract fun formatBreadcrumbs(items: Iterable<FormatLink>): String @@ -42,7 +43,9 @@ public abstract class StructuredFormatService(val locationService: LocationServi is ContentSymbol -> append(formatSymbol(content.text)) is ContentKeyword -> append(formatKeyword(content.text)) is ContentIdentifier -> append(formatIdentifier(content.text)) - is ContentEmphasis -> append(formatBold(formatText(location, content.children))) + is ContentStrong -> append(formatStrong(formatText(location, content.children))) + is ContentCode -> append(formatCode(formatText(location, content.children))) + is ContentEmphasis -> append(formatEmphasis(formatText(location, content.children))) is ContentNodeLink -> { val linkTo = locationService.relativeLocation(location, content.node, extension) val linkText = formatText(location, content.children) @@ -52,6 +55,12 @@ public abstract class StructuredFormatService(val locationService: LocationServi val linkText = formatText(location, content.children) append(formatLink(linkText, content.href)) } + is ContentParagraph -> { + appendText(this, formatText(location, content.children)) + } + is ContentBlockCode -> { + appendBlockCode(this, formatText(location, content.children)) + } else -> append(formatText(location, content.children)) } }.toString() @@ -64,7 +73,7 @@ public abstract class StructuredFormatService(val locationService: LocationServi } fun appendDescription(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) { - val described = nodes.filter { !it.doc.isEmpty } + val described = nodes.filter { !it.content.isEmpty } if (described.any()) { val single = described.size == 1 appendHeader(to, "Description", 3) @@ -72,14 +81,15 @@ public abstract class StructuredFormatService(val locationService: LocationServi if (!single) { appendBlockCode(to, formatText(location, languageService.render(node))) } - appendLine(to, formatText(location,node.doc.description)) + appendLine(to, formatText(location,node.content.description)) appendLine(to) - for ((label, section) in node.doc.sections) { + for ((label, section) in node.content.sections) { if (label.startsWith("$")) continue - appendLine(to, formatBold(formatText(label))) + if (node.members.any { it.name == label }) + continue + appendLine(to, formatStrong(formatText(label))) appendLine(to, formatText(location, section)) - appendLine(to) } } } @@ -87,14 +97,14 @@ public abstract class StructuredFormatService(val locationService: LocationServi fun appendSummary(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) { val breakdownBySummary = nodes.groupByTo(LinkedHashMap()) { node -> - node.doc.summary + formatText(location, node.summary) } for ((summary, items) in breakdownBySummary) { items.forEach { appendBlockCode(to, formatText(location, languageService.render(it))) } - appendLine(to, formatText(location, summary)) + appendLine(to, summary) appendLine(to) } } @@ -123,14 +133,14 @@ public abstract class StructuredFormatService(val locationService: LocationServi appendText(to, formatLink(memberLocation)) } appendTableCell(to) { - val breakdownBySummary = members.groupBy { it.doc.summary } + val breakdownBySummary = members.groupBy { formatText(location, it.summary) } for ((summary, items) in breakdownBySummary) { for (signature in items) { appendBlockCode(to, formatText(location, languageService.render(signature))) } if (!summary.isEmpty()) { - appendText(to, formatText(location, summary)) + appendText(to, summary) } } } diff --git a/src/Formats/TextFormatService.kt b/src/Formats/TextFormatService.kt index 63d2ce42..4e43cbcc 100644 --- a/src/Formats/TextFormatService.kt +++ b/src/Formats/TextFormatService.kt @@ -7,9 +7,9 @@ public class TextFormatService(val signatureGenerator: LanguageService) : Format with (to) { appendln(signatureGenerator.render(node)) appendln() - appendln(node.doc.summary) + appendln(node.content.summary) - for ((label, section) in node.doc.sections) { + for ((label, section) in node.content.sections) { appendln(label) } } diff --git a/src/Generation/ConsoleGenerator.kt b/src/Generation/ConsoleGenerator.kt index 78164bb9..f52c6f4b 100644 --- a/src/Generation/ConsoleGenerator.kt +++ b/src/Generation/ConsoleGenerator.kt @@ -13,7 +13,7 @@ public class ConsoleGenerator(val signatureGenerator: LanguageService, val locat public fun generateHeader(node: DocumentationNode, indent: String = "") { println(indent + signatureGenerator.render(node)) - val docString = node.doc.toString() + val docString = node.content.toString() if (!docString.isEmpty()) println("$indent\"${docString.replace("\n", "\n$indent")}\"") println() diff --git a/src/Kotlin/ContentBuilder.kt b/src/Kotlin/ContentBuilder.kt index b7290b58..635fc74f 100644 --- a/src/Kotlin/ContentBuilder.kt +++ b/src/Kotlin/ContentBuilder.kt @@ -2,15 +2,20 @@ package org.jetbrains.dokka import org.jetbrains.markdown.MarkdownElementTypes import java.util.ArrayDeque +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor +import org.jetbrains.jet.lang.resolve.name.Name +import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils +import org.jetbrains.jet.lang.resolve.scopes.JetScope +import org.jetbrains.jet.lang.resolve.name.FqName -public fun MarkdownTree.toContent(): Content { +public fun DocumentationBuilder.buildContent(tree: MarkdownTree, descriptor: DeclarationDescriptor): Content { val nodeStack = ArrayDeque<ContentNode>() nodeStack.push(Content()) - visit {(node, text, processChildren) -> + tree.visit {(node, text, processChildren) -> val parent = nodeStack.peek()!! val nodeType = node.getTokenType() - val nodeText = getNodeText(node) + val nodeText = tree.getNodeText(node) when (nodeType) { MarkdownElementTypes.BULLET_LIST -> { nodeStack.push(ContentList()) @@ -39,20 +44,32 @@ public fun MarkdownTree.toContent(): Content { processChildren() parent.append(nodeStack.pop()) } + MarkdownElementTypes.CODE -> { + nodeStack.push(ContentCode()) + processChildren() + parent.append(nodeStack.pop()) + } MarkdownElementTypes.ANONYMOUS_SECTION -> { nodeStack.push(ContentSection("")) processChildren() parent.append(nodeStack.pop()) } + MarkdownElementTypes.DIRECTIVE -> { + val name = tree.findChildByType(node, MarkdownElementTypes.DIRECTIVE_NAME)?.let { tree.getNodeText(it) } ?: "" + val params = tree.findChildByType(node, MarkdownElementTypes.DIRECTIVE_PARAMS)?.let { tree.getNodeText(it) } ?: "" + when (name) { + "code" -> parent.append(functionBody(descriptor, params)) + } + } MarkdownElementTypes.NAMED_SECTION -> { - val label = findChildByType(node, MarkdownElementTypes.SECTION_NAME)?.let { getNodeText(it) } ?: "" + val label = tree.findChildByType(node, MarkdownElementTypes.SECTION_NAME)?.let { tree.getNodeText(it) } ?: "" nodeStack.push(ContentSection(label)) processChildren() 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 target = tree.findChildByType(node, MarkdownElementTypes.TARGET)?.let { tree.getNodeText(it) } ?: "" + val href = tree.findChildByType(node, MarkdownElementTypes.HREF)?.let { tree.getNodeText(it) } val link = if (href != null) ContentExternalLink(href) else ContentExternalLink(target) link.append(ContentText(target)) parent.append(link) @@ -71,7 +88,7 @@ public fun MarkdownTree.toContent(): Content { processChildren() } MarkdownElementTypes.PARA -> { - nodeStack.push(ContentBlock()) + nodeStack.push(ContentParagraph()) processChildren() parent.append(nodeStack.pop()) } @@ -84,3 +101,41 @@ public fun MarkdownTree.toContent(): Content { } +fun DocumentationBuilder.functionBody(descriptor: DeclarationDescriptor, functionName: String): ContentNode { + val scope = getResolutionScope(descriptor) + val rootPackage = session.getModuleDescriptor().getPackage(FqName.ROOT)!! + val rootScope = rootPackage.getMemberScope() + val symbol = resolveInScope(functionName, scope) ?: resolveInScope(functionName, rootScope) + if (symbol == null) + return ContentBlockCode().let() { it.append(ContentText("Unresolved: $functionName")); it } + val psiElement = DescriptorToSourceUtils.descriptorToDeclaration(symbol) + if (psiElement == null) + return ContentBlockCode().let() { it.append(ContentText("Source not found: $functionName")); it } + + return ContentBlockCode().let() { it.append(ContentText(psiElement.getText())); it } +} + +private fun DocumentationBuilder.resolveInScope(functionName: String, scope: JetScope): DeclarationDescriptor? { + var currentScope = scope + val parts = functionName.split('.') + var symbol: DeclarationDescriptor? = null + + for (part in parts) { + // short name + val symbolName = Name.guess(part) + val partSymbol = currentScope.getLocalVariable(symbolName) ?: + currentScope.getProperties(symbolName).firstOrNull() ?: + currentScope.getFunctions(symbolName).firstOrNull() ?: + currentScope.getClassifier(symbolName) ?: + currentScope.getPackage(symbolName) + + if (partSymbol == null) { + symbol = null + break + } + currentScope = getResolutionScope(partSymbol) + symbol = partSymbol + } + + return symbol +}
\ No newline at end of file diff --git a/src/Kotlin/Diagnostics.kt b/src/Kotlin/Diagnostics.kt deleted file mode 100644 index 5548bc01..00000000 --- a/src/Kotlin/Diagnostics.kt +++ /dev/null @@ -1,40 +0,0 @@ -package org.jetbrains.dokka - -import org.jetbrains.jet.lang.descriptors.* -import org.jetbrains.jet.lang.resolve.name.* -import org.jetbrains.jet.lang.resolve.BindingContext - -fun DocumentationContext.checkResolveChildren(node: DocumentationNode) { - if (node.kind != DocumentationNode.Kind.Module && node.kind != DocumentationNode.Kind.Package) { - // TODO: we don't resolve packages and modules for now - - val parentScope = getResolutionScope(node) - for (item in node.details + node.members) { - val symbolName = item.name - val symbol: DeclarationDescriptor? = when (item.kind) { - DocumentationNode.Kind.Modifier -> continue // do not resolve modifiers, they are not names - DocumentationNode.Kind.Receiver -> continue // what is receiver's name in platform? - DocumentationNode.Kind.Parameter -> parentScope.getLocalVariable(Name.guess(symbolName)) - DocumentationNode.Kind.Function -> parentScope.getFunctions(Name.guess(symbolName)).firstOrNull() - DocumentationNode.Kind.Property -> parentScope.getProperties(Name.guess(symbolName)).firstOrNull() - DocumentationNode.Kind.Constructor -> parentScope.getFunctions(Name.guess(symbolName)).firstOrNull() - else -> parentScope.getClassifier(Name.guess(symbolName)) - } - - if (symbol == null) - println("WARNING: Cannot resolve $item in ${path(node)}") - } - } - - for (reference in node.allReferences().filterNot { it.kind == DocumentationReference.Kind.Owner }) { - checkResolveChildren(reference.to) - } -} - -fun path(node: DocumentationNode): String { - val owner = node.owner - if (owner != null) - return "$node in ${path(owner)}" - else - return "$node" -}
\ No newline at end of file diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt new file mode 100644 index 00000000..f91c922c --- /dev/null +++ b/src/Kotlin/DocumentationBuilder.kt @@ -0,0 +1,329 @@ +package org.jetbrains.dokka + +import org.jetbrains.jet.lang.descriptors.* +import org.jetbrains.dokka.DocumentationNode.Kind +import org.jetbrains.jet.lang.types.TypeProjection +import org.jetbrains.jet.lang.types.Variance +import org.jetbrains.jet.lang.types.JetType +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.resolve.name.Name +import org.jetbrains.jet.lang.resolve.scopes.JetScope +import org.jetbrains.jet.lang.psi.JetFile +import org.jetbrains.jet.lang.resolve.name.FqName +import org.jetbrains.jet.lang.resolve.lazy.ResolveSession + +public data class DocumentationOptions(val includeNonPublic: Boolean = false) + +class DocumentationBuilder(val session: ResolveSession, val options: DocumentationOptions) { + val visibleToDocumentation = setOf(Visibilities.INTERNAL, Visibilities.PROTECTED, Visibilities.PUBLIC) + val descriptorToNode = hashMapOf<DeclarationDescriptor, DocumentationNode>() + val nodeToDescriptor = hashMapOf<DocumentationNode, DeclarationDescriptor>() + val links = hashMapOf<DocumentationNode, DeclarationDescriptor>() + val packages = hashMapOf<FqName, DocumentationNode>() + + fun parseDocumentation(descriptor: DeclarationDescriptor): Content { + val docText = descriptor.getDocumentationElements().map { it.extractText() }.join("\n") + val tree = MarkdownProcessor.parse(docText) + //println(tree.toTestString()) + val content = buildContent(tree, descriptor) + return content + } + + fun link(node: DocumentationNode, descriptor: DeclarationDescriptor) { + links.put(node, descriptor) + } + + 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 { + val doc = parseDocumentation(descriptor) + val node = DocumentationNode(descriptor.getName().asString(), doc, kind) + if (descriptor is MemberDescriptor) { + if (descriptor !is ConstructorDescriptor) { + node.appendModality(descriptor) + } + node.appendVisibility(descriptor) + } + return node + } + + fun DocumentationNode.append(child: DocumentationNode, kind: DocumentationReference.Kind) { + addReferenceTo(child, kind) + when (kind) { + DocumentationReference.Kind.Detail -> child.addReferenceTo(this, DocumentationReference.Kind.Owner) + DocumentationReference.Kind.Member -> child.addReferenceTo(this, DocumentationReference.Kind.Owner) + DocumentationReference.Kind.Owner -> child.addReferenceTo(this, DocumentationReference.Kind.Member) + } + } + + fun DocumentationNode.appendModality(descriptor: MemberDescriptor) { + val modifier = descriptor.getModality().name().toLowerCase() + val node = DocumentationNode(modifier, Content.Empty, DocumentationNode.Kind.Modifier) + append(node, DocumentationReference.Kind.Detail) + } + + fun DocumentationNode.appendVisibility(descriptor: DeclarationDescriptorWithVisibility) { + val modifier = descriptor.getVisibility().toString() + val node = DocumentationNode(modifier, Content.Empty, DocumentationNode.Kind.Modifier) + append(node, DocumentationReference.Kind.Detail) + } + + fun DocumentationNode.appendSupertypes(descriptor: ClassDescriptor) { + val superTypes = descriptor.getTypeConstructor().getSupertypes() + for (superType in superTypes) { + if (superType.toString() != "Any") + appendType(superType, DocumentationNode.Kind.Supertype) + } + } + + fun DocumentationNode.appendProjection(projection: TypeProjection, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type) { + val prefix = when (projection.getProjectionKind()) { + Variance.IN_VARIANCE -> "in " + Variance.OUT_VARIANCE -> "out " + else -> "" + } + appendType(projection.getType(), kind, prefix) + } + + fun DocumentationNode.appendType(jetType: JetType?, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type, prefix: String = "") { + if (jetType == null) + return + val classifierDescriptor = jetType.getConstructor().getDeclarationDescriptor() + val name = when (classifierDescriptor) { + is Named -> prefix + classifierDescriptor.getName().asString() + if (jetType.isNullable()) "?" else "" + else -> "<anonymous>" + } + val node = DocumentationNode(name, Content.Empty, kind) + if (classifierDescriptor != null) + link(node, classifierDescriptor) + + append(node, DocumentationReference.Kind.Detail) + for (typeArgument in jetType.getArguments()) + node.appendProjection(typeArgument) + } + + fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: DocumentationReference.Kind) { + // do not include generated code + if (descriptor is CallableMemberDescriptor && descriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION) + return + + if (options.includeNonPublic + || descriptor !is MemberDescriptor + || descriptor.getVisibility() in visibleToDocumentation) { + append(descriptor.build(), kind) + } + } + + fun DocumentationNode.appendChildren(descriptors: Iterable<DeclarationDescriptor>, kind: DocumentationReference.Kind) { + descriptors.forEach { descriptor -> appendChild(descriptor, kind) } + } + + fun DocumentationNode.appendFragments(fragments: Collection<PackageFragmentDescriptor>) { + val descriptors = hashMapOf<String, List<DeclarationDescriptor>>() + for ((name, parts) in fragments.groupBy { it.fqName }) { + descriptors.put(name.asString(), parts.flatMap { it.getMemberScope().getAllDescriptors() }) + } + for ((packageName, declarations) in descriptors) { + println(" package $packageName: ${declarations.count()} nodes") + val packageNode = DocumentationNode(packageName, Content.Empty, Kind.Package) + packageNode.appendChildren(declarations, DocumentationReference.Kind.Member) + append(packageNode, DocumentationReference.Kind.Member) + } + } + + fun DeclarationDescriptor.build(): DocumentationNode = when (this) { + is ClassDescriptor -> build() + is ConstructorDescriptor -> build() + is ScriptDescriptor -> build() + is FunctionDescriptor -> build() + is PropertyDescriptor -> build() + is PropertyGetterDescriptor -> build() + is PropertySetterDescriptor -> build() + is TypeParameterDescriptor -> build() + is ValueParameterDescriptor -> build() + is ReceiverParameterDescriptor -> build() + else -> throw IllegalStateException("Descriptor $this is not known") + } + + fun ScriptDescriptor.build(): DocumentationNode = getClassDescriptor().build() + fun ClassDescriptor.build(): DocumentationNode { + val kind = when (getKind()) { + ClassKind.OBJECT -> Kind.Object + ClassKind.CLASS_OBJECT -> Kind.Object + ClassKind.TRAIT -> Kind.Interface + ClassKind.ENUM_CLASS -> Kind.Enum + ClassKind.ENUM_ENTRY -> Kind.EnumItem + else -> Kind.Class + } + val node = DocumentationNode(this, kind) + node.appendSupertypes(this) + if (getKind() != ClassKind.OBJECT) { + node.appendChildren(getTypeConstructor().getParameters(), DocumentationReference.Kind.Detail) + node.appendChildren(getConstructors(), DocumentationReference.Kind.Member) + val classObjectDescriptor = getClassObjectDescriptor() + if (classObjectDescriptor != null) + node.appendChild(classObjectDescriptor, DocumentationReference.Kind.Member) + } + node.appendChildren(getDefaultType().getMemberScope().getAllDescriptors(), DocumentationReference.Kind.Member) + register(this, node) + return node + } + + fun ConstructorDescriptor.build(): DocumentationNode { + val node = DocumentationNode(this, Kind.Constructor) + node.appendChildren(getValueParameters(), DocumentationReference.Kind.Detail) + register(this, node) + return node + } + + fun FunctionDescriptor.build(): DocumentationNode { + val node = DocumentationNode(this, Kind.Function) + + node.appendChildren(getTypeParameters(), DocumentationReference.Kind.Detail) + getExtensionReceiverParameter()?.let { node.appendChild(it, DocumentationReference.Kind.Detail) } + node.appendChildren(getValueParameters(), DocumentationReference.Kind.Detail) + node.appendType(getReturnType()) + register(this, node) + return node + + } + + fun PropertyDescriptor.build(): DocumentationNode { + val node = DocumentationNode(this, Kind.Property) + node.appendChildren(getTypeParameters(), DocumentationReference.Kind.Detail) + getExtensionReceiverParameter()?.let { node.appendChild(it, DocumentationReference.Kind.Detail) } + node.appendType(getReturnType()) + getGetter()?.let { + if (!it.isDefault()) + node.appendChild(it, DocumentationReference.Kind.Member) + } + getSetter()?.let { + if (!it.isDefault()) + node.appendChild(it, DocumentationReference.Kind.Member) + } + + register(this, node) + return node + } + + fun ValueParameterDescriptor.build(): DocumentationNode { + val node = DocumentationNode(this, Kind.Parameter) + node.appendType(getType()) + return node + } + + fun TypeParameterDescriptor.build(): DocumentationNode { + val doc = parseDocumentation(this) + val name = getName().asString() + val prefix = when (getVariance()) { + Variance.IN_VARIANCE -> "in " + Variance.OUT_VARIANCE -> "out " + else -> "" + } + + val node = DocumentationNode(prefix + name, doc, DocumentationNode.Kind.TypeParameter) + + val builtIns = KotlinBuiltIns.getInstance() + for (constraint in getUpperBounds()) { + if (constraint == builtIns.getDefaultBound()) + continue + val constraintNode = DocumentationNode(constraint.toString(), Content.Empty, DocumentationNode.Kind.UpperBound) + node.append(constraintNode, DocumentationReference.Kind.Detail) + } + + for (constraint in getLowerBounds()) { + if (builtIns.isNothing(constraint)) + continue + val constraintNode = DocumentationNode(constraint.toString(), Content.Empty, DocumentationNode.Kind.LowerBound) + node.append(constraintNode, DocumentationReference.Kind.Detail) + } + return node + } + + fun ReceiverParameterDescriptor.build(): DocumentationNode { + val node = DocumentationNode(getName().asString(), Content.Empty, Kind.Receiver) + node.appendType(getType()) + return node + } + + /** + * 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 resolveReferences(node: DocumentationNode) { + node.details(DocumentationNode.Kind.Receiver).forEach { detail -> + val receiverType = detail.detail(DocumentationNode.Kind.Type) + val descriptor = links[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 = links[detail] + if (descriptor != null) { + val typeNode = descriptorToNode[descriptor] + typeNode?.addReferenceTo(node, DocumentationReference.Kind.Inheritor) + } + } + node.details.forEach { detail -> + val descriptor = links[detail] + if (descriptor != null) { + val typeNode = descriptorToNode[descriptor] + if (typeNode != null) { + detail.addReferenceTo(typeNode, DocumentationReference.Kind.Link) + } + } + } + + resolveContentLinks(node, node.content) + + for (child in node.members) { + resolveReferences(child) + } + for (child in node.details) { + resolveReferences(child) + } + } + + fun getResolutionScope(node: DocumentationNode): JetScope { + val descriptor = nodeToDescriptor[node] ?: throw IllegalArgumentException("Node is not known to this context") + return getResolutionScope(descriptor) + } + + fun resolveContentLinks(node: DocumentationNode, content: ContentNode) { + val snapshot = content.children.toList() + for (child in snapshot) { + if (child is ContentExternalLink) { + val referenceText = child.href + if (Name.isValidIdentifier(referenceText)) { + val scope = getResolutionScope(node) + val symbolName = Name.guess(referenceText) + val symbol = scope.getLocalVariable(symbolName) ?: + scope.getProperties(symbolName).firstOrNull() ?: + scope.getFunctions(symbolName).firstOrNull() ?: + scope.getClassifier(symbolName) + + if (symbol != null) { + val targetNode = descriptorToNode[symbol] + val contentLink = if (targetNode != null) ContentNodeLink(targetNode) else ContentExternalLink("#") + + val index = content.children.indexOf(child) + content.children.remove(index) + contentLink.children.addAll(child.children) + content.children.add(index, contentLink) + } + } + } + resolveContentLinks(node, child) + } + } +}
\ No newline at end of file diff --git a/src/Kotlin/DocumentationBuildingVisitor.kt b/src/Kotlin/DocumentationBuildingVisitor.kt deleted file mode 100644 index 81ac2430..00000000 --- a/src/Kotlin/DocumentationBuildingVisitor.kt +++ /dev/null @@ -1,127 +0,0 @@ -package org.jetbrains.dokka - -import org.jetbrains.jet.lang.descriptors.* -import org.jetbrains.jet.lang.resolve.name.* -import org.jetbrains.jet.lang.resolve.* - -public data class DocumentationOptions(val includeNonPublic: Boolean = false) - -class DocumentationBuildingVisitor(val context: BindingContext, - val options: DocumentationOptions, - private val worker: DeclarationDescriptorVisitor<DocumentationNode, DocumentationNode>) -: DeclarationDescriptorVisitor<DocumentationNode, DocumentationNode> { - - val visibleToDocumentation = setOf(Visibilities.INTERNAL, Visibilities.PROTECTED, Visibilities.PUBLIC) - - private fun visitChildren(descriptors: Collection<DeclarationDescriptor>, data: DocumentationNode) { - for (descriptor in descriptors) { - visitChild(descriptor, data) - } - } - - private fun visitChild(descriptor: DeclarationDescriptor?, data: DocumentationNode) { - if (descriptor != null && descriptor.isUserCode()) { - if (options.includeNonPublic - || descriptor !is MemberDescriptor - || descriptor.getVisibility() in visibleToDocumentation) { - descriptor.accept(this, data) - } - } - } - - private fun createDocumentation(descriptor: DeclarationDescriptor, data: DocumentationNode): DocumentationNode { - return descriptor.accept(worker, data) - } - - private fun processCallable(descriptor: CallableDescriptor, data: DocumentationNode): DocumentationNode { - val node = createDocumentation(descriptor, data) - visitChildren(descriptor.getTypeParameters(), node) - visitChild(descriptor.getExtensionReceiverParameter(), node) - visitChildren(descriptor.getValueParameters(), node) - return node - } - - public override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = createDocumentation(descriptor!!, data!!) - visitChildren(descriptor.getMemberScope().getAllDescriptors(), node) - return node - } - - public override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = createDocumentation(descriptor!!, data!!) - visitChildren(descriptor.getMemberScope().getAllDescriptors(), node) - return node - } - - public override fun visitVariableDescriptor(descriptor: VariableDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = processCallable(descriptor!!, data!!) - return node - } - - public override fun visitPropertyDescriptor(descriptor: PropertyDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = processCallable(descriptor!!, data!!) - visitChild(descriptor.getGetter(), node) - visitChild(descriptor.getSetter(), node) - return node - } - - public override fun visitFunctionDescriptor(descriptor: FunctionDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = processCallable(descriptor!!, data!!) - return node - } - - public override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = createDocumentation(descriptor!!, data!!) - return node - } - - public override fun visitClassDescriptor(descriptor: ClassDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = createDocumentation(descriptor!!, data!!) - if (descriptor.getKind() != ClassKind.OBJECT) { - // do not go inside object for class object and constructors, they are generated - visitChildren(descriptor.getTypeConstructor().getParameters(), node) - visitChildren(descriptor.getConstructors(), node) - visitChild(descriptor.getClassObjectDescriptor(), node) - } - visitChildren(descriptor.getDefaultType().getMemberScope().getAllDescriptors(), node) - return node - } - - public override fun visitModuleDeclaration(descriptor: ModuleDescriptor, data: DocumentationNode): DocumentationNode { - val node = createDocumentation(descriptor, data) - visitChild(descriptor.getPackage(FqName.ROOT), node) - return node - } - - public override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = createDocumentation(descriptor!!, data!!) - visitChildren(descriptor.getValueParameters(), node) - return node - } - - public override fun visitScriptDescriptor(scriptDescriptor: ScriptDescriptor?, data: DocumentationNode?): DocumentationNode? { - val classDescriptor = scriptDescriptor!!.getClassDescriptor() - val node = visitClassDescriptor(classDescriptor, data) - return node - } - - public override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = visitVariableDescriptor(descriptor!!, data) - return node - } - - public override fun visitPropertyGetterDescriptor(descriptor: PropertyGetterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = visitFunctionDescriptor(descriptor!!, data) - return node - } - - public override fun visitPropertySetterDescriptor(descriptor: PropertySetterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = visitFunctionDescriptor(descriptor!!, data) - return node - } - - public override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { - val node = createDocumentation(descriptor!!, data!!) - return node - } -} diff --git a/src/Kotlin/DocumentationContext.kt b/src/Kotlin/DocumentationContext.kt deleted file mode 100644 index 95c3ded1..00000000 --- a/src/Kotlin/DocumentationContext.kt +++ /dev/null @@ -1,62 +0,0 @@ -package org.jetbrains.dokka - -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor -import org.jetbrains.jet.lang.resolve.BindingContext -import org.jetbrains.jet.lang.resolve.scopes.JetScope -import org.jetbrains.jet.lang.descriptors.ModuleDescriptor -import org.jetbrains.jet.lang.resolve.name.FqName - -/** - * Context for documentation generation. - * - * Holds information about relations between [nodes](DocumentationNode) and [descriptors](DeclarationDescriptor) during documentation generation - * - * $bindingContext: symbol resolution context - */ -public class DocumentationContext(val bindingContext: BindingContext) { - val descriptorToNode = hashMapOf<DeclarationDescriptor, DocumentationNode>() - val nodeToDescriptor = hashMapOf<DocumentationNode, DeclarationDescriptor>() - - val relations = hashMapOf<DocumentationNode, DeclarationDescriptor>() - - fun attach(node: DocumentationNode, descriptor: DeclarationDescriptor) { - relations.put(node, descriptor) - } - - fun register(descriptor: DeclarationDescriptor, node: DocumentationNode) { - descriptorToNode.put(descriptor, node) - nodeToDescriptor.put(node, descriptor) - } - - fun getResolutionScope(node: DocumentationNode): JetScope { - val descriptor = nodeToDescriptor[node] ?: throw IllegalArgumentException("Node is not known to this context") - return bindingContext.getResolutionScope(descriptor) - } - - fun parseDocumentation(descriptor: DeclarationDescriptor): Content { - val docText = bindingContext.getDocumentationElements(descriptor).map { it.extractText() }.join("\n") - val tree = MarkdownProcessor.parse(docText) - //println(tree.toTestString()) - val content = tree.toContent() - return content - } -} - -fun BindingContext.createDocumentationModule(name: String, - module: ModuleDescriptor, - packages: Set<FqName>, - options: DocumentationOptions = DocumentationOptions()): DocumentationModule { - val documentationModule = DocumentationModule(name) - val context = DocumentationContext(this) - val visitor = DocumentationNodeBuilder(context) - for (packageName in packages) { - val pkg = module.getPackage(packageName) - pkg!!.accept(DocumentationBuildingVisitor(this, options, visitor), documentationModule) - } - - context.resolveReferences(documentationModule) - - // TODO: Uncomment for resolve verification - // checkResolveChildren(documentationModule) - return documentationModule -} diff --git a/src/Kotlin/DocumentationNodeBuilder.kt b/src/Kotlin/DocumentationNodeBuilder.kt deleted file mode 100644 index 8f77a3d6..00000000 --- a/src/Kotlin/DocumentationNodeBuilder.kt +++ /dev/null @@ -1,206 +0,0 @@ -package org.jetbrains.dokka - -import org.jetbrains.jet.lang.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies -import org.jetbrains.jet.lang.descriptors.MemberDescriptor -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor -import org.jetbrains.jet.lang.types.JetType -import org.jetbrains.jet.lang.descriptors.Named -import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor -import org.jetbrains.jet.lang.descriptors.ClassDescriptor -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor -import org.jetbrains.jet.lang.descriptors.PropertyDescriptor -import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor -import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor -import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor -import org.jetbrains.jet.lang.descriptors.ClassKind -import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns -import org.jetbrains.jet.lang.types.TypeProjection -import org.jetbrains.jet.lang.types.Variance - -class DocumentationNodeBuilder(val context: DocumentationContext) : DeclarationDescriptorVisitorEmptyBodies<DocumentationNode, DocumentationNode>() { - - fun reference(from: DocumentationNode, to: DocumentationNode, kind: DocumentationReference.Kind) { - from.addReferenceTo(to, kind) - when (kind) { - DocumentationReference.Kind.Detail -> to.addReferenceTo(from, DocumentationReference.Kind.Owner) - DocumentationReference.Kind.Member -> to.addReferenceTo(from, DocumentationReference.Kind.Owner) - DocumentationReference.Kind.Owner -> to.addReferenceTo(from, DocumentationReference.Kind.Member) - } - } - - fun addModality(descriptor: MemberDescriptor, data: DocumentationNode) { - val modifier = descriptor.getModality().name().toLowerCase() - val node = DocumentationNode(modifier, Content.Empty, DocumentationNode.Kind.Modifier) - reference(data, node, DocumentationReference.Kind.Detail) - } - - fun addVisibility(descriptor: MemberDescriptor, data: DocumentationNode) { - val modifier = descriptor.getVisibility().toString() - val node = DocumentationNode(modifier, Content.Empty, DocumentationNode.Kind.Modifier) - reference(data, node, DocumentationReference.Kind.Detail) - } - - fun addSupertypes(descriptor: ClassDescriptor, data: DocumentationNode) { - val superTypes = descriptor.getTypeConstructor().getSupertypes() - for (superType in superTypes) { - if (superType.toString() != "Any") - addType(superType, data, DocumentationNode.Kind.Supertype) - } - } - - fun addProjection(projection: TypeProjection, data: DocumentationNode, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type) { - val prefix = when (projection.getProjectionKind()) { - Variance.IN_VARIANCE -> "in " - Variance.OUT_VARIANCE -> "out " - else -> "" - } - addType(projection.getType(), data, kind, prefix) - } - - fun addType(jetType: JetType?, data: DocumentationNode, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type, prefix : String = "") { - if (jetType == null) - return - val classifierDescriptor = jetType.getConstructor().getDeclarationDescriptor() - val name = when (classifierDescriptor) { - is Named -> prefix + classifierDescriptor.getName().asString() + if (jetType.isNullable()) "?" else "" - else -> "<anonymous>" - } - val node = DocumentationNode(name, Content.Empty, kind) - if (classifierDescriptor != null) - context.attach(node, classifierDescriptor) - - reference(data, node, DocumentationReference.Kind.Detail) - for (typeArgument in jetType.getArguments()) - addProjection(typeArgument, node) - } - - override fun visitDeclarationDescriptor(descriptor: DeclarationDescriptor?, data: DocumentationNode?): DocumentationNode? { - descriptor!! - val doc = context.parseDocumentation(descriptor) - val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Unknown) - reference(data!!, node, DocumentationReference.Kind.Member) - context.register(descriptor, node) - return node - } - - override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { - descriptor!! - val node = DocumentationNode(descriptor.getName().asString(), Content.Empty, DocumentationNode.Kind.Receiver) - reference(data!!, node, DocumentationReference.Kind.Detail) - - addType(descriptor.getType(), node) - - return node - } - - override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { - descriptor!! - val doc = context.parseDocumentation(descriptor) - val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Parameter) - reference(data!!, node, DocumentationReference.Kind.Detail) - - addType(descriptor.getType(), node) - - return node - } - - override fun visitClassDescriptor(descriptor: ClassDescriptor?, data: DocumentationNode?): DocumentationNode? { - descriptor!! - val doc = context.parseDocumentation(descriptor) - val node = DocumentationNode(descriptor.getName().asString(), doc, when (descriptor.getKind()) { - ClassKind.OBJECT -> org.jetbrains.dokka.DocumentationNode.Kind.Object - ClassKind.CLASS_OBJECT -> org.jetbrains.dokka.DocumentationNode.Kind.Object - ClassKind.TRAIT -> org.jetbrains.dokka.DocumentationNode.Kind.Interface - ClassKind.ENUM_CLASS -> org.jetbrains.dokka.DocumentationNode.Kind.Enum - ClassKind.ENUM_ENTRY -> org.jetbrains.dokka.DocumentationNode.Kind.EnumItem - else -> DocumentationNode.Kind.Class - }) - reference(data!!, node, DocumentationReference.Kind.Member) - addModality(descriptor, node) - addVisibility(descriptor, node) - addSupertypes(descriptor, node) - context.register(descriptor, node) - return node - } - - override fun visitFunctionDescriptor(descriptor: FunctionDescriptor?, data: DocumentationNode?): DocumentationNode? { - descriptor!! - val doc = context.parseDocumentation(descriptor) - val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Function) - reference(data!!, node, DocumentationReference.Kind.Member) - - addType(descriptor.getReturnType(), node) - addModality(descriptor, node) - addVisibility(descriptor, node) - context.register(descriptor, node) - return node - } - - override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor?, data: DocumentationNode?): DocumentationNode? { - descriptor!! - val doc = context.parseDocumentation(descriptor) - val name = descriptor.getName().asString() - val prefix = when (descriptor.getVariance()) { - Variance.IN_VARIANCE -> "in " - Variance.OUT_VARIANCE -> "out " - else -> "" - } - - val node = DocumentationNode(prefix + name, doc, DocumentationNode.Kind.TypeParameter) - reference(data!!, node, DocumentationReference.Kind.Detail) - val builtIns = KotlinBuiltIns.getInstance() - for (constraint in descriptor.getUpperBounds()) { - if (constraint == builtIns.getDefaultBound()) - continue - val constraintNode = DocumentationNode(constraint.toString(), Content.Empty, DocumentationNode.Kind.UpperBound) - reference(node, constraintNode, DocumentationReference.Kind.Detail) - } - for (constraint in descriptor.getLowerBounds()) { - if (builtIns.isNothing(constraint)) - continue - val constraintNode = DocumentationNode(constraint.toString(), Content.Empty, DocumentationNode.Kind.LowerBound) - reference(node, constraintNode, DocumentationReference.Kind.Detail) - } - return node - } - - override fun visitPropertyDescriptor(descriptor: PropertyDescriptor?, data: DocumentationNode?): DocumentationNode? { - descriptor!! - val doc = context.parseDocumentation(descriptor) - val node = DocumentationNode(descriptor.getName().asString(), doc, DocumentationNode.Kind.Property) - reference(data!!, node, DocumentationReference.Kind.Member) - - addType(descriptor.getType(), node) - addModality(descriptor, node) - addVisibility(descriptor, node) - context.register(descriptor, node) - return node - } - - override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor?, data: DocumentationNode?): DocumentationNode? { - descriptor!! - val doc = context.parseDocumentation(descriptor) - val node = DocumentationNode("<constructor>", doc, DocumentationNode.Kind.Constructor) - reference(data!!, node, DocumentationReference.Kind.Member) - - addVisibility(descriptor, node) - context.register(descriptor, node) - return node - } - - override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor?, data: DocumentationNode?): DocumentationNode? { - descriptor!! - val node = DocumentationNode(descriptor.getFqName().asString(), Content.Empty, DocumentationNode.Kind.Package) - reference(data!!, node, DocumentationReference.Kind.Member) - return node - } - - override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor?, data: DocumentationNode?): DocumentationNode? { - descriptor!! - val node = DocumentationNode(descriptor.fqName.asString(), Content.Empty, DocumentationNode.Kind.Package) - reference(data!!, node, DocumentationReference.Kind.Member) - return node - } -}
\ No newline at end of file diff --git a/src/Languages/KotlinLanguageService.kt b/src/Kotlin/KotlinLanguageService.kt index f806dd19..c7fabda9 100644 --- a/src/Languages/KotlinLanguageService.kt +++ b/src/Kotlin/KotlinLanguageService.kt @@ -1,29 +1,35 @@ package org.jetbrains.dokka -import org.jetbrains.dokka.DocumentationNode.* +import org.jetbrains.dokka.symbol +import org.jetbrains.dokka.text +import org.jetbrains.dokka.identifier +import org.jetbrains.dokka.link +import org.jetbrains.dokka.keyword +import org.jetbrains.dokka.LanguageService +import org.jetbrains.dokka.DocumentationNode +import org.jetbrains.dokka.ContentNode +import org.jetbrains.dokka +import org.jetbrains.dokka.ContentText -/** - * Implements [LanguageService] and provides rendering of symbols in Kotlin language - */ class KotlinLanguageService : LanguageService { override fun render(node: DocumentationNode): ContentNode { - return content { + return dokka.content { when (node.kind) { - Kind.Package -> renderPackage(node) - Kind.Class, - Kind.Interface, - Kind.Enum, - Kind.EnumItem, - Kind.Object -> renderClass(node) - - Kind.TypeParameter -> renderTypeParameter(node) - Kind.Type, - Kind.UpperBound -> renderType(node) - - Kind.Modifier -> renderModifier(node) - Kind.Constructor, - Kind.Function -> renderFunction(node) - Kind.Property -> renderProperty(node) + DocumentationNode.Kind.Package -> renderPackage(node) + DocumentationNode.Kind.Class, + DocumentationNode.Kind.Interface, + DocumentationNode.Kind.Enum, + DocumentationNode.Kind.EnumItem, + DocumentationNode.Kind.Object -> renderClass(node) + + DocumentationNode.Kind.TypeParameter -> renderTypeParameter(node) + DocumentationNode.Kind.Type, + DocumentationNode.Kind.UpperBound -> renderType(node) + + DocumentationNode.Kind.Modifier -> renderModifier(node) + DocumentationNode.Kind.Constructor, + DocumentationNode.Kind.Function -> renderFunction(node) + DocumentationNode.Kind.Property -> renderProperty(node) else -> ContentText("${node.kind}: ${node.name}") } } @@ -31,7 +37,7 @@ class KotlinLanguageService : LanguageService { override fun renderName(node: DocumentationNode): String { return when (node.kind) { - Kind.Constructor -> node.owner!!.name + DocumentationNode.Kind.Constructor -> node.owner!!.name else -> node.name } } @@ -63,7 +69,7 @@ class KotlinLanguageService : LanguageService { } private fun ContentNode.renderType(node: DocumentationNode) { - val typeArguments = node.details(Kind.Type) + val typeArguments = node.details(DocumentationNode.Kind.Type) if (node.name == "Function${typeArguments.count() - 1}") { // lambda symbol("(") @@ -104,14 +110,16 @@ class KotlinLanguageService : LanguageService { private fun ContentNode.renderModifier(node: DocumentationNode) { when (node.name) { - "final", "internal" -> { + "final", "internal" -> {} + else -> { + keyword(node.name) + text(" ") } - else -> keyword(node.name) } } private fun ContentNode.renderTypeParameter(node: DocumentationNode) { - val constraints = node.details(Kind.UpperBound) + val constraints = node.details(DocumentationNode.Kind.UpperBound) identifier(node.name) if (constraints.any()) { symbol(" : ") @@ -124,12 +132,12 @@ class KotlinLanguageService : LanguageService { private fun ContentNode.renderParameter(node: DocumentationNode) { identifier(node.name) symbol(": ") - val parameterType = node.detail(Kind.Type) + val parameterType = node.detail(DocumentationNode.Kind.Type) renderType(parameterType) } private fun ContentNode.renderTypeParametersForNode(node: DocumentationNode) { - val typeParameters = node.details(Kind.TypeParameter) + val typeParameters = node.details(DocumentationNode.Kind.TypeParameter) if (typeParameters.any()) { symbol("<") renderList(typeParameters) { @@ -140,7 +148,7 @@ class KotlinLanguageService : LanguageService { } private fun ContentNode.renderSupertypesForNode(node: DocumentationNode) { - val supertypes = node.details(Kind.Supertype) + val supertypes = node.details(DocumentationNode.Kind.Supertype) if (supertypes.any()) { symbol(" : ") renderList(supertypes) { @@ -150,23 +158,22 @@ class KotlinLanguageService : LanguageService { } private fun ContentNode.renderModifiersForNode(node: DocumentationNode) { - val modifiers = node.details(Kind.Modifier) + val modifiers = node.details(DocumentationNode.Kind.Modifier) for (it in modifiers) { - if (node.kind == Kind.Interface && it.name == "abstract") + if (node.kind == org.jetbrains.dokka.DocumentationNode.Kind.Interface && it.name == "abstract") continue renderModifier(it) - text(" ") } } private fun ContentNode.renderClass(node: DocumentationNode) { renderModifiersForNode(node) when (node.kind) { - Kind.Class -> keyword("class ") - Kind.Interface -> keyword("trait ") - Kind.Enum -> keyword("enum class ") - Kind.EnumItem -> keyword("enum val ") - Kind.Object -> keyword("object ") + DocumentationNode.Kind.Class -> keyword("class ") + DocumentationNode.Kind.Interface -> keyword("trait ") + DocumentationNode.Kind.Enum -> keyword("enum class ") + DocumentationNode.Kind.EnumItem -> keyword("enum val ") + DocumentationNode.Kind.Object -> keyword("object ") else -> throw IllegalArgumentException("Node $node is not a class-like object") } @@ -178,46 +185,46 @@ class KotlinLanguageService : LanguageService { private fun ContentNode.renderFunction(node: DocumentationNode) { renderModifiersForNode(node) when (node.kind) { - Kind.Constructor -> identifier(node.owner!!.name) - Kind.Function -> keyword("fun ") + DocumentationNode.Kind.Constructor -> identifier(node.owner!!.name) + DocumentationNode.Kind.Function -> keyword("fun ") else -> throw IllegalArgumentException("Node $node is not a function-like object") } renderTypeParametersForNode(node) - val receiver = node.details(Kind.Receiver).singleOrNull() + val receiver = node.details(DocumentationNode.Kind.Receiver).singleOrNull() if (receiver != null) { - renderType(receiver.detail(Kind.Type)) + renderType(receiver.detail(DocumentationNode.Kind.Type)) symbol(".") } - if (node.kind != Kind.Constructor) + if (node.kind != org.jetbrains.dokka.DocumentationNode.Kind.Constructor) identifier(node.name) symbol("(") - renderList(node.details(Kind.Parameter)) { + renderList(node.details(DocumentationNode.Kind.Parameter)) { renderParameter(it) } symbol(")") - if (node.kind != Kind.Constructor) { + if (node.kind != org.jetbrains.dokka.DocumentationNode.Kind.Constructor) { symbol(": ") - renderType(node.detail(Kind.Type)) + renderType(node.detail(DocumentationNode.Kind.Type)) } } private fun ContentNode.renderProperty(node: DocumentationNode) { renderModifiersForNode(node) when (node.kind) { - Kind.Property -> keyword("val ") + DocumentationNode.Kind.Property -> keyword("val ") else -> throw IllegalArgumentException("Node $node is not a property") } renderTypeParametersForNode(node) - val receiver = node.details(Kind.Receiver).singleOrNull() + val receiver = node.details(DocumentationNode.Kind.Receiver).singleOrNull() if (receiver != null) { - renderType(receiver.detail(Kind.Type)) + renderType(receiver.detail(DocumentationNode.Kind.Type)) symbol(".") } identifier(node.name) symbol(": ") - renderType(node.detail(Kind.Type)) + renderType(node.detail(DocumentationNode.Kind.Type)) } }
\ No newline at end of file diff --git a/src/Kotlin/ResolveReferences.kt b/src/Kotlin/ResolveReferences.kt deleted file mode 100644 index 1349c69e..00000000 --- a/src/Kotlin/ResolveReferences.kt +++ /dev/null @@ -1,75 +0,0 @@ -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 ContentExternalLink) { - val referenceText = child.href - if (Name.isValidIdentifier(referenceText)) { - val scope = getResolutionScope(node) - val symbolName = Name.guess(referenceText) - val symbol = scope.getLocalVariable(symbolName) ?: - scope.getProperties(symbolName).firstOrNull() ?: - scope.getFunctions(symbolName).firstOrNull() ?: - scope.getClassifier(symbolName) - - if (symbol != null) { - val targetNode = descriptorToNode[symbol] - val contentLink = if (targetNode != null) ContentNodeLink(targetNode) else ContentExternalLink("#") - - val index = content.children.indexOf(child) - content.children.remove(index) - contentLink.children.addAll(child.children) - content.children.add(index, contentLink) - } - } - } - resolveContentLinks(node, child) - } -}
\ No newline at end of file diff --git a/src/Locations/LocationService.kt b/src/Locations/LocationService.kt index f89fedd0..3c3ed3e1 100644 --- a/src/Locations/LocationService.kt +++ b/src/Locations/LocationService.kt @@ -12,7 +12,7 @@ public trait LocationService { } -public fun escapeUri(path: String): String = path.replace('<', '_').replace('>', '_') +public fun escapeUri(path: String): String = path.replace('<', '-').replace('>', '-') fun LocationService.relativeLocation(owner: DocumentationNode, node: DocumentationNode, extension: String): Location { return relativeLocation(location(owner), node, extension) diff --git a/src/Markdown/MarkdownProcessor.kt b/src/Markdown/MarkdownProcessor.kt index 19d5a8fb..040f2ad5 100644 --- a/src/Markdown/MarkdownProcessor.kt +++ b/src/Markdown/MarkdownProcessor.kt @@ -30,7 +30,7 @@ public class MarkdownTree(private val text: String, private val structure: Flywe } fun findChildByType(node: LighterASTNode, findType: IElementType) : LighterASTNode? { - val ref = Ref.create<Array<LighterASTNode>?>() + val ref: Ref<Array<LighterASTNode>?> = Ref.create<Array<LighterASTNode>?>() val count = structure.getChildren(node, ref) val children = ref.get() if (children != null) { @@ -53,7 +53,7 @@ public class MarkdownTree(private val text: String, private val structure: Flywe fun visit(node: LighterASTNode, action: (LighterASTNode, String, visitChildren: () -> Unit) -> Unit) { action(node, text) { - val ref = Ref.create<Array<LighterASTNode>?>() + val ref : Ref<Array<LighterASTNode>?> = Ref.create<Array<LighterASTNode>?>() val count = structure.getChildren(node, ref) val children = ref.get() if (children != null) { diff --git a/src/Markdown/markdown.bnf b/src/Markdown/markdown.bnf index d6fd2ed2..2e4979ec 100644 --- a/src/Markdown/markdown.bnf +++ b/src/Markdown/markdown.bnf @@ -47,6 +47,7 @@ Block ::= BlankLine* ( OrderedList | BulletList | HorizontalRule + | Directive | Para ) @@ -58,6 +59,10 @@ HorizontalRule ::= NonindentSpace | '_' OptionalSpace '_' OptionalSpace '_' (OptionalSpace '_')*) OptionalSpace EOL BlankLine+ +Directive ::= '{' DirectiveName Space+ DirectiveParams '}' +DirectiveName ::= Word +DirectiveParams ::= PlainText + Bullet ::= !HorizontalRule NonindentSpace ('+' | '*' | '-') Space+ Enumerator ::= NonindentSpace Number '.' Space+ @@ -75,13 +80,15 @@ ListContinuationBlock ::= BlankLine* (Indent ListBlock)+ // ---- INLINES ---- private Inlines ::= (!EndLine Inline | EndLine &Inline )+ EndLine? -Inline ::= Strong | Emph | Link | PlainText -PlainText ::= (Word | Number | Space+)+ +Inline ::= Strong | Emph | Code | Link | PlainText +PlainText ::= (Word | Number | Space | ':')+ Emph ::= EmphStar | EmphUnderscore private EmphStar ::= '*' !Whitespace (!'*' Inline)+ '*' private EmphUnderscore ::= '_' !Whitespace (!'_' Inline)+ '_' +Code ::= '`' !Whitespace (!'`' Inline)+ '`' + Strong ::= StrongStar | StrongUnderscore StrongStar ::= '**' !Whitespace (!'**' Inline)+ '**' StrongUnderscore ::= '__' !Whitespace (!'__' Inline)+ '__' diff --git a/src/Model/Content.kt b/src/Model/Content.kt index ce438835..794faf50 100644 --- a/src/Model/Content.kt +++ b/src/Model/Content.kt @@ -23,10 +23,14 @@ public class ContentText(val text: String) : ContentNode() public class ContentKeyword(val text: String) : ContentNode() public class ContentIdentifier(val text: String) : ContentNode() public class ContentSymbol(val text: String) : ContentNode() + +public class ContentParagraph() : ContentBlock() public class ContentEmphasis() : ContentBlock() +public class ContentStrong() : ContentBlock() +public class ContentCode() : ContentBlock() +public class ContentBlockCode() : ContentBlock() public class ContentNodeLink(val node : DocumentationNode) : ContentBlock() public class ContentExternalLink(val href : String) : ContentBlock() -public class ContentStrong() : ContentBlock() public class ContentList() : ContentBlock() public class ContentSection(public val label: String) : ContentBlock() @@ -49,7 +53,7 @@ fun ContentNode.link(to: DocumentationNode, body: ContentNode.() -> Unit) { public class Content() : ContentNode() { public val sections: Map<String, ContentSection> by Delegates.lazy { - val map = hashMapOf<String, ContentSection>() + val map = linkedMapOf<String, ContentSection>() for (child in children) { if (child is ContentSection) map.put(child.label, child) @@ -80,7 +84,9 @@ public class Content() : ContentNode() { map } - public val summary: ContentNode get() = sections["\$summary"] ?: ContentNode.empty + public val summary: ContentNode get() { + return sections["\$summary"] ?: ContentNode.empty + } public val description: ContentNode get() = sections["\$description"] ?: ContentNode.empty override fun equals(other: Any?): Boolean { diff --git a/src/Model/DocumentationModule.kt b/src/Model/DocumentationModule.kt index 6084ea5e..e74c544b 100644 --- a/src/Model/DocumentationModule.kt +++ b/src/Model/DocumentationModule.kt @@ -1,6 +1,6 @@ package org.jetbrains.dokka -public class DocumentationModule(name: String) : DocumentationNode(name, Content.Empty, DocumentationNode.Kind.Module) { +public class DocumentationModule(name: String, content: Content = Content.Empty) : DocumentationNode(name, content, DocumentationNode.Kind.Module) { fun merge(other: DocumentationModule): DocumentationModule { val model = DocumentationModule(name) model.addAllReferencesFrom(other) diff --git a/src/Model/DocumentationNode.kt b/src/Model/DocumentationNode.kt index 18efaa9b..2be5bf15 100644 --- a/src/Model/DocumentationNode.kt +++ b/src/Model/DocumentationNode.kt @@ -3,11 +3,21 @@ package org.jetbrains.dokka import java.util.LinkedHashSet public open class DocumentationNode(val name: String, - val doc: Content, + val content: Content, val kind: DocumentationNode.Kind) { private val references = LinkedHashSet<DocumentationReference>() + public val summary: ContentNode get() { + val contentSection = content.sections["\$summary"] + if (contentSection != null) + return contentSection + val ownerSection = owner?.content?.sections?.get(name) + if (ownerSection != null) + return ownerSection + return ContentNode.empty + } + public val owner: DocumentationNode? get() = references(DocumentationReference.Kind.Owner).singleOrNull()?.to public val details: List<DocumentationNode> diff --git a/src/main.kt b/src/main.kt index 970bbd8c..6f5cf796 100644 --- a/src/main.kt +++ b/src/main.kt @@ -6,11 +6,22 @@ import org.jetbrains.jet.cli.common.messages.* import org.jetbrains.jet.cli.common.arguments.* import org.jetbrains.jet.utils.PathUtil import java.io.File +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor +import org.jetbrains.jet.lang.resolve.name.FqName +import java.lang.reflect.Constructor class DokkaArguments { Argument(value = "src", description = "Source file or directory (allows many paths separated by the system path separator)") ValueDescription("<path>") - public var src: String? = null + public var src: String = "" + + Argument(value = "include", description = "Markdown files to load (allows many paths separated by the system path separator)") + ValueDescription("<path>") + public var include: String = "" + + Argument(value = "samples", description = "Source root for samples") + ValueDescription("<path>") + public var samples: String = "" Argument(value = "output", description = "Output directory path for .md files") ValueDescription("<path>") @@ -23,21 +34,25 @@ class DokkaArguments { Argument(value = "classpath", description = "Classpath for symbol resolution") ValueDescription("<path>") public var classpath: String = "" + } public fun main(args: Array<String>) { - val arguments = DokkaArguments() - val sourceFiles = Args.parse(arguments, args) - val sources: List<String> = sourceFiles ?: listOf() + val freeArgs: List<String> = Args.parse(arguments, args) ?: listOf() + val sources = if (arguments.src.isNotEmpty()) arguments.src.split(File.pathSeparatorChar).toList() + freeArgs else freeArgs + val samples = if (arguments.samples.isNotEmpty()) arguments.samples.split(File.pathSeparatorChar).toList() else listOf() + val includes = if (arguments.include.isNotEmpty()) arguments.include.split(File.pathSeparatorChar).toList() else listOf() val environment = AnalysisEnvironment(MessageCollectorPlainTextToStream.PLAIN_TEXT_TO_SYSTEM_ERR) { addClasspath(PathUtil.getJdkClassesRoots()) + // addClasspath(PathUtil.getKotlinPathsForCompiler().getRuntimePath()) for (element in arguments.classpath.split(File.pathSeparatorChar)) { addClasspath(File(element)) } - // addClasspath(PathUtil.getKotlinPathsForCompiler().getRuntimePath()) + addSources(sources) + addSources(samples) } println("Module: ${arguments.moduleName}") @@ -47,15 +62,50 @@ public fun main(args: Array<String>) { println() - print("Analysing sources and libraries... ") + println("Analysing sources and libraries... ") val startAnalyse = System.currentTimeMillis() - val documentation = environment.withContext<DocumentationModule> { environment, module, context -> - val packageSet = environment.getSourceFiles().map { file -> - context.getPackageFragment(file)!!.fqName - }.toSet() - context.createDocumentationModule(arguments.moduleName, module, packageSet) + + val documentation = environment.withContext { environment, session -> + val fragmentFiles = environment.getSourceFiles().filter { + val sourceFile = File(it.getVirtualFile()!!.getPath()) + samples.none { sample -> + val canonicalSample = File(sample).canonicalPath + val canonicalSource = sourceFile.canonicalPath + canonicalSource.startsWith(canonicalSample) + } + } + val fragments = fragmentFiles.map { session.getPackageFragment(it.getPackageFqName()) }.filterNotNull().distinct() + val options = DocumentationOptions() + val documentationBuilder = DocumentationBuilder(session, options) + + with(documentationBuilder) { + + val moduleContent = Content() + for (include in includes) { + val text = File(include).readText() + val tree = MarkdownProcessor.parse(text) + val content = buildContent(tree, session.getPackageFragment(FqName.ROOT)) + moduleContent.children.addAll(content.children) + } + + val documentationModule = DocumentationModule(arguments.moduleName, moduleContent) + + val descriptors = hashMapOf<String, List<DeclarationDescriptor>>() + for ((name, parts) in fragments.groupBy { it.fqName }) { + descriptors.put(name.asString(), parts.flatMap { it.getMemberScope().getAllDescriptors() }) + } + for ((packageName, declarations) in descriptors) { + println(" package $packageName: ${declarations.count()} nodes") + val packageNode = DocumentationNode(packageName, Content.Empty, DocumentationNode.Kind.Package) + packageNode.appendChildren(declarations, DocumentationReference.Kind.Member) + documentationModule.append(packageNode, DocumentationReference.Kind.Member) + } + documentationBuilder.resolveReferences(documentationModule) + documentationModule + } } + val timeAnalyse = System.currentTimeMillis() - startAnalyse println("done in ${timeAnalyse / 1000} secs") @@ -64,9 +114,10 @@ public fun main(args: Array<String>) { val locationService = FoldersLocationService(arguments.outputDir) val templateService = HtmlTemplateService.default("/dokka/styles/style.css") +// val formatter = HtmlFormatService(locationService, signatureGenerator, templateService) val formatter = KotlinWebsiteFormatService(locationService, signatureGenerator) val generator = FileGenerator(signatureGenerator, locationService, formatter) - print("Building pages... ") + print("Generating pages... ") generator.buildPage(documentation) generator.buildOutline(documentation) val timeBuild = System.currentTimeMillis() - startBuild |