From 39631054c58df5841ea268b7002b820ec55f6e0a Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 3 Dec 2015 16:22:11 +0100 Subject: restructure Dokka build to use Gradle for everything except for the Maven plugin --- .../main/kotlin/Analysis/AnalysisEnvironment.kt | 210 +++++++ .../main/kotlin/Analysis/CoreProjectFileIndex.kt | 550 +++++++++++++++++ core/src/main/kotlin/Formats/FormatDescriptor.kt | 12 + core/src/main/kotlin/Formats/FormatService.kt | 20 + core/src/main/kotlin/Formats/HtmlFormatService.kt | 169 ++++++ .../src/main/kotlin/Formats/HtmlTemplateService.kt | 34 ++ .../src/main/kotlin/Formats/JekyllFormatService.kt | 22 + .../kotlin/Formats/KotlinWebsiteFormatService.kt | 121 ++++ .../main/kotlin/Formats/MarkdownFormatService.kt | 117 ++++ core/src/main/kotlin/Formats/OutlineService.kt | 29 + core/src/main/kotlin/Formats/StandardFormats.kt | 38 ++ .../main/kotlin/Formats/StructuredFormatService.kt | 367 ++++++++++++ core/src/main/kotlin/Formats/YamlOutlineService.kt | 24 + .../src/main/kotlin/Generation/ConsoleGenerator.kt | 42 ++ core/src/main/kotlin/Generation/FileGenerator.kt | 57 ++ core/src/main/kotlin/Generation/Generator.kt | 19 + .../kotlin/Java/JavaPsiDocumentationBuilder.kt | 266 +++++++++ core/src/main/kotlin/Java/JavadocParser.kt | 170 ++++++ core/src/main/kotlin/Kotlin/ContentBuilder.kt | 132 +++++ .../main/kotlin/Kotlin/DeclarationLinkResolver.kt | 43 ++ .../kotlin/Kotlin/DescriptorDocumentationParser.kt | 199 +++++++ .../src/main/kotlin/Kotlin/DocumentationBuilder.kt | 653 +++++++++++++++++++++ .../Kotlin/KotlinAsJavaDocumentationBuilder.kt | 64 ++ .../main/kotlin/Kotlin/KotlinLanguageService.kt | 409 +++++++++++++ .../main/kotlin/Languages/JavaLanguageService.kt | 162 +++++ core/src/main/kotlin/Languages/LanguageService.kt | 41 ++ .../kotlin/Locations/FoldersLocationService.kt | 29 + core/src/main/kotlin/Locations/LocationService.kt | 78 +++ .../Locations/SingleFolderLocationService.kt | 19 + core/src/main/kotlin/Markdown/MarkdownProcessor.kt | 50 ++ core/src/main/kotlin/Model/Content.kt | 231 ++++++++ core/src/main/kotlin/Model/DocumentationNode.kt | 162 +++++ .../main/kotlin/Model/DocumentationReference.kt | 61 ++ core/src/main/kotlin/Model/PackageDocs.kt | 60 ++ core/src/main/kotlin/Model/SourceLinks.kt | 56 ++ core/src/main/kotlin/Utilities/DokkaModule.kt | 73 +++ core/src/main/kotlin/Utilities/Html.kt | 8 + core/src/main/kotlin/Utilities/Path.kt | 5 + core/src/main/kotlin/Utilities/ServiceLocator.kt | 78 +++ core/src/main/kotlin/ant/dokka.kt | 108 ++++ core/src/main/kotlin/javadoc/docbase.kt | 501 ++++++++++++++++ core/src/main/kotlin/javadoc/dokka-adapters.kt | 30 + core/src/main/kotlin/javadoc/reporter.kt | 34 ++ core/src/main/kotlin/javadoc/source-position.kt | 18 + core/src/main/kotlin/javadoc/tags.kt | 214 +++++++ core/src/main/kotlin/main.kt | 262 +++++++++ core/src/main/resources/META-INF/MANIFEST.MF | 4 + core/src/main/resources/dokka-antlib.xml | 3 + .../resources/dokka/format/html-as-java.properties | 2 + .../main/resources/dokka/format/html.properties | 2 + .../main/resources/dokka/format/javadoc.properties | 1 + .../main/resources/dokka/format/jekyll.properties | 2 + .../dokka/format/kotlin-website.properties | 2 + .../resources/dokka/format/markdown.properties | 2 + .../resources/dokka/generator/default.properties | 2 + .../resources/dokka/generator/javadoc.properties | 2 + .../main/resources/dokka/language/java.properties | 1 + .../resources/dokka/language/kotlin.properties | 1 + .../main/resources/dokka/outline/yaml.properties | 1 + core/src/main/resources/dokka/styles/style.css | 280 +++++++++ core/src/main/resources/format/javadoc.properties | 1 + core/src/test/kotlin/TestAPI.kt | 214 +++++++ core/src/test/kotlin/format/HtmlFormatTest.kt | 157 +++++ core/src/test/kotlin/format/MarkdownFormatTest.kt | 218 +++++++ core/src/test/kotlin/format/PackageDocsTest.kt | 18 + core/src/test/kotlin/javadoc/JavadocTest.kt | 44 ++ core/src/test/kotlin/markdown/ParserTest.kt | 142 +++++ core/src/test/kotlin/model/ClassTest.kt | 275 +++++++++ core/src/test/kotlin/model/CommentTest.kt | 153 +++++ core/src/test/kotlin/model/FunctionTest.kt | 227 +++++++ core/src/test/kotlin/model/JavaTest.kt | 197 +++++++ core/src/test/kotlin/model/KotlinAsJavaTest.kt | 40 ++ core/src/test/kotlin/model/LinkTest.kt | 48 ++ core/src/test/kotlin/model/PackageTest.kt | 86 +++ core/src/test/kotlin/model/PropertyTest.kt | 103 ++++ 75 files changed, 8275 insertions(+) create mode 100644 core/src/main/kotlin/Analysis/AnalysisEnvironment.kt create mode 100644 core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt create mode 100644 core/src/main/kotlin/Formats/FormatDescriptor.kt create mode 100644 core/src/main/kotlin/Formats/FormatService.kt create mode 100644 core/src/main/kotlin/Formats/HtmlFormatService.kt create mode 100644 core/src/main/kotlin/Formats/HtmlTemplateService.kt create mode 100644 core/src/main/kotlin/Formats/JekyllFormatService.kt create mode 100644 core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt create mode 100644 core/src/main/kotlin/Formats/MarkdownFormatService.kt create mode 100644 core/src/main/kotlin/Formats/OutlineService.kt create mode 100644 core/src/main/kotlin/Formats/StandardFormats.kt create mode 100644 core/src/main/kotlin/Formats/StructuredFormatService.kt create mode 100644 core/src/main/kotlin/Formats/YamlOutlineService.kt create mode 100644 core/src/main/kotlin/Generation/ConsoleGenerator.kt create mode 100644 core/src/main/kotlin/Generation/FileGenerator.kt create mode 100644 core/src/main/kotlin/Generation/Generator.kt create mode 100644 core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt create mode 100644 core/src/main/kotlin/Java/JavadocParser.kt create mode 100644 core/src/main/kotlin/Kotlin/ContentBuilder.kt create mode 100644 core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt create mode 100644 core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt create mode 100644 core/src/main/kotlin/Kotlin/DocumentationBuilder.kt create mode 100644 core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt create mode 100644 core/src/main/kotlin/Kotlin/KotlinLanguageService.kt create mode 100644 core/src/main/kotlin/Languages/JavaLanguageService.kt create mode 100644 core/src/main/kotlin/Languages/LanguageService.kt create mode 100644 core/src/main/kotlin/Locations/FoldersLocationService.kt create mode 100644 core/src/main/kotlin/Locations/LocationService.kt create mode 100644 core/src/main/kotlin/Locations/SingleFolderLocationService.kt create mode 100644 core/src/main/kotlin/Markdown/MarkdownProcessor.kt create mode 100644 core/src/main/kotlin/Model/Content.kt create mode 100644 core/src/main/kotlin/Model/DocumentationNode.kt create mode 100644 core/src/main/kotlin/Model/DocumentationReference.kt create mode 100644 core/src/main/kotlin/Model/PackageDocs.kt create mode 100644 core/src/main/kotlin/Model/SourceLinks.kt create mode 100644 core/src/main/kotlin/Utilities/DokkaModule.kt create mode 100644 core/src/main/kotlin/Utilities/Html.kt create mode 100644 core/src/main/kotlin/Utilities/Path.kt create mode 100644 core/src/main/kotlin/Utilities/ServiceLocator.kt create mode 100644 core/src/main/kotlin/ant/dokka.kt create mode 100644 core/src/main/kotlin/javadoc/docbase.kt create mode 100644 core/src/main/kotlin/javadoc/dokka-adapters.kt create mode 100644 core/src/main/kotlin/javadoc/reporter.kt create mode 100644 core/src/main/kotlin/javadoc/source-position.kt create mode 100644 core/src/main/kotlin/javadoc/tags.kt create mode 100644 core/src/main/kotlin/main.kt create mode 100644 core/src/main/resources/META-INF/MANIFEST.MF create mode 100644 core/src/main/resources/dokka-antlib.xml create mode 100644 core/src/main/resources/dokka/format/html-as-java.properties create mode 100644 core/src/main/resources/dokka/format/html.properties create mode 100644 core/src/main/resources/dokka/format/javadoc.properties create mode 100644 core/src/main/resources/dokka/format/jekyll.properties create mode 100644 core/src/main/resources/dokka/format/kotlin-website.properties create mode 100644 core/src/main/resources/dokka/format/markdown.properties create mode 100644 core/src/main/resources/dokka/generator/default.properties create mode 100644 core/src/main/resources/dokka/generator/javadoc.properties create mode 100644 core/src/main/resources/dokka/language/java.properties create mode 100644 core/src/main/resources/dokka/language/kotlin.properties create mode 100644 core/src/main/resources/dokka/outline/yaml.properties create mode 100644 core/src/main/resources/dokka/styles/style.css create mode 100644 core/src/main/resources/format/javadoc.properties create mode 100644 core/src/test/kotlin/TestAPI.kt create mode 100644 core/src/test/kotlin/format/HtmlFormatTest.kt create mode 100644 core/src/test/kotlin/format/MarkdownFormatTest.kt create mode 100644 core/src/test/kotlin/format/PackageDocsTest.kt create mode 100644 core/src/test/kotlin/javadoc/JavadocTest.kt create mode 100644 core/src/test/kotlin/markdown/ParserTest.kt create mode 100644 core/src/test/kotlin/model/ClassTest.kt create mode 100644 core/src/test/kotlin/model/CommentTest.kt create mode 100644 core/src/test/kotlin/model/FunctionTest.kt create mode 100644 core/src/test/kotlin/model/JavaTest.kt create mode 100644 core/src/test/kotlin/model/KotlinAsJavaTest.kt create mode 100644 core/src/test/kotlin/model/LinkTest.kt create mode 100644 core/src/test/kotlin/model/PackageTest.kt create mode 100644 core/src/test/kotlin/model/PropertyTest.kt (limited to 'core/src') diff --git a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt new file mode 100644 index 00000000..a5e35a0e --- /dev/null +++ b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt @@ -0,0 +1,210 @@ +package org.jetbrains.dokka + +import com.intellij.core.CoreApplicationEnvironment +import com.intellij.core.CoreModuleManager +import com.intellij.mock.MockComponentManager +import com.intellij.openapi.Disposable +import com.intellij.openapi.extensions.Extensions +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.OrderEnumerationHandler +import com.intellij.openapi.roots.ProjectFileIndex +import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.util.Disposer +import com.intellij.psi.PsiElement +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.analyzer.AnalysisResult +import org.jetbrains.kotlin.analyzer.ModuleContent +import org.jetbrains.kotlin.analyzer.ModuleInfo +import org.jetbrains.kotlin.analyzer.ResolverForModule +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot +import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot +import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots +import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots +import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.ContentRoot +import org.jetbrains.kotlin.config.KotlinSourceRoot +import org.jetbrains.kotlin.container.getService +import org.jetbrains.kotlin.context.ProjectContext +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.KotlinCacheService +import org.jetbrains.kotlin.idea.caches.resolve.KotlinOutOfBlockCompletionModificationTracker +import org.jetbrains.kotlin.idea.caches.resolve.LibraryModificationTracker +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.CompilerEnvironment +import org.jetbrains.kotlin.resolve.jvm.JvmAnalyzerFacade +import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.resolve.lazy.ResolveSession +import java.io.File + +/** + * Kotlin as a service entry point + * + * Configures environment, analyses files and provides facilities to perform code processing without emitting bytecode + * + * $messageCollector: required by compiler infrastructure and will receive all compiler messages + * $body: optional and can be used to configure environment without creating local variable + */ +public class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable { + val configuration = CompilerConfiguration(); + + init { + configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) + } + + fun createCoreEnvironment(): KotlinCoreEnvironment { + val environment = KotlinCoreEnvironment.createForProduction(this, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES) + val projectComponentManager = environment.project as MockComponentManager + + val projectFileIndex = CoreProjectFileIndex(environment.project, + environment.configuration.getList(CommonConfigurationKeys.CONTENT_ROOTS)) + + val moduleManager = object : CoreModuleManager(environment.project, this) { + override fun getModules(): Array = arrayOf(projectFileIndex.module) + } + + CoreApplicationEnvironment.registerComponentInstance(projectComponentManager.picoContainer, + ModuleManager::class.java, moduleManager) + + Extensions.registerAreaClass("IDEA_MODULE", null) + CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), + OrderEnumerationHandler.EP_NAME, OrderEnumerationHandler.Factory::class.java) + + projectComponentManager.registerService(ProjectFileIndex::class.java, + projectFileIndex) + projectComponentManager.registerService(ProjectRootManager::class.java, + CoreProjectRootManager(projectFileIndex)) + projectComponentManager.registerService(LibraryModificationTracker::class.java, + LibraryModificationTracker(environment.project)) + projectComponentManager.registerService(KotlinCacheService::class.java, + KotlinCacheService(environment.project)) + projectComponentManager.registerService(KotlinOutOfBlockCompletionModificationTracker::class.java, + KotlinOutOfBlockCompletionModificationTracker()) + return environment + } + + fun createResolutionFacade(environment: KotlinCoreEnvironment): DokkaResolutionFacade { + val projectContext = ProjectContext(environment.project) + val sourceFiles = environment.getSourceFiles() + + val module = object : ModuleInfo { + override val name: Name = Name.special("") + override fun dependencies(): List = listOf(this) + } + val resolverForProject = JvmAnalyzerFacade.setupResolverForProject( + "Dokka", + projectContext, + listOf(module), + { ModuleContent(sourceFiles, GlobalSearchScope.allScope(environment.project)) }, + JvmPlatformParameters { module }, + CompilerEnvironment + ) + + val resolverForModule = resolverForProject.resolverForModule(module) + return DokkaResolutionFacade(environment.project, resolverForProject.descriptorForModule(module), resolverForModule) + } + + /** + * Classpath for this environment. + */ + public val classpath: List + get() = configuration.jvmClasspathRoots + + /** + * Adds list of paths to classpath. + * $paths: collection of files to add + */ + public fun addClasspath(paths: List) { + configuration.addJvmClasspathRoots(paths) + } + + /** + * Adds path to classpath. + * $path: path to add + */ + public fun addClasspath(path: File) { + configuration.addJvmClasspathRoot(path) + } + + /** + * List of source roots for this environment. + */ + public val sources: List + get() = configuration.get(CommonConfigurationKeys.CONTENT_ROOTS) + ?.filterIsInstance() + ?.map { it.path } ?: emptyList() + + /** + * Adds list of paths to source roots. + * $list: collection of files to add + */ + public fun addSources(list: List) { + list.forEach { + configuration.add(CommonConfigurationKeys.CONTENT_ROOTS, contentRootFromPath(it)) + } + } + + public fun addRoots(list: List) { + configuration.addAll(CommonConfigurationKeys.CONTENT_ROOTS, list) + } + + /** + * Disposes the environment and frees all associated resources. + */ + public override fun dispose() { + Disposer.dispose(this) + } +} + +public fun contentRootFromPath(path: String): ContentRoot { + val file = File(path) + return if (file.extension == "java") JavaSourceRoot(file, null) else KotlinSourceRoot(path) +} + + +class DokkaResolutionFacade(override val project: Project, + override val moduleDescriptor: ModuleDescriptor, + val resolverForModule: ResolverForModule) : ResolutionFacade { + + val resolveSession: ResolveSession get() = getFrontendService(ResolveSession::class.java) + + override fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode): BindingContext { + throw UnsupportedOperationException() + } + + override fun analyzeFullyAndGetResult(elements: Collection): AnalysisResult { + throw UnsupportedOperationException() + } + + override fun getFrontendService(element: PsiElement, serviceClass: Class): T { + throw UnsupportedOperationException() + } + + override fun getFrontendService(serviceClass: Class): T { + return resolverForModule.componentProvider.getService(serviceClass) + } + + override fun getFrontendService(moduleDescriptor: ModuleDescriptor, serviceClass: Class): T { + throw UnsupportedOperationException() + } + + override fun getIdeService(serviceClass: Class): T { + throw UnsupportedOperationException() + } + + override fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor { + return resolveSession.resolveToDescriptor(declaration) + } +} diff --git a/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt b/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt new file mode 100644 index 00000000..a1362fde --- /dev/null +++ b/core/src/main/kotlin/Analysis/CoreProjectFileIndex.kt @@ -0,0 +1,550 @@ +package org.jetbrains.dokka + +import com.intellij.openapi.Disposable +import com.intellij.openapi.components.BaseComponent +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.projectRoots.SdkAdditionalData +import com.intellij.openapi.projectRoots.SdkModificator +import com.intellij.openapi.projectRoots.SdkTypeId +import com.intellij.openapi.roots.* +import com.intellij.openapi.roots.impl.ProjectOrderEnumerator +import com.intellij.openapi.util.Condition +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.UserDataHolderBase +import com.intellij.openapi.vfs.StandardFileSystems +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.util.messages.MessageBus +import org.jetbrains.jps.model.module.JpsModuleSourceRootType +import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot +import org.jetbrains.kotlin.cli.jvm.config.JvmContentRoot +import org.jetbrains.kotlin.config.ContentRoot +import org.jetbrains.kotlin.config.KotlinSourceRoot +import org.picocontainer.PicoContainer +import java.io.File + +/** + * Workaround for the lack of ability to create a ProjectFileIndex implementation using only + * classes from projectModel-{api,impl}. + */ +class CoreProjectFileIndex(val project: Project, contentRoots: List) : ProjectFileIndex, ModuleFileIndex { + val sourceRoots = contentRoots.filter { it !is JvmClasspathRoot } + val classpathRoots = contentRoots.filterIsInstance() + + val module: Module = object : UserDataHolderBase(), Module { + override fun isDisposed(): Boolean { + throw UnsupportedOperationException() + } + + override fun getOptionValue(p0: String): String? { + throw UnsupportedOperationException() + } + + override fun clearOption(p0: String) { + throw UnsupportedOperationException() + } + + override fun getName(): String = "" + + override fun getModuleWithLibrariesScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleWithDependentsScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleContentScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun isLoaded(): Boolean { + throw UnsupportedOperationException() + } + + override fun setOption(p0: String, p1: String) { + throw UnsupportedOperationException() + } + + override fun getModuleWithDependenciesScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleWithDependenciesAndLibrariesScope(p0: Boolean): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getProject(): Project = project + + override fun getModuleContentWithDependenciesScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleFilePath(): String { + throw UnsupportedOperationException() + } + + override fun getModuleTestsWithDependentsScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleScope(): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleScope(p0: Boolean): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleRuntimeScope(p0: Boolean): GlobalSearchScope { + throw UnsupportedOperationException() + } + + override fun getModuleFile(): VirtualFile? { + throw UnsupportedOperationException() + } + + override fun getExtensions(p0: ExtensionPointName): Array { + throw UnsupportedOperationException() + } + + override fun getComponent(p0: String): BaseComponent? { + throw UnsupportedOperationException() + } + + override fun getComponent(p0: Class, p1: T): T { + throw UnsupportedOperationException() + } + + override fun getComponent(interfaceClass: Class): T? { + if (interfaceClass == ModuleRootManager::class.java) { + return moduleRootManager as T + } + throw UnsupportedOperationException() + } + + override fun getDisposed(): Condition<*> { + throw UnsupportedOperationException() + } + + override fun getComponents(p0: Class): Array { + throw UnsupportedOperationException() + } + + override fun getPicoContainer(): PicoContainer { + throw UnsupportedOperationException() + } + + override fun hasComponent(p0: Class<*>): Boolean { + throw UnsupportedOperationException() + } + + override fun getMessageBus(): MessageBus { + throw UnsupportedOperationException() + } + + override fun dispose() { + throw UnsupportedOperationException() + } + } + + private val sdk: Sdk = object : Sdk, RootProvider { + override fun getFiles(rootType: OrderRootType): Array = classpathRoots + .map { StandardFileSystems.local().findFileByPath(it.file.path) } + .filterNotNull() + .toTypedArray() + + override fun addRootSetChangedListener(p0: RootProvider.RootSetChangedListener) { + throw UnsupportedOperationException() + } + + override fun addRootSetChangedListener(p0: RootProvider.RootSetChangedListener, p1: Disposable) { + throw UnsupportedOperationException() + } + + override fun getUrls(p0: OrderRootType): Array { + throw UnsupportedOperationException() + } + + override fun removeRootSetChangedListener(p0: RootProvider.RootSetChangedListener) { + throw UnsupportedOperationException() + } + + override fun getSdkModificator(): SdkModificator { + throw UnsupportedOperationException() + } + + override fun getName(): String = "" + + override fun getRootProvider(): RootProvider = this + + override fun getHomePath(): String? { + throw UnsupportedOperationException() + } + + override fun getVersionString(): String? { + throw UnsupportedOperationException() + } + + override fun getSdkAdditionalData(): SdkAdditionalData? { + throw UnsupportedOperationException() + } + + override fun clone(): Any { + throw UnsupportedOperationException() + } + + override fun getSdkType(): SdkTypeId { + throw UnsupportedOperationException() + } + + override fun getHomeDirectory(): VirtualFile? { + throw UnsupportedOperationException() + } + + override fun getUserData(p0: Key): T? { + throw UnsupportedOperationException() + } + + override fun putUserData(p0: Key, p1: T?) { + throw UnsupportedOperationException() + } + } + + private val moduleSourceOrderEntry = object : ModuleSourceOrderEntry { + override fun getFiles(p0: OrderRootType?): Array { + throw UnsupportedOperationException() + } + + override fun getPresentableName(): String { + throw UnsupportedOperationException() + } + + override fun getUrls(p0: OrderRootType?): Array { + throw UnsupportedOperationException() + } + + override fun getOwnerModule(): Module = module + + override fun accept(p0: RootPolicy?, p1: R?): R { + throw UnsupportedOperationException() + } + + override fun isValid(): Boolean { + throw UnsupportedOperationException() + } + + override fun compareTo(other: OrderEntry?): Int { + throw UnsupportedOperationException() + } + + override fun getRootModel(): ModuleRootModel = moduleRootManager + + override fun isSynthetic(): Boolean { + throw UnsupportedOperationException() + } + } + + private val sdkOrderEntry = object : JdkOrderEntry { + override fun getJdkName(): String? { + throw UnsupportedOperationException() + } + + override fun getJdk(): Sdk = sdk + + override fun getFiles(p0: OrderRootType?): Array { + throw UnsupportedOperationException() + } + + override fun getPresentableName(): String { + throw UnsupportedOperationException() + } + + override fun getUrls(p0: OrderRootType?): Array { + throw UnsupportedOperationException() + } + + override fun getOwnerModule(): Module { + throw UnsupportedOperationException() + } + + override fun accept(p0: RootPolicy?, p1: R?): R { + throw UnsupportedOperationException() + } + + override fun isValid(): Boolean { + throw UnsupportedOperationException() + } + + override fun getRootFiles(p0: OrderRootType?): Array? { + throw UnsupportedOperationException() + } + + override fun getRootUrls(p0: OrderRootType?): Array? { + throw UnsupportedOperationException() + } + + override fun compareTo(other: OrderEntry?): Int { + throw UnsupportedOperationException() + } + + override fun isSynthetic(): Boolean { + throw UnsupportedOperationException() + } + + } + + inner class MyModuleRootManager : ModuleRootManager() { + override fun getExcludeRoots(): Array { + throw UnsupportedOperationException() + } + + override fun getContentEntries(): Array { + throw UnsupportedOperationException() + } + + override fun getExcludeRootUrls(): Array { + throw UnsupportedOperationException() + } + + override fun processOrder(p0: RootPolicy?, p1: R): R { + throw UnsupportedOperationException() + } + + override fun getSourceRoots(p0: Boolean): Array { + throw UnsupportedOperationException() + } + + override fun getSourceRoots(): Array { + throw UnsupportedOperationException() + } + + override fun getSourceRoots(p0: JpsModuleSourceRootType<*>): MutableList { + throw UnsupportedOperationException() + } + + override fun getSourceRoots(p0: MutableSet>): MutableList { + throw UnsupportedOperationException() + } + + override fun getContentRoots(): Array { + throw UnsupportedOperationException() + } + + override fun orderEntries(): OrderEnumerator = + ProjectOrderEnumerator(project, null).using(object : RootModelProvider { + override fun getModules(): Array = arrayOf(module) + + override fun getRootModel(p0: Module): ModuleRootModel = this@MyModuleRootManager + }) + + override fun getModuleExtension(p0: Class?): T { + throw UnsupportedOperationException() + } + + override fun getDependencyModuleNames(): Array { + throw UnsupportedOperationException() + } + + override fun getModule(): Module = module + + override fun isSdkInherited(): Boolean { + throw UnsupportedOperationException() + } + + override fun getOrderEntries(): Array = arrayOf(moduleSourceOrderEntry, sdkOrderEntry) + + override fun getSourceRootUrls(): Array { + throw UnsupportedOperationException() + } + + override fun getSourceRootUrls(p0: Boolean): Array { + throw UnsupportedOperationException() + } + + override fun getSdk(): Sdk? { + throw UnsupportedOperationException() + } + + override fun getContentRootUrls(): Array { + throw UnsupportedOperationException() + } + + override fun getModuleDependencies(): Array { + throw UnsupportedOperationException() + } + + override fun getModuleDependencies(p0: Boolean): Array { + throw UnsupportedOperationException() + } + + override fun getModifiableModel(): ModifiableRootModel { + throw UnsupportedOperationException() + } + + override fun isDependsOn(p0: Module?): Boolean { + throw UnsupportedOperationException() + } + + override fun getFileIndex(): ModuleFileIndex { + return this@CoreProjectFileIndex + } + + override fun getDependencies(): Array { + throw UnsupportedOperationException() + } + + override fun getDependencies(p0: Boolean): Array { + throw UnsupportedOperationException() + } + } + + val moduleRootManager = MyModuleRootManager() + + override fun getContentRootForFile(p0: VirtualFile): VirtualFile? { + throw UnsupportedOperationException() + } + + override fun getContentRootForFile(p0: VirtualFile, p1: Boolean): VirtualFile? { + throw UnsupportedOperationException() + } + + override fun getPackageNameByDirectory(p0: VirtualFile): String? { + throw UnsupportedOperationException() + } + + override fun isInLibrarySource(file: VirtualFile): Boolean = false + + override fun getClassRootForFile(file: VirtualFile): VirtualFile? = + classpathRoots.firstOrNull { it.contains(file) }?.let { StandardFileSystems.local().findFileByPath(it.file.path) } + + override fun getOrderEntriesForFile(file: VirtualFile): List = + if (classpathRoots.contains(file)) listOf(sdkOrderEntry) else emptyList() + + override fun isInLibraryClasses(file: VirtualFile): Boolean = classpathRoots.contains(file) + + override fun isExcluded(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun getSourceRootForFile(p0: VirtualFile): VirtualFile? { + throw UnsupportedOperationException() + } + + override fun isUnderIgnored(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun isLibraryClassFile(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun getModuleForFile(file: VirtualFile): Module? = + if (sourceRoots.contains(file)) module else null + + private fun List.contains(file: VirtualFile): Boolean = any { it.contains(file) } + + override fun getModuleForFile(p0: VirtualFile, p1: Boolean): Module? { + throw UnsupportedOperationException() + } + + override fun isInSource(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun isIgnored(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun isContentSourceFile(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun isInSourceContent(file: VirtualFile): Boolean = sourceRoots.contains(file) + + override fun iterateContent(p0: ContentIterator): Boolean { + throw UnsupportedOperationException() + } + + override fun isInContent(p0: VirtualFile): Boolean { + throw UnsupportedOperationException() + } + + override fun iterateContentUnderDirectory(p0: VirtualFile, p1: ContentIterator): Boolean { + throw UnsupportedOperationException() + } + + override fun isInTestSourceContent(file: VirtualFile): Boolean = false + + override fun isUnderSourceRootOfType(p0: VirtualFile, p1: MutableSet>): Boolean { + throw UnsupportedOperationException() + } + + override fun getOrderEntryForFile(p0: VirtualFile): OrderEntry? { + throw UnsupportedOperationException() + } +} + +class CoreProjectRootManager(val projectFileIndex: CoreProjectFileIndex) : ProjectRootManager() { + override fun orderEntries(): OrderEnumerator { + throw UnsupportedOperationException() + } + + override fun orderEntries(p0: MutableCollection): OrderEnumerator { + throw UnsupportedOperationException() + } + + override fun getContentRootsFromAllModules(): Array? { + throw UnsupportedOperationException() + } + + override fun setProjectSdk(p0: Sdk?) { + throw UnsupportedOperationException() + } + + override fun setProjectSdkName(p0: String?) { + throw UnsupportedOperationException() + } + + override fun getModuleSourceRoots(p0: MutableSet>): MutableList { + throw UnsupportedOperationException() + } + + override fun getContentSourceRoots(): Array { + throw UnsupportedOperationException() + } + + override fun getFileIndex(): ProjectFileIndex = projectFileIndex + + override fun getProjectSdkName(): String? { + throw UnsupportedOperationException() + } + + override fun getProjectSdk(): Sdk? { + throw UnsupportedOperationException() + } + + override fun getContentRoots(): Array { + throw UnsupportedOperationException() + } + + override fun getContentRootUrls(): MutableList { + throw UnsupportedOperationException() + } + +} + +fun ContentRoot.contains(file: VirtualFile) = when (this) { + is JvmContentRoot -> { + val path = if (file.fileSystem.protocol == StandardFileSystems.JAR_PROTOCOL) + StandardFileSystems.getVirtualFileForJar(file)?.path ?: file.path + else + file.path + File(path).startsWith(this.file.absoluteFile) + } + is KotlinSourceRoot -> File(file.path).startsWith(File(this.path).absoluteFile) + else -> false +} diff --git a/core/src/main/kotlin/Formats/FormatDescriptor.kt b/core/src/main/kotlin/Formats/FormatDescriptor.kt new file mode 100644 index 00000000..0c7ca794 --- /dev/null +++ b/core/src/main/kotlin/Formats/FormatDescriptor.kt @@ -0,0 +1,12 @@ +package org.jetbrains.dokka.Formats + +import org.jetbrains.dokka.* +import kotlin.reflect.KClass + +public interface FormatDescriptor { + val formatServiceClass: KClass? + val outlineServiceClass: KClass? + val generatorServiceClass: KClass + val packageDocumentationBuilderClass: KClass + val javaDocumentationBuilderClass: KClass +} diff --git a/core/src/main/kotlin/Formats/FormatService.kt b/core/src/main/kotlin/Formats/FormatService.kt new file mode 100644 index 00000000..7e66a6b7 --- /dev/null +++ b/core/src/main/kotlin/Formats/FormatService.kt @@ -0,0 +1,20 @@ +package org.jetbrains.dokka + +/** + * Abstract representation of a formatting service used to output documentation in desired format + * + * Bundled Formatters: + * * [HtmlFormatService] – outputs documentation to HTML format + * * [MarkdownFormatService] – outputs documentation in Markdown format + * * [TextFormatService] – outputs documentation in Text format + */ +public interface FormatService { + /** Returns extension for output files */ + val extension: String + + /** Appends formatted content to [StringBuilder](to) using specified [location] */ + fun appendNodes(location: Location, to: StringBuilder, nodes: Iterable) +} + +/** Format content to [String] using specified [location] */ +fun FormatService.format(location: Location, nodes: Iterable): String = StringBuilder().apply { appendNodes(location, this, nodes) }.toString() diff --git a/core/src/main/kotlin/Formats/HtmlFormatService.kt b/core/src/main/kotlin/Formats/HtmlFormatService.kt new file mode 100644 index 00000000..4d45e6cb --- /dev/null +++ b/core/src/main/kotlin/Formats/HtmlFormatService.kt @@ -0,0 +1,169 @@ +package org.jetbrains.dokka + +import com.google.inject.Inject +import com.google.inject.name.Named +import java.io.File +import java.nio.file.Path +import java.nio.file.Paths + +public open class HtmlFormatService @Inject constructor(@Named("folders") locationService: LocationService, + signatureGenerator: LanguageService, + val templateService: HtmlTemplateService) +: StructuredFormatService(locationService, signatureGenerator, "html"), OutlineFormatService { + override public fun formatText(text: String): String { + return text.htmlEscape() + } + + override fun formatSymbol(text: String): String { + return "${formatText(text)}" + } + + override fun formatKeyword(text: String): String { + return "${formatText(text)}" + } + + override fun formatIdentifier(text: String, kind: IdentifierKind): String { + return "${formatText(text)}" + } + + override fun appendBlockCode(to: StringBuilder, line: String, language: String) { + to.append("
")
+        to.append(line)
+        to.append("
") + } + + override fun appendHeader(to: StringBuilder, text: String, level: Int) { + to.appendln("${text}") + } + + override fun appendParagraph(to: StringBuilder, text: String) { + to.appendln("

${text}

") + } + + override fun appendLine(to: StringBuilder, text: String) { + to.appendln("${text}
") + } + + override fun appendLine(to: StringBuilder) { + to.appendln("
") + } + + override fun appendAnchor(to: StringBuilder, anchor: String) { + to.appendln("") + } + + override fun appendTable(to: StringBuilder, body: () -> Unit) { + to.appendln("") + body() + to.appendln("
") + } + + override fun appendTableHeader(to: StringBuilder, body: () -> Unit) { + to.appendln("") + body() + to.appendln("") + } + + override fun appendTableBody(to: StringBuilder, body: () -> Unit) { + to.appendln("") + body() + to.appendln("") + } + + override fun appendTableRow(to: StringBuilder, body: () -> Unit) { + to.appendln("") + body() + to.appendln("") + } + + override fun appendTableCell(to: StringBuilder, body: () -> Unit) { + to.appendln("") + body() + to.appendln("") + } + + override fun formatLink(text: String, href: String): String { + return "${text}" + } + + override fun formatStrong(text: String): String { + return "${text}" + } + + override fun formatEmphasis(text: String): String { + return "${text}" + } + + override fun formatStrikethrough(text: String): String { + return "${text}" + } + + override fun formatCode(code: String): String { + return "${code}" + } + + override fun formatUnorderedList(text: String): String = "
    ${text}
" + override fun formatOrderedList(text: String): String = "
    ${text}
" + + override fun formatListItem(text: String, kind: ListKind): String { + return "
  • ${text}
  • " + } + + override fun formatBreadcrumbs(items: Iterable): String { + return items.map { formatLink(it) }.joinToString(" / ") + } + + + override fun appendNodes(location: Location, to: StringBuilder, nodes: Iterable) { + templateService.appendHeader(to, getPageTitle(nodes), calcPathToRoot(location)) + super.appendNodes(location, to, nodes) + templateService.appendFooter(to) + } + + override fun appendOutline(location: Location, to: StringBuilder, nodes: Iterable) { + templateService.appendHeader(to, "Module Contents", calcPathToRoot(location)) + super.appendOutline(location, to, nodes) + templateService.appendFooter(to) + } + + private fun calcPathToRoot(location: Location): Path { + val path = Paths.get(location.path) + return path.parent?.relativize(Paths.get(locationService.root.path + '/')) ?: path + } + + override fun getOutlineFileName(location: Location): File { + return File("${location.path}-outline.html") + } + + override fun appendOutlineHeader(location: Location, node: DocumentationNode, to: StringBuilder) { + val link = ContentNodeDirectLink(node) + link.append(languageService.render(node, LanguageService.RenderMode.FULL)) + val signature = formatText(location, link) + to.appendln("${signature}
    ") + } + + override fun appendOutlineLevel(to: StringBuilder, body: () -> Unit) { + to.appendln("
      ") + body() + to.appendln("
    ") + } + + override fun formatNonBreakingSpace(): String = " " +} + +fun getPageTitle(nodes: Iterable): String? { + val breakdownByLocation = nodes.groupBy { node -> formatPageTitle(node) } + return breakdownByLocation.keys.singleOrNull() +} + +fun formatPageTitle(node: DocumentationNode): String { + val path = node.path + if (path.size == 1) { + return path.first().name + } + val qualifiedName = node.qualifiedName() + if (qualifiedName.length == 0 && path.size == 2) { + return path.first().name + " / root package" + } + return path.first().name + " / " + qualifiedName +} diff --git a/core/src/main/kotlin/Formats/HtmlTemplateService.kt b/core/src/main/kotlin/Formats/HtmlTemplateService.kt new file mode 100644 index 00000000..ae42a31b --- /dev/null +++ b/core/src/main/kotlin/Formats/HtmlTemplateService.kt @@ -0,0 +1,34 @@ +package org.jetbrains.dokka + +import java.nio.file.Path + +public interface HtmlTemplateService { + fun appendHeader(to: StringBuilder, title: String?, basePath: Path) + fun appendFooter(to: StringBuilder) + + companion object { + public fun default(css: String? = null): HtmlTemplateService { + return object : HtmlTemplateService { + override fun appendFooter(to: StringBuilder) { + to.appendln("") + to.appendln("") + } + override fun appendHeader(to: StringBuilder, title: String?, basePath: Path) { + to.appendln("") + to.appendln("") + if (title != null) { + to.appendln("$title") + } + if (css != null) { + val cssPath = basePath.resolve(css) + to.appendln("") + } + to.appendln("") + to.appendln("") + } + } + } + } +} + + diff --git a/core/src/main/kotlin/Formats/JekyllFormatService.kt b/core/src/main/kotlin/Formats/JekyllFormatService.kt new file mode 100644 index 00000000..f81257d6 --- /dev/null +++ b/core/src/main/kotlin/Formats/JekyllFormatService.kt @@ -0,0 +1,22 @@ +package org.jetbrains.dokka + +import com.google.inject.Inject + +open class JekyllFormatService + @Inject constructor(locationService: LocationService, + signatureGenerator: LanguageService, + linkExtension: String = "md") +: MarkdownFormatService(locationService, signatureGenerator, linkExtension) { + + override fun appendNodes(location: Location, to: StringBuilder, nodes: Iterable) { + to.appendln("---") + appendFrontMatter(nodes, to) + to.appendln("---") + to.appendln("") + super.appendNodes(location, to, nodes) + } + + protected open fun appendFrontMatter(nodes: Iterable, to: StringBuilder) { + to.appendln("title: ${getPageTitle(nodes)}") + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt new file mode 100644 index 00000000..4eda7910 --- /dev/null +++ b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt @@ -0,0 +1,121 @@ +package org.jetbrains.dokka + +import com.google.inject.Inject + +public class KotlinWebsiteFormatService @Inject constructor(locationService: LocationService, + signatureGenerator: LanguageService) +: JekyllFormatService(locationService, signatureGenerator, "html") { + private var needHardLineBreaks = false + + override fun appendFrontMatter(nodes: Iterable, to: StringBuilder) { + super.appendFrontMatter(nodes, to) + to.appendln("layout: api") + } + + override public fun formatBreadcrumbs(items: Iterable): String { + items.drop(1) + + if (items.count() > 1) { + return "
    " + + items.map { formatLink(it) }.joinToString(" / ") + + "
    " + } + + return "" + } + + override public fun formatCode(code: String): String = if (code.length > 0) "$code" else "" + + override fun formatStrikethrough(text: String): String = "$text" + + override fun appendAsSignature(to: StringBuilder, node: ContentNode, block: () -> Unit) { + val contentLength = node.textLength + if (contentLength == 0) return + to.append("
    ") + needHardLineBreaks = contentLength >= 62 + try { + block() + } finally { + needHardLineBreaks = false + } + to.append("
    ") + } + + override fun appendAsOverloadGroup(to: StringBuilder, block: () -> Unit) { + to.append("
    \n") + block() + to.append("
    \n") + } + + override fun formatLink(text: String, href: String): String { + return "${text}" + } + + override fun appendTable(to: StringBuilder, body: () -> Unit) { + to.appendln("") + body() + to.appendln("
    ") + } + + override fun appendTableHeader(to: StringBuilder, body: () -> Unit) { + to.appendln("") + body() + to.appendln("") + } + + override fun appendTableBody(to: StringBuilder, body: () -> Unit) { + to.appendln("") + body() + to.appendln("") + } + + override fun appendTableRow(to: StringBuilder, body: () -> Unit) { + to.appendln("") + body() + to.appendln("") + } + + override fun appendTableCell(to: StringBuilder, body: () -> Unit) { + to.appendln("") + body() + to.appendln("\n") + } + + override public fun appendBlockCode(to: StringBuilder, line: String, language: String) { + if (language.isNotEmpty()) { + super.appendBlockCode(to, line, language) + } else { + to.append("
    ")
    +            to.append(line.trimStart())
    +            to.append("
    ") + } + } + + override fun formatSymbol(text: String): String { + return "${formatText(text)}" + } + + override fun formatKeyword(text: String): String { + return "${formatText(text)}" + } + + override fun formatIdentifier(text: String, kind: IdentifierKind): String { + return "${formatText(text)}" + } + + override fun formatSoftLineBreak(): String = if (needHardLineBreaks) + "
    " + else + "" + + override fun formatIndentedSoftLineBreak(): String = if (needHardLineBreaks) + "
        " + else + "" + + private fun identifierClassName(kind: IdentifierKind) = when(kind) { + IdentifierKind.ParameterName -> "parameterName" + IdentifierKind.SummarizedTypeName -> "summarizedTypeName" + else -> "identifier" + } +} diff --git a/core/src/main/kotlin/Formats/MarkdownFormatService.kt b/core/src/main/kotlin/Formats/MarkdownFormatService.kt new file mode 100644 index 00000000..f694ae3e --- /dev/null +++ b/core/src/main/kotlin/Formats/MarkdownFormatService.kt @@ -0,0 +1,117 @@ +package org.jetbrains.dokka + +import com.google.inject.Inject + + +public open class MarkdownFormatService + @Inject constructor(locationService: LocationService, + signatureGenerator: LanguageService, + linkExtension: String = "md") +: StructuredFormatService(locationService, signatureGenerator, "md", linkExtension) { + override public fun formatBreadcrumbs(items: Iterable): String { + return items.map { formatLink(it) }.joinToString(" / ") + } + + override public fun formatText(text: String): String { + return text.htmlEscape() + } + + override fun formatSymbol(text: String): String { + return text.htmlEscape() + } + + override fun formatKeyword(text: String): String { + return text.htmlEscape() + } + override fun formatIdentifier(text: String, kind: IdentifierKind): String { + return text.htmlEscape() + } + + override public fun formatCode(code: String): String { + return "`$code`" + } + + override public fun formatUnorderedList(text: String): String = text + "\n" + override public fun formatOrderedList(text: String): String = text + "\n" + + override fun formatListItem(text: String, kind: ListKind): String { + val itemText = if (text.endsWith("\n")) text else text + "\n" + return if (kind == ListKind.Unordered) "* $itemText" else "1. $itemText" + } + + override public fun formatStrong(text: String): String { + return "**$text**" + } + + override fun formatEmphasis(text: String): String { + return "*$text*" + } + + override fun formatStrikethrough(text: String): String { + return "~~$text~~" + } + + override fun formatLink(text: String, href: String): String { + return "[$text]($href)" + } + + override public fun appendLine(to: StringBuilder) { + to.appendln() + } + + override public fun appendLine(to: StringBuilder, text: String) { + to.appendln(text) + } + + override fun appendAnchor(to: StringBuilder, anchor: String) { + // no anchors in Markdown + } + + override public fun appendParagraph(to: StringBuilder, text: String) { + to.appendln() + to.appendln(text) + to.appendln() + } + + override public fun appendHeader(to: StringBuilder, text: String, level: Int) { + appendLine(to) + appendLine(to, "${"#".repeat(level)} $text") + appendLine(to) + } + + override public fun appendBlockCode(to: StringBuilder, line: String, language: String) { + appendLine(to) + to.appendln("``` ${language}") + to.appendln(line) + to.appendln("```") + appendLine(to) + } + + override fun appendTable(to: StringBuilder, body: () -> Unit) { + to.appendln() + body() + to.appendln() + } + + override fun appendTableHeader(to: StringBuilder, body: () -> Unit) { + body() + } + + override fun appendTableBody(to: StringBuilder, body: () -> Unit) { + body() + } + + override fun appendTableRow(to: StringBuilder, body: () -> Unit) { + to.append("|") + body() + to.appendln() + } + + override fun appendTableCell(to: StringBuilder, body: () -> Unit) { + to.append(" ") + body() + to.append(" |") + } + + override fun formatNonBreakingSpace(): String = " " +} diff --git a/core/src/main/kotlin/Formats/OutlineService.kt b/core/src/main/kotlin/Formats/OutlineService.kt new file mode 100644 index 00000000..6626cf51 --- /dev/null +++ b/core/src/main/kotlin/Formats/OutlineService.kt @@ -0,0 +1,29 @@ +package org.jetbrains.dokka + +import java.io.File + +/** + * Service for building the outline of the package contents. + */ +public interface OutlineFormatService { + fun getOutlineFileName(location: Location): File + + public fun appendOutlineHeader(location: Location, node: DocumentationNode, to: StringBuilder) + public fun appendOutlineLevel(to: StringBuilder, body: () -> Unit) + + /** Appends formatted outline to [StringBuilder](to) using specified [location] */ + public fun appendOutline(location: Location, to: StringBuilder, nodes: Iterable) { + for (node in nodes) { + appendOutlineHeader(location, node, to) + if (node.members.any()) { + val sortedMembers = node.members.sortedBy { it.name } + appendOutlineLevel(to) { + appendOutline(location, to, sortedMembers) + } + } + } + } + + fun formatOutline(location: Location, nodes: Iterable): String = + StringBuilder().apply { appendOutline(location, this, nodes) }.toString() +} diff --git a/core/src/main/kotlin/Formats/StandardFormats.kt b/core/src/main/kotlin/Formats/StandardFormats.kt new file mode 100644 index 00000000..94e1b115 --- /dev/null +++ b/core/src/main/kotlin/Formats/StandardFormats.kt @@ -0,0 +1,38 @@ +package org.jetbrains.dokka.Formats + +import org.jetbrains.dokka.* + +abstract class KotlinFormatDescriptorBase : FormatDescriptor { + override val packageDocumentationBuilderClass = KotlinPackageDocumentationBuilder::class + override val javaDocumentationBuilderClass = KotlinJavaDocumentationBuilder::class + + override val generatorServiceClass = FileGenerator::class +} + +class HtmlFormatDescriptor : KotlinFormatDescriptorBase() { + override val formatServiceClass = HtmlFormatService::class + override val outlineServiceClass = HtmlFormatService::class +} + +class HtmlAsJavaFormatDescriptor : FormatDescriptor { + override val formatServiceClass = HtmlFormatService::class + override val outlineServiceClass = HtmlFormatService::class + override val generatorServiceClass = FileGenerator::class + override val packageDocumentationBuilderClass = KotlinAsJavaDocumentationBuilder::class + override val javaDocumentationBuilderClass = JavaPsiDocumentationBuilder::class +} + +class KotlinWebsiteFormatDescriptor : KotlinFormatDescriptorBase() { + override val formatServiceClass = KotlinWebsiteFormatService::class + override val outlineServiceClass = YamlOutlineService::class +} + +class JekyllFormatDescriptor : KotlinFormatDescriptorBase() { + override val formatServiceClass = JekyllFormatService::class + override val outlineServiceClass = null +} + +class MarkdownFormatDescriptor : KotlinFormatDescriptorBase() { + override val formatServiceClass = MarkdownFormatService::class + override val outlineServiceClass = null +} diff --git a/core/src/main/kotlin/Formats/StructuredFormatService.kt b/core/src/main/kotlin/Formats/StructuredFormatService.kt new file mode 100644 index 00000000..32a2b68a --- /dev/null +++ b/core/src/main/kotlin/Formats/StructuredFormatService.kt @@ -0,0 +1,367 @@ +package org.jetbrains.dokka + +import org.jetbrains.dokka.LanguageService.RenderMode +import java.util.* + +data class FormatLink(val text: String, val href: String) + +enum class ListKind { + Ordered, + Unordered +} + +abstract class StructuredFormatService(locationService: LocationService, + val languageService: LanguageService, + override val extension: String, + val linkExtension: String = extension) : FormatService { + val locationService: LocationService = locationService.withExtension(linkExtension) + + abstract fun appendBlockCode(to: StringBuilder, line: String, language: String) + abstract fun appendHeader(to: StringBuilder, text: String, level: Int = 1) + abstract fun appendParagraph(to: StringBuilder, text: String) + abstract fun appendLine(to: StringBuilder, text: String) + abstract fun appendLine(to: StringBuilder) + abstract fun appendAnchor(to: StringBuilder, anchor: String) + + abstract fun appendTable(to: StringBuilder, body: () -> Unit) + abstract fun appendTableHeader(to: StringBuilder, body: () -> Unit) + abstract fun appendTableBody(to: StringBuilder, body: () -> Unit) + abstract fun appendTableRow(to: StringBuilder, body: () -> Unit) + abstract fun appendTableCell(to: StringBuilder, body: () -> Unit) + + abstract fun formatText(text: String): String + abstract fun formatSymbol(text: String): String + abstract fun formatKeyword(text: String): String + abstract fun formatIdentifier(text: String, kind: IdentifierKind): String + fun formatEntity(text: String): String = text + abstract fun formatLink(text: String, href: String): String + open fun formatLink(link: FormatLink): String = formatLink(formatText(link.text), link.href) + abstract fun formatStrong(text: String): String + abstract fun formatStrikethrough(text: String): String + abstract fun formatEmphasis(text: String): String + abstract fun formatCode(code: String): String + abstract fun formatUnorderedList(text: String): String + abstract fun formatOrderedList(text: String): String + abstract fun formatListItem(text: String, kind: ListKind): String + abstract fun formatBreadcrumbs(items: Iterable): String + abstract fun formatNonBreakingSpace(): String + open fun formatSoftLineBreak(): String = "" + open fun formatIndentedSoftLineBreak(): String = "" + + open fun formatText(location: Location, nodes: Iterable, listKind: ListKind = ListKind.Unordered): String { + return nodes.map { formatText(location, it, listKind) }.joinToString("") + } + + open fun formatText(location: Location, content: ContentNode, listKind: ListKind = ListKind.Unordered): String { + return StringBuilder().apply { + when (content) { + is ContentText -> append(formatText(content.text)) + is ContentSymbol -> append(formatSymbol(content.text)) + is ContentKeyword -> append(formatKeyword(content.text)) + is ContentIdentifier -> append(formatIdentifier(content.text, content.kind)) + is ContentNonBreakingSpace -> append(formatNonBreakingSpace()) + is ContentSoftLineBreak -> append(formatSoftLineBreak()) + is ContentIndentedSoftLineBreak -> append(formatIndentedSoftLineBreak()) + is ContentEntity -> append(formatEntity(content.text)) + is ContentStrong -> append(formatStrong(formatText(location, content.children))) + is ContentStrikethrough -> append(formatStrikethrough(formatText(location, content.children))) + is ContentCode -> append(formatCode(formatText(location, content.children))) + is ContentEmphasis -> append(formatEmphasis(formatText(location, content.children))) + is ContentUnorderedList -> append(formatUnorderedList(formatText(location, content.children, ListKind.Unordered))) + is ContentOrderedList -> append(formatOrderedList(formatText(location, content.children, ListKind.Ordered))) + is ContentListItem -> append(formatListItem(formatText(location, content.children), listKind)) + + is ContentNodeLink -> { + val node = content.node + val linkTo = if (node != null) locationHref(location, node) else "#" + val linkText = formatText(location, content.children) + if (linkTo == ".") { + append(linkText) + } else { + append(formatLink(linkText, linkTo)) + } + } + is ContentExternalLi