diff --git a/docs/src/doc/docs/user_guide/versioning/versioning.md b/docs/src/doc/docs/user_guide/versioning/versioning.md index 7cb2a78350f..dbb72004129 100644 --- a/docs/src/doc/docs/user_guide/versioning/versioning.md +++ b/docs/src/doc/docs/user_guide/versioning/versioning.md @@ -19,9 +19,6 @@ Above configuration should be placed under the `pluginsConfiguration` block spec Configuration object is named `org.jetbrains.dokka.versioning.VersioningConfiguration`. -!!! note - In the current release versioning is available only for the multimodule. Supporting single module is scheduled for next release - ### Directory structure required If you pass previous versions using `olderVersionsDir`, a particular directory structure is required: diff --git a/plugins/all-modules-page/api/all-modules-page.api b/plugins/all-modules-page/api/all-modules-page.api index 1849c6d9bc2..004ea9d7250 100644 --- a/plugins/all-modules-page/api/all-modules-page.api +++ b/plugins/all-modules-page/api/all-modules-page.api @@ -4,7 +4,6 @@ public final class org/jetbrains/dokka/allModulesPage/AllModulesPageGeneration : public final fun finishProcessingSubmodules ()V public fun generate (Lorg/jetbrains/dokka/Timer;)V public fun getGenerationName ()Ljava/lang/String; - public final fun handlePreviousDocs ()V public final fun processMultiModule (Lorg/jetbrains/dokka/pages/RootPageNode;)V public final fun processSubmodules ()Lorg/jetbrains/dokka/allModulesPage/AllModulesPageGeneration$DefaultAllModulesContext; public final fun render (Lorg/jetbrains/dokka/pages/RootPageNode;)V diff --git a/plugins/all-modules-page/src/main/kotlin/AllModulesPageGeneration.kt b/plugins/all-modules-page/src/main/kotlin/AllModulesPageGeneration.kt index 21c624efa4a..b163e9cd0e4 100644 --- a/plugins/all-modules-page/src/main/kotlin/AllModulesPageGeneration.kt +++ b/plugins/all-modules-page/src/main/kotlin/AllModulesPageGeneration.kt @@ -11,13 +11,11 @@ import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.templates.TemplatingPlugin import org.jetbrains.dokka.templates.TemplatingResult import org.jetbrains.dokka.transformers.pages.CreationContext -import org.jetbrains.dokka.versioning.VersioningPlugin class AllModulesPageGeneration(private val context: DokkaContext) : Generation { private val allModulesPagePlugin by lazy { context.plugin() } private val templatingPlugin by lazy { context.plugin() } - private val versioningPlugin by lazy { context.plugin() } override fun Timer.generate() { report("Processing submodules") @@ -26,9 +24,6 @@ class AllModulesPageGeneration(private val context: DokkaContext) : Generation { report("Creating all modules page") val pages = createAllModulesPage(generationContext) - report("Copy previous documentation") - handlePreviousDocs() - report("Transforming pages") val transformedPages = transformAllModulesPage(pages) @@ -44,8 +39,6 @@ class AllModulesPageGeneration(private val context: DokkaContext) : Generation { override val generationName = "index page for project" - fun handlePreviousDocs() = versioningPlugin.querySingle { versioningHandler }.invoke() - fun createAllModulesPage(allModulesContext: DefaultAllModulesContext) = allModulesPagePlugin.querySingle { allModulesPageCreator }.invoke(allModulesContext) diff --git a/plugins/all-modules-page/src/main/kotlin/MultimoduleLocationProvider.kt b/plugins/all-modules-page/src/main/kotlin/MultimoduleLocationProvider.kt index 1a323f63c3d..9c7344e2f5e 100644 --- a/plugins/all-modules-page/src/main/kotlin/MultimoduleLocationProvider.kt +++ b/plugins/all-modules-page/src/main/kotlin/MultimoduleLocationProvider.kt @@ -27,7 +27,7 @@ open class MultimoduleLocationProvider(private val root: RootPageNode, dokkaCont ?.let(externalModuleLinkResolver::resolveLinkToModuleIndex) override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean) = - if (node is ContentPage && MultimodulePageCreator.MULTIMODULE_ROOT_DRI in node.dri) pathToRoot(root) + "index" + if (node is ContentPage && MultimodulePageCreator.MULTIMODULE_ROOT_DRI in node.dri) pathToRoot(root) + "index${if(skipExtension)"" else ".html"}" else defaultLocationProvider.resolve(node, context, skipExtension) override fun pathToRoot(from: PageNode): String = defaultLocationProvider.pathToRoot(from) diff --git a/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt b/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt index 4285046a160..f522fd4ca2a 100644 --- a/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt +++ b/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt @@ -19,14 +19,10 @@ import org.jetbrains.dokka.model.doc.P import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.configuration import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.transformers.pages.PageCreator import org.jetbrains.dokka.utilities.DokkaLogger -import org.jetbrains.dokka.versioning.ReplaceVersionsCommand -import org.jetbrains.dokka.versioning.VersioningConfiguration -import org.jetbrains.dokka.versioning.VersioningPlugin import java.io.File class MultimodulePageCreator( @@ -46,11 +42,6 @@ class MultimodulePageCreator( kind = ContentKind.Cover, sourceSets = sourceSetData ) { - /* The line below checks if there is a provided configuration for versioning. - If not, we are skipping the template for inserting versions navigation */ - configuration(context)?.let { - group(extra = PropertyContainer.withAll(InsertTemplateExtra(ReplaceVersionsCommand))) { } - } getMultiModuleDocumentation(context.configuration.includes).takeIf { it.isNotEmpty() }?.let { nodes -> group(kind = ContentKind.Cover) { nodes.forEach { node -> diff --git a/plugins/base/api/base.api b/plugins/base/api/base.api index 10d2c564c66..9eb0d4aedde 100644 --- a/plugins/base/api/base.api +++ b/plugins/base/api/base.api @@ -40,6 +40,7 @@ public final class org/jetbrains/dokka/base/DokkaBase : org/jetbrains/dokka/plug public final fun getPageMerger ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getPageMergerStrategy ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; public final fun getPathToRootConsumer ()Lorg/jetbrains/dokka/plugability/Extension; + public final fun getPostActions ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; public final fun getPreMergeDocumentableTransformer ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; public final fun getPsiToDocumentableTranslator ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getResolveLinkConsumer ()Lorg/jetbrains/dokka/plugability/Extension; @@ -243,6 +244,7 @@ public abstract class org/jetbrains/dokka/base/renderers/DefaultRenderer : org/j protected final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; protected final fun getLocationProvider ()Lorg/jetbrains/dokka/base/resolvers/local/LocationProvider; protected final fun getOutputWriter ()Lorg/jetbrains/dokka/base/renderers/OutputWriter; + protected fun getPostActions ()Ljava/lang/Iterable; protected fun getPreprocessors ()Ljava/lang/Iterable; protected final fun groupDivergentInstances (Lorg/jetbrains/dokka/pages/ContentDivergentGroup;Lorg/jetbrains/dokka/pages/ContentPage;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;)Ljava/util/Map; public fun render (Lorg/jetbrains/dokka/pages/RootPageNode;)V @@ -297,6 +299,9 @@ public final class org/jetbrains/dokka/base/renderers/PackageListService$Compani public final fun renderPackageList (Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; } +public abstract interface class org/jetbrains/dokka/base/renderers/PostAction : kotlin/jvm/functions/Function0 { +} + public final class org/jetbrains/dokka/base/renderers/RootCreator : org/jetbrains/dokka/transformers/pages/PageTransformer { public static final field INSTANCE Lorg/jetbrains/dokka/base/renderers/RootCreator; public fun invoke (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RendererSpecificRootPage; @@ -365,6 +370,8 @@ public class org/jetbrains/dokka/base/renderers/html/HtmlRenderer : org/jetbrain public synthetic fun buildText (Ljava/lang/Object;Lorg/jetbrains/dokka/pages/ContentText;)V public fun buildText (Lkotlinx/html/FlowContent;Lorg/jetbrains/dokka/pages/ContentText;)V public fun clickableLogo (Lkotlinx/html/FlowContent;Lorg/jetbrains/dokka/pages/PageNode;Ljava/lang/String;)V + public synthetic fun getPostActions ()Ljava/lang/Iterable; + protected fun getPostActions ()Ljava/util/List; public synthetic fun getPreprocessors ()Ljava/lang/Iterable; protected fun getPreprocessors ()Ljava/util/List; public fun render (Lorg/jetbrains/dokka/pages/RootPageNode;)V diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index 7e88d08f0d4..28f0ff6ac58 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -42,6 +42,7 @@ class DokkaBase : DokkaPlugin() { val externalLocationProviderFactory by extensionPoint() val outputWriter by extensionPoint() val htmlPreprocessors by extensionPoint() + val postActions by extensionPoint() val kotlinAnalysis by extensionPoint() val tabSortingStrategy by extensionPoint() val immediateHtmlCommandConsumer by extensionPoint() diff --git a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt index 5eaf9fc74d0..cb438d413f7 100644 --- a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt @@ -25,6 +25,7 @@ abstract class DefaultRenderer( private set protected open val preprocessors: Iterable = emptyList() + protected open val postActions: Iterable = emptyList() abstract fun T.buildHeader(level: Int, node: ContentHeader, content: T.() -> Unit) abstract fun T.buildLink(address: String, content: T.() -> Unit) @@ -209,6 +210,8 @@ abstract class DefaultRenderer( runBlocking(Dispatchers.Default) { renderPages(newRoot) } + + postActions.forEach { it() } } protected fun ContentDivergentGroup.groupDivergentInstances( diff --git a/plugins/base/src/main/kotlin/renderers/PostAction.kt b/plugins/base/src/main/kotlin/renderers/PostAction.kt new file mode 100644 index 00000000000..62b088c6461 --- /dev/null +++ b/plugins/base/src/main/kotlin/renderers/PostAction.kt @@ -0,0 +1,3 @@ +package org.jetbrains.dokka.base.renderers + +interface PostAction : () -> Unit \ No newline at end of file diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt index 317533320d2..6c1a137c9fd 100644 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -43,6 +43,7 @@ open class HtmlRenderer( private var shouldRenderSourceSetBubbles: Boolean = false override val preprocessors = context.plugin().query { htmlPreprocessors } + override val postActions = context.plugin().query { postActions } private val tabSortingStrategy = context.plugin().querySingle { tabSortingStrategy } diff --git a/plugins/versioning/api/versioning.api b/plugins/versioning/api/versioning.api index 8223579b630..f83aaf3d61b 100644 --- a/plugins/versioning/api/versioning.api +++ b/plugins/versioning/api/versioning.api @@ -5,27 +5,22 @@ public final class org/jetbrains/dokka/versioning/ByConfigurationVersionOrdering } public final class org/jetbrains/dokka/versioning/DefaultVersioningHandler : org/jetbrains/dokka/versioning/VersioningHandler { - public static final field Companion Lorg/jetbrains/dokka/versioning/DefaultVersioningHandler$Companion; public fun (Lorg/jetbrains/dokka/plugability/DokkaContext;)V public fun currentVersion ()Ljava/io/File; public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; + public fun getPreviousVersions ()Ljava/util/Map; public fun getVersions ()Ljava/util/Map; - public synthetic fun invoke ()Ljava/lang/Object; - public fun invoke ()V -} - -public final class org/jetbrains/dokka/versioning/DefaultVersioningHandler$Companion { } public final class org/jetbrains/dokka/versioning/HtmlVersionsNavigationCreator : org/jetbrains/dokka/versioning/VersionsNavigationCreator { public fun (Lorg/jetbrains/dokka/plugability/DokkaContext;)V public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; - public fun invoke ()Ljava/lang/String; public fun invoke (Ljava/io/File;)Ljava/lang/String; + public fun invoke (Ljava/lang/String;)Ljava/lang/String; } public final class org/jetbrains/dokka/versioning/MultiModuleStylesInstaller : org/jetbrains/dokka/transformers/pages/PageTransformer { - public static final field INSTANCE Lorg/jetbrains/dokka/versioning/MultiModuleStylesInstaller; + public fun (Lorg/jetbrains/dokka/plugability/DokkaContext;)V public fun invoke (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode; } @@ -45,7 +40,17 @@ public final class org/jetbrains/dokka/versioning/ReplaceVersionCommandHandler : } public final class org/jetbrains/dokka/versioning/ReplaceVersionsCommand : org/jetbrains/dokka/base/templating/Command { - public static final field INSTANCE Lorg/jetbrains/dokka/versioning/ReplaceVersionsCommand; + public fun ()V + public fun (Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lorg/jetbrains/dokka/versioning/ReplaceVersionsCommand; + public static synthetic fun copy$default (Lorg/jetbrains/dokka/versioning/ReplaceVersionsCommand;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/dokka/versioning/ReplaceVersionsCommand; + public fun equals (Ljava/lang/Object;)Z + public final fun getLocation ()Ljava/lang/String; + public fun hashCode ()I + public final fun setLocation (Ljava/lang/String;)V + public fun toString ()Ljava/lang/String; } public final class org/jetbrains/dokka/versioning/SemVerVersionOrdering : org/jetbrains/dokka/versioning/VersionsOrdering { @@ -53,25 +58,43 @@ public final class org/jetbrains/dokka/versioning/SemVerVersionOrdering : org/je public fun order (Ljava/util/List;)Ljava/util/List; } +public final class org/jetbrains/dokka/versioning/VersionDirs { + public fun (Ljava/io/File;Ljava/io/File;)V + public final fun component1 ()Ljava/io/File; + public final fun component2 ()Ljava/io/File; + public final fun copy (Ljava/io/File;Ljava/io/File;)Lorg/jetbrains/dokka/versioning/VersionDirs; + public static synthetic fun copy$default (Lorg/jetbrains/dokka/versioning/VersionDirs;Ljava/io/File;Ljava/io/File;ILjava/lang/Object;)Lorg/jetbrains/dokka/versioning/VersionDirs; + public fun equals (Ljava/lang/Object;)Z + public final fun getDst ()Ljava/io/File; + public final fun getSrc ()Ljava/io/File; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class org/jetbrains/dokka/versioning/VersioningConfiguration : org/jetbrains/dokka/plugability/ConfigurableBlock { public static final field Companion Lorg/jetbrains/dokka/versioning/VersioningConfiguration$Companion; + public static final field OLDER_VERSIONS_DIR Ljava/lang/String; + public static final field VERSIONS_FILE Ljava/lang/String; public fun ()V - public fun (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;)V - public synthetic fun (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;)V + public synthetic fun (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/io/File; public final fun component2 ()Ljava/util/List; public final fun component3 ()Ljava/util/List; public final fun component4 ()Ljava/lang/String; - public final fun copy (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;)Lorg/jetbrains/dokka/versioning/VersioningConfiguration; - public static synthetic fun copy$default (Lorg/jetbrains/dokka/versioning/VersioningConfiguration;Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/dokka/versioning/VersioningConfiguration; + public final fun component5 ()Ljava/lang/Boolean; + public final fun copy (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;)Lorg/jetbrains/dokka/versioning/VersioningConfiguration; + public static synthetic fun copy$default (Lorg/jetbrains/dokka/versioning/VersioningConfiguration;Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;ILjava/lang/Object;)Lorg/jetbrains/dokka/versioning/VersioningConfiguration; public fun equals (Ljava/lang/Object;)Z public final fun getOlderVersions ()Ljava/util/List; public final fun getOlderVersionsDir ()Ljava/io/File; + public final fun getOnEachPage ()Ljava/lang/Boolean; public final fun getVersion ()Ljava/lang/String; public final fun getVersionsOrdering ()Ljava/util/List; public fun hashCode ()I public final fun setOlderVersions (Ljava/util/List;)V public final fun setOlderVersionsDir (Ljava/io/File;)V + public final fun setOnEachPage (Ljava/lang/Boolean;)V public final fun setVersion (Ljava/lang/String;)V public final fun setVersionsOrdering (Ljava/util/List;)V public fun toString ()Ljava/lang/String; @@ -80,12 +103,14 @@ public final class org/jetbrains/dokka/versioning/VersioningConfiguration : org/ public final class org/jetbrains/dokka/versioning/VersioningConfiguration$Companion { public final fun getDefaultOlderVersions ()Ljava/util/List; public final fun getDefaultOlderVersionsDir ()Ljava/io/File; + public final fun getDefaultOnEachPage ()Z public final fun getDefaultVersion ()Ljava/lang/Void; public final fun getDefaultVersionsOrdering ()Ljava/util/List; } -public abstract interface class org/jetbrains/dokka/versioning/VersioningHandler : kotlin/jvm/functions/Function0 { +public abstract interface class org/jetbrains/dokka/versioning/VersioningHandler { public abstract fun currentVersion ()Ljava/io/File; + public abstract fun getPreviousVersions ()Ljava/util/Map; public abstract fun getVersions ()Ljava/util/Map; } @@ -94,6 +119,8 @@ public final class org/jetbrains/dokka/versioning/VersioningPlugin : org/jetbrai public final fun getCssStyleInstaller ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getDefaultVersioningHandler ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getDefaultVersioningNavigationCreator ()Lorg/jetbrains/dokka/plugability/Extension; + public final fun getDefaultVersionsNavigationAdder ()Lorg/jetbrains/dokka/plugability/Extension; + public final fun getPreviousDocumentationCopier ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getReplaceVersionCommandHandler ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getResolveLinkConsumer ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getVersioningHandler ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; @@ -103,11 +130,24 @@ public final class org/jetbrains/dokka/versioning/VersioningPlugin : org/jetbrai } public abstract interface class org/jetbrains/dokka/versioning/VersionsNavigationCreator { - public abstract fun invoke ()Ljava/lang/String; public abstract fun invoke (Ljava/io/File;)Ljava/lang/String; + public abstract fun invoke (Ljava/lang/String;)Ljava/lang/String; } public abstract interface class org/jetbrains/dokka/versioning/VersionsOrdering { public abstract fun order (Ljava/util/List;)Ljava/util/List; } +public final class versioning/DefaultPreviousDocumentationCopier : org/jetbrains/dokka/base/renderers/PostAction { + public fun (Lorg/jetbrains/dokka/plugability/DokkaContext;)V + public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; + public synthetic fun invoke ()Ljava/lang/Object; + public fun invoke ()V +} + +public final class versioning/VersionsNavigationAdder : org/jetbrains/dokka/transformers/pages/PageTransformer { + public fun (Lorg/jetbrains/dokka/plugability/DokkaContext;)V + public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; + public fun invoke (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode; +} + diff --git a/plugins/versioning/src/main/kotlin/versioning/PreviousDocumentationCopier.kt b/plugins/versioning/src/main/kotlin/versioning/PreviousDocumentationCopier.kt new file mode 100644 index 00000000000..516e7999442 --- /dev/null +++ b/plugins/versioning/src/main/kotlin/versioning/PreviousDocumentationCopier.kt @@ -0,0 +1,55 @@ +package versioning + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.jetbrains.dokka.base.renderers.PostAction +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.query +import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.templates.TemplateProcessingStrategy +import org.jetbrains.dokka.templates.TemplatingPlugin +import org.jetbrains.dokka.versioning.VersionId +import org.jetbrains.dokka.versioning.VersioningConfiguration +import org.jetbrains.dokka.versioning.VersioningPlugin +import java.io.File + +class DefaultPreviousDocumentationCopier(val context: DokkaContext) : PostAction { + private val versioningHandler by lazy { context.plugin().querySingle { versioningHandler } } + private val processingStrategies: List = + context.plugin().query { templateProcessingStrategy } + + override fun invoke() { + versioningHandler.previousVersions.onEach { (_, dirs) -> copyVersion(dirs.src, dirs.dst) } + .toMap() + } + + private fun copyVersion(versionRoot: File, targetParent: File) { + targetParent.apply { mkdirs() } + val ignoreDir = versionRoot.resolve(VersioningConfiguration.OLDER_VERSIONS_DIR) + runBlocking(Dispatchers.Default) { + coroutineScope { + versionRoot.listFiles().orEmpty() + .filter { it.absolutePath != ignoreDir.absolutePath } + .forEach { versionRootContent -> + launch { + processRecursively(versionRootContent, targetParent) + } + } + } + } + } + + private fun processRecursively(versionRootContent: File, targetParent: File) { + if (versionRootContent.isDirectory) { + val target = targetParent.resolve(versionRootContent.name).also { it.mkdir() } + versionRootContent.listFiles()?.forEach { + processRecursively(it, target) + } + } else processingStrategies.first { + it.process(versionRootContent, targetParent.resolve(versionRootContent.name), null) + } + } +} \ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionCommandConsumer.kt b/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionCommandConsumer.kt index 2577b2da5c7..1dd6157e94a 100644 --- a/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionCommandConsumer.kt +++ b/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionCommandConsumer.kt @@ -27,7 +27,7 @@ class ReplaceVersionCommandConsumer(context: DokkaContext) : ImmediateHtmlComman command as ReplaceVersionsCommand templateCommandFor(command, tagConsumer).visit { unsafe { - +versionsNavigationCreator() + +versionsNavigationCreator(command.location) } } } @@ -36,10 +36,12 @@ class ReplaceVersionCommandConsumer(context: DokkaContext) : ImmediateHtmlComman command: Command, block: TemplateBlock, tagConsumer: ImmediateResolutionTagConsumer - ): R = - templateCommandFor(command, tagConsumer).visitAndFinalize(tagConsumer) { + ): R { + command as ReplaceVersionsCommand + return templateCommandFor(command, tagConsumer).visitAndFinalize(tagConsumer) { unsafe { - +versionsNavigationCreator() + +versionsNavigationCreator(command.location) } } + } } \ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionsCommand.kt b/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionsCommand.kt index 2d2c8e36d65..8437ca1e178 100644 --- a/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionsCommand.kt +++ b/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionsCommand.kt @@ -9,7 +9,7 @@ import org.jetbrains.dokka.templates.CommandHandler import org.jsoup.nodes.Element import java.io.File -object ReplaceVersionsCommand : Command +data class ReplaceVersionsCommand(var location: String = ""): Command class ReplaceVersionCommandHandler(context: DokkaContext) : CommandHandler { diff --git a/plugins/versioning/src/main/kotlin/versioning/VersioningConfiguration.kt b/plugins/versioning/src/main/kotlin/versioning/VersioningConfiguration.kt index f5c69cf4a8d..a629a668336 100644 --- a/plugins/versioning/src/main/kotlin/versioning/VersioningConfiguration.kt +++ b/plugins/versioning/src/main/kotlin/versioning/VersioningConfiguration.kt @@ -9,6 +9,7 @@ data class VersioningConfiguration( var olderVersions: List? = defaultOlderVersions, var versionsOrdering: List? = defaultVersionsOrdering, var version: String? = defaultVersion, + var onEachPage: Boolean? = defaultOnEachPage ) : ConfigurableBlock { internal fun versionFromConfigurationOrModule(dokkaContext: DokkaContext): String = version ?: dokkaContext.configuration.moduleVersion ?: "1.0" @@ -25,5 +26,9 @@ data class VersioningConfiguration( val defaultOlderVersions: List? = null val defaultVersionsOrdering: List? = null val defaultVersion = null + val defaultOnEachPage = true + + const val OLDER_VERSIONS_DIR = "older" + const val VERSIONS_FILE = "version.json" } } \ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/versioning/VersioningHandler.kt b/plugins/versioning/src/main/kotlin/versioning/VersioningHandler.kt index 1cc584b77dc..d000f56a375 100644 --- a/plugins/versioning/src/main/kotlin/versioning/VersioningHandler.kt +++ b/plugins/versioning/src/main/kotlin/versioning/VersioningHandler.kt @@ -15,90 +15,60 @@ import org.jetbrains.dokka.templates.TemplateProcessingStrategy import org.jetbrains.dokka.templates.TemplatingPlugin import java.io.File -interface VersioningHandler : () -> Unit { - fun getVersions(): Map +interface VersioningHandler { + val versions: Map + val previousVersions: Map fun currentVersion(): File? } +data class VersionDirs(val src: File, val dst: File) typealias VersionId = String class DefaultVersioningHandler(val context: DokkaContext) : VersioningHandler { private val mapper = ObjectMapper() - - private lateinit var versions: Map - - private val processingStrategies: List = - context.plugin().query { templateProcessingStrategy } - private val configuration = configuration(context) - override fun getVersions() = versions - - override fun currentVersion() = configuration?.let { versionsConfiguration -> - versions[versionsConfiguration.versionFromConfigurationOrModule(context)] + override val previousVersions: Map by lazy { + configuration?.let { versionsConfiguration -> + handlePreviousVersions(versionsConfiguration.allOlderVersions(), context.configuration.outputDir) + } ?: emptyMap() } - override fun invoke() { + private val currentVersionId: Pair by lazy { configuration?.let { versionsConfiguration -> - versions = - mapOf(versionsConfiguration.versionFromConfigurationOrModule(context) to context.configuration.outputDir) - handlePreviousVersions(versionsConfiguration.allOlderVersions(), context.configuration.outputDir) + versionsConfiguration.versionFromConfigurationOrModule(context) to context.configuration.outputDir + }?.also { mapper.writeValue( - context.configuration.outputDir.resolve(VERSIONS_FILE), - Version(versionsConfiguration.versionFromConfigurationOrModule(context)) + it.second.resolve(VersioningConfiguration.VERSIONS_FILE), + Version(it.first) ) - } + } ?: throw IllegalAccessException("Can't get plugin configuration") } - - private fun handlePreviousVersions(olderVersions: List, output: File): Map { - return versionsFrom(olderVersions) - .also { fetched -> - versions = versions + fetched.map { (key, _) -> - key to output.resolve(OLDER_VERSIONS_DIR).resolve(key) - }.toMap() - } - .onEach { (version, path) -> copyVersion(version, path, output) }.toMap() + override val versions: Map by lazy { + previousVersions.map { (k, v) -> k to v.dst }.toMap() + currentVersionId } - private fun versionsFrom(olderVersions: List) = - olderVersions.mapNotNull { versionDir -> - versionDir.listFiles { _, name -> name == VERSIONS_FILE }?.firstOrNull()?.let { file -> - val versionsContent = mapper.readValue(file) - Pair(versionsContent.version, versionDir) - }.also { - if (it == null) context.logger.warn("Failed to find versions file named $VERSIONS_FILE in $versionDir") - } + + override fun currentVersion() = currentVersionId.second + + private fun handlePreviousVersions(olderVersions: List, output: File): Map = + versionsFrom(olderVersions).associate { (key, srcDir) -> + key to VersionDirs(srcDir, output.resolve(VersioningConfiguration.OLDER_VERSIONS_DIR).resolve(key)) } - private fun copyVersion(version: VersionId, versionRoot: File, output: File) { - val targetParent = output.resolve(OLDER_VERSIONS_DIR).resolve(version).apply { mkdirs() } - val olderDirs = versionRoot.resolve(OLDER_VERSIONS_DIR) - runBlocking(Dispatchers.Default) { - coroutineScope { - versionRoot.listFiles().orEmpty() - .filter { it.absolutePath != olderDirs.absolutePath } - .forEach { versionRootContent -> - launch { - if (versionRootContent.isDirectory) versionRootContent.copyRecursively( - targetParent.resolve(versionRootContent.name), - overwrite = true - ) - else processingStrategies.first { - it.process(versionRootContent, targetParent.resolve(versionRootContent.name), null) - } - } - } - } + private fun versionsFrom(olderVersions: List) = + olderVersions.mapNotNull { versionDir -> + versionDir.listFiles { _, name -> name == VersioningConfiguration.VERSIONS_FILE }?.firstOrNull() + ?.let { file -> + val versionsContent = mapper.readValue(file) + Pair(versionsContent.version, versionDir) + }.also { + if (it == null) context.logger.warn("Failed to find versions file named ${VersioningConfiguration.VERSIONS_FILE} in $versionDir") + } } - } private data class Version( @JsonProperty("version") val version: String, ) - - companion object { - private const val OLDER_VERSIONS_DIR = "older" - private const val VERSIONS_FILE = "version.json" - } } diff --git a/plugins/versioning/src/main/kotlin/versioning/VersioningPlugin.kt b/plugins/versioning/src/main/kotlin/versioning/VersioningPlugin.kt index 9c20a128b87..05228c8d3b4 100644 --- a/plugins/versioning/src/main/kotlin/versioning/VersioningPlugin.kt +++ b/plugins/versioning/src/main/kotlin/versioning/VersioningPlugin.kt @@ -4,6 +4,8 @@ import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.plugability.configuration import org.jetbrains.dokka.templates.TemplatingPlugin +import versioning.DefaultPreviousDocumentationCopier +import versioning.VersionsNavigationAdder class VersioningPlugin : DokkaPlugin() { @@ -27,7 +29,10 @@ class VersioningPlugin : DokkaPlugin() { dokkaBase.immediateHtmlCommandConsumer providing ::ReplaceVersionCommandConsumer } val cssStyleInstaller by extending { - dokkaBase.htmlPreprocessors with MultiModuleStylesInstaller order { after(dokkaBase.assetsInstaller) } + dokkaBase.htmlPreprocessors providing ::MultiModuleStylesInstaller order { + after(dokkaBase.assetsInstaller) + before(dokkaBase.baseSearchbarDataInstaller) + } } val versionsDefaultOrdering by extending { versionsOrdering providing { ctx -> @@ -36,4 +41,12 @@ class VersioningPlugin : DokkaPlugin() { } ?: SemVerVersionOrdering() } } + val previousDocumentationCopier by extending { + dokkaBase.postActions providing ::DefaultPreviousDocumentationCopier applyIf { !delayTemplateSubstitution } + } + val defaultVersionsNavigationAdder by extending { + dokkaBase.htmlPreprocessors providing ::VersionsNavigationAdder order { + after(dokkaBase.assetsInstaller) + } + } } \ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/versioning/VersionsNavigationAdder.kt b/plugins/versioning/src/main/kotlin/versioning/VersionsNavigationAdder.kt new file mode 100644 index 00000000000..3c3b8d6aa91 --- /dev/null +++ b/plugins/versioning/src/main/kotlin/versioning/VersionsNavigationAdder.kt @@ -0,0 +1,57 @@ +package versioning + +import org.jetbrains.dokka.base.DokkaBase +import org.jetbrains.dokka.base.renderers.sourceSets +import org.jetbrains.dokka.base.templating.InsertTemplateExtra +import org.jetbrains.dokka.model.properties.PropertyContainer +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.configuration +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.transformers.pages.PageTransformer +import org.jetbrains.dokka.versioning.ReplaceVersionsCommand +import org.jetbrains.dokka.versioning.VersioningConfiguration +import org.jetbrains.dokka.versioning.VersioningPlugin + +class VersionsNavigationAdder(val context: DokkaContext) : PageTransformer { + private val configuration = configuration(context) + + override fun invoke(input: RootPageNode): RootPageNode { + val locationProvider = + context.plugin().querySingle { locationProviderFactory }.getLocationProvider(input) + + var isFirst = true + var cmd = ReplaceVersionsCommand() + return input.transformContentPagesTree { + if (isFirst || configuration?.onEachPage != false) { + isFirst = false + cmd = if (context.configuration.delayTemplateSubstitution) + cmd + else ReplaceVersionsCommand(location = locationProvider.resolve(it) ?: "") + + addOnPageCmd(it, cmd) + } else { + it + } + } + } + + private fun addOnPageCmd(contentPage: ContentPage, Cmd: ReplaceVersionsCommand) = + contentPage.modified(content = contentPage.content.let { + when (it) { + is ContentGroup -> it.copy( + listOf( + ContentGroup( + children = emptyList(), + dci = DCI(contentPage.dri, ContentKind.Main), + sourceSets = contentPage.sourceSets(), + style = emptySet(), + extra = PropertyContainer.withAll(InsertTemplateExtra(Cmd)) + ) + ) + it.children + ) + else -> it + } + }) +} \ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/versioning/VersionsNavigationCreator.kt b/plugins/versioning/src/main/kotlin/versioning/VersionsNavigationCreator.kt index 76653d47209..80533668567 100644 --- a/plugins/versioning/src/main/kotlin/versioning/VersionsNavigationCreator.kt +++ b/plugins/versioning/src/main/kotlin/versioning/VersionsNavigationCreator.kt @@ -5,6 +5,7 @@ import kotlinx.html.button import kotlinx.html.div import kotlinx.html.i import kotlinx.html.stream.appendHTML +import org.jetbrains.dokka.base.renderers.html.strike import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle @@ -13,7 +14,7 @@ import java.nio.file.Files.isDirectory import java.nio.file.Path interface VersionsNavigationCreator { - operator fun invoke(): String + operator fun invoke(location: String): String operator fun invoke(output: File): String } @@ -23,27 +24,47 @@ class HtmlVersionsNavigationCreator(val context: DokkaContext) : VersionsNavigat private val versionsOrdering by lazy { context.plugin().querySingle { versionsOrdering } } - override fun invoke(): String = - versioningHandler.currentVersion()?.let { invoke(it) }.orEmpty() + override fun invoke(location: String): String = + versioningHandler.currentVersion()?.let { invoke(it.resolve(location)) }.orEmpty() override fun invoke(output: File): String { val position = output.takeIf { it.isDirectory } ?: output.parentFile - return versioningHandler.getVersions() + return versioningHandler.versions .let { versions -> versionsOrdering.order(versions.keys.toList()).map { it to versions[it] } } .takeIf { it.isNotEmpty() } ?.let { versions -> StringBuilder().appendHTML().div(classes = "versions-dropdown") { + var relativePosition: String? = null + var activeVersion = "" button(classes = "versions-dropdown-button") { - versions.first { (_, versionLocation) -> versionLocation?.absolutePath == position.absolutePath } - .let { (version, _) -> - text(version) - } - i(classes = "fa fa-caret-down") + versions.minByOrNull { (_, versionLocation) -> + versionLocation?.let { position.toRelativeString(it).length } ?: 0xffffff + }?.let { (version, versionRoot) -> + relativePosition = versionRoot?.let { output.toRelativeString(it) } + activeVersion = version + text(version) + } } div(classes = "versions-dropdown-data") { versions.forEach { (version, path) -> - a(href = path?.resolve("index.html")?.toRelativeString(position)) { - text(version) + if (version == activeVersion) { + a(href = output.name) { text(version) } + } else { + var exist = false + val absolutePath = path?.resolve(relativePosition ?: "index.html")?.takeIf { + it.exists() || + versioningHandler.previousVersions[version]?.src?.resolve( + relativePosition ?: "index.html" + )?.exists() == true + }?.also { exist = true } + ?: path?.resolve("index.html") + + a(href = absolutePath?.toRelativeString(position)) { + if(exist) + text(version) + else + strike { text(version) } + } } } } diff --git a/plugins/versioning/src/main/kotlin/versioning/htmlPreprocessors.kt b/plugins/versioning/src/main/kotlin/versioning/htmlPreprocessors.kt index 5852ba9e82c..4c78a9b92af 100644 --- a/plugins/versioning/src/main/kotlin/versioning/htmlPreprocessors.kt +++ b/plugins/versioning/src/main/kotlin/versioning/htmlPreprocessors.kt @@ -3,17 +3,19 @@ package org.jetbrains.dokka.versioning import org.jetbrains.dokka.pages.RendererSpecificResourcePage import org.jetbrains.dokka.pages.RenderingStrategy import org.jetbrains.dokka.pages.RootPageNode +import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.pages.PageTransformer -object MultiModuleStylesInstaller : PageTransformer { +class MultiModuleStylesInstaller(private val dokkaContext: DokkaContext) : PageTransformer { private val stylesPages = listOf( "styles/multimodule.css", ) override fun invoke(input: RootPageNode): RootPageNode = - input.modified( - children = input.children + stylesPages.toRenderSpecificResourcePage() - ).transformContentPagesTree { + input.let { root -> + if (dokkaContext.configuration.delayTemplateSubstitution) root + else root.modified(children = input.children + stylesPages.toRenderSpecificResourcePage()) + }.transformContentPagesTree { it.modified( embeddedResources = it.embeddedResources + stylesPages ) diff --git a/plugins/versioning/src/main/resources/dokka/styles/multimodule.css b/plugins/versioning/src/main/resources/dokka/styles/multimodule.css index 4334d759ad1..b7b8f86f631 100644 --- a/plugins/versioning/src/main/resources/dokka/styles/multimodule.css +++ b/plugins/versioning/src/main/resources/dokka/styles/multimodule.css @@ -6,6 +6,23 @@ border: none; cursor: pointer; padding: 5px; + color: black; +} + +.versions-dropdown-button::after { + content: ''; + -webkit-mask: url("../images/arrow_down.svg") no-repeat 50% 50%; + mask: url("../images/arrow_down.svg") no-repeat 50% 50%; + mask-size: auto; + -webkit-mask-size: cover; + mask-size: cover; + background-color: black; + display: inline-block; + position: relative; + top: 2px; + transform: rotate(90deg); + width: 16px; + height: 16px; } .versions-dropdown-button:hover, @@ -23,9 +40,10 @@ .versions-dropdown-data a { padding: 5px; + padding-right: 18px; text-decoration: none; display: block; - color: black; + color: black !important; } .versions-dropdown-data a:hover {