aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/base/src/main/kotlin')
-rw-r--r--plugins/base/src/main/kotlin/DokkaBase.kt4
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt103
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt4
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/htmlFormatingUtils.kt37
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt38
-rw-r--r--plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt25
-rw-r--r--plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt167
-rw-r--r--plugins/base/src/main/kotlin/templating/ProjectNameSubstitutionCommand.kt3
-rw-r--r--plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt2
-rw-r--r--plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt31
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt18
11 files changed, 242 insertions, 190 deletions
diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt
index 4c3f35db..7e88d08f 100644
--- a/plugins/base/src/main/kotlin/DokkaBase.kt
+++ b/plugins/base/src/main/kotlin/DokkaBase.kt
@@ -209,10 +209,6 @@ class DokkaBase : DokkaPlugin() {
htmlPreprocessors providing ::NavigationPageInstaller order { after(rootCreator) }
}
- val navigationSearchInstaller by extending {
- htmlPreprocessors providing ::NavigationSearchInstaller order { after(rootCreator) }
- }
-
val scriptsInstaller by extending {
htmlPreprocessors providing ::ScriptsInstaller order { after(rootCreator) }
}
diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
index d63e8da6..31753332 100644
--- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
@@ -15,6 +15,7 @@ import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
import org.jetbrains.dokka.base.resolvers.local.DokkaBaseLocationProvider
import org.jetbrains.dokka.base.templating.InsertTemplateExtra
import org.jetbrains.dokka.base.templating.PathToRootSubstitutionCommand
+import org.jetbrains.dokka.base.templating.ProjectNameSubstitutionCommand
import org.jetbrains.dokka.base.templating.ResolveLinkCommand
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.DisplaySourceSet
@@ -603,22 +604,13 @@ open class HtmlRenderer(
override fun FlowContent.buildNavigation(page: PageNode) =
- div("navigation-wrapper") {
- id = "navigation-wrapper"
- div(classes = "breadcrumbs") {
- val path = locationProvider.ancestors(page).filterNot { it is RendererSpecificPage }.asReversed()
- if (path.isNotEmpty()) {
- buildNavigationElement(path.first(), page)
- path.drop(1).forEach { node ->
- text("/")
- buildNavigationElement(node, page)
- }
- }
- }
- div("pull-right d-flex") {
- filterButtons(page)
- div {
- id = "searchBar"
+ div(classes = "breadcrumbs") {
+ val path = locationProvider.ancestors(page).filterNot { it is RendererSpecificPage }.asReversed()
+ if (path.size > 1) {
+ buildNavigationElement(path.first(), page)
+ path.drop(1).forEach { node ->
+ text("/")
+ buildNavigationElement(node, page)
}
}
}
@@ -685,12 +677,15 @@ open class HtmlRenderer(
pageContext: ContentPage
) {
div("sample-container") {
- code(code.style.joinToString(" ") { it.toString().toLowerCase() }) {
- attributes["theme"] = "idea"
- pre {
+ val codeLang = "lang-" + code.language.ifEmpty { "kotlin" }
+ val stylesWithBlock = code.style + TextStyle.Block + codeLang
+ pre {
+ code(stylesWithBlock.joinToString(" ") { it.toString().toLowerCase() }) {
+ attributes["theme"] = "idea"
code.children.forEach { buildContentNode(it, pageContext) }
}
}
+ copyButton()
}
}
@@ -698,7 +693,9 @@ open class HtmlRenderer(
code: ContentCodeInline,
pageContext: ContentPage
) {
- code {
+ val codeLang = "lang-" + code.language.ifEmpty { "kotlin" }
+ val stylesWithBlock = code.style + codeLang
+ code(stylesWithBlock.joinToString(" ") { it.toString().toLowerCase() }) {
code.children.forEach { buildContentNode(it, pageContext) }
}
}
@@ -716,7 +713,7 @@ open class HtmlRenderer(
}
unappliedStyles.isNotEmpty() -> {
val styleToApply = unappliedStyles.first()
- applyStyle(styleToApply){
+ applyStyle(styleToApply) {
buildText(textNode, unappliedStyles - styleToApply)
}
}
@@ -726,12 +723,13 @@ open class HtmlRenderer(
}
}
- private inline fun FlowContent.applyStyle(styleToApply: Style, crossinline body: FlowContent.() -> Unit){
- when(styleToApply){
+ private inline fun FlowContent.applyStyle(styleToApply: Style, crossinline body: FlowContent.() -> Unit) {
+ when (styleToApply) {
TextStyle.Bold -> b { body() }
TextStyle.Italic -> i { body() }
TextStyle.Strikethrough -> strike { body() }
TextStyle.Strong -> strong { body() }
+ is TokenStyle -> span("token " + styleToApply.toString().toLowerCase()) { body() }
else -> body()
}
}
@@ -741,8 +739,6 @@ open class HtmlRenderer(
super.render(root)
}
- private fun PageNode.root(path: String) = locationProvider.pathToRoot(this) + path
-
override fun buildPage(page: ContentPage, content: (FlowContent, ContentPage) -> Unit): String =
buildHtml(page, page.embeddedResources) {
div("main-content") {
@@ -762,11 +758,19 @@ open class HtmlRenderer(
meta(name = "viewport", content = "width=device-width, initial-scale=1", charset = "UTF-8")
title(page.name)
templateCommand(PathToRootSubstitutionCommand("###", default = pathToRoot)) {
- link(href = page.root("###images/logo-icon.svg"), rel = "icon", type = "image/svg")
+ link(href = "###images/logo-icon.svg", rel = "icon", type = "image/svg")
}
templateCommand(PathToRootSubstitutionCommand("###", default = pathToRoot)) {
script { unsafe { +"""var pathToRoot = "###";""" } }
}
+ // This script doesn't need to be there but it is nice to have since app in dark mode doesn't 'blink' (class is added before it is rendered)
+ script { unsafe { +"""
+ const storage = localStorage.getItem("dokka-dark-mode")
+ const savedDarkMode = storage ? JSON.parse(storage) : false
+ if(savedDarkMode === true){
+ document.getElementsByTagName("html")[0].classList.add("theme-dark")
+ }
+ """.trimIndent() } }
resources.forEach {
when {
it.substringBefore('?').substringAfterLast('.') == "css" ->
@@ -803,24 +807,41 @@ open class HtmlRenderer(
}
}
body {
- div {
- id = "container"
+ div("navigation-wrapper") {
+ id = "navigation-wrapper"
div {
- id = "leftColumn"
+ id = "leftToggler"
+ span("icon-toggler")
+ }
+ div("library-name") {
clickableLogo(page, pathToRoot)
+ }
+ context.configuration.moduleVersion?.let { moduleVersion ->
+ div { text(moduleVersion) }
+ }
+ div("pull-right d-flex") {
+ filterButtons(page)
+ button {
+ id = "theme-toggle-button"
+ span {
+ id = "theme-toggle"
+ }
+ }
div {
- id = "paneSearch"
+ id = "searchBar"
}
+ }
+ }
+ div {
+ id = "container"
+ div {
+ id = "leftColumn"
div {
id = "sideMenu"
}
}
div {
id = "main"
- div {
- id = "leftToggler"
- span("icon-toggler")
- }
templateCommand(PathToRootSubstitutionCommand("###", default = pathToRoot)) {
script(type = ScriptType.textJavaScript, src = "###scripts/main.js") {}
}
@@ -857,15 +878,17 @@ open class HtmlRenderer(
templateCommand(PathToRootSubstitutionCommand(pattern = "###", default = pathToRoot)) {
a {
href = "###index.html"
- div {
- id = "logo"
+ templateCommand(ProjectNameSubstitutionCommand(pattern = "@@@", default = context.configuration.moduleName)) {
+ span {
+ text("@@@")
+ }
}
}
}
- } else a {
- href = pathToRoot + "index.html"
- div {
- id = "logo"
+ } else {
+ a {
+ href = pathToRoot + "index.html"
+ text(context.configuration.moduleName)
}
}
}
diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt
index e2953d46..e0b20f01 100644
--- a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt
@@ -40,13 +40,13 @@ class NavigationPage(val root: NavigationNode, val moduleName: String, val conte
id = navId
attributes["pageId"] = "${moduleName}::${node.pageId}"
div("overview") {
- buildLink(node.dri, node.sourceSets.toList()) { buildBreakableText(node.name) }
if (node.children.isNotEmpty()) {
- span("navButton pull-right") {
+ span("navButton") {
onClick = """document.getElementById("$navId").classList.toggle("hidden");"""
span("navButtonContent")
}
}
+ buildLink(node.dri, node.sourceSets.toList()) { buildBreakableText(node.name) }
}
node.children.withIndex().forEach { (n, p) -> visit(p, "$navId-$n", renderer) }
}
diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlFormatingUtils.kt b/plugins/base/src/main/kotlin/renderers/html/htmlFormatingUtils.kt
index b9eab293..c77a6e94 100644
--- a/plugins/base/src/main/kotlin/renderers/html/htmlFormatingUtils.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/htmlFormatingUtils.kt
@@ -3,7 +3,7 @@ package org.jetbrains.dokka.base.renderers.html
import kotlinx.html.FlowContent
import kotlinx.html.span
-fun FlowContent.buildTextBreakableAfterCapitalLetters(name: String) {
+fun FlowContent.buildTextBreakableAfterCapitalLetters(name: String, hasLastElement: Boolean = false) {
if (name.contains(" ")) {
val withOutSpaces = name.split(" ")
withOutSpaces.dropLast(1).forEach {
@@ -12,8 +12,8 @@ fun FlowContent.buildTextBreakableAfterCapitalLetters(name: String) {
}
buildBreakableText(withOutSpaces.last())
} else {
- val content = name.replace(Regex("(?!^)([A-Z])"), " $1").split(" ")
- joinToHtml(content) {
+ val content = name.replace(Regex("(?<=[a-z])([A-Z])"), " $1").split(" ")
+ joinToHtml(content, hasLastElement) {
it
}
}
@@ -22,32 +22,35 @@ fun FlowContent.buildTextBreakableAfterCapitalLetters(name: String) {
fun FlowContent.buildBreakableDotSeparatedHtml(name: String) {
val phrases = name.split(".")
phrases.forEachIndexed { i, e ->
+ val elementWithOptionalDot = e.takeIf { i == phrases.lastIndex } ?: "$e."
if (e.length > 10) {
- buildBreakableText(e)
+ buildTextBreakableAfterCapitalLetters(elementWithOptionalDot, hasLastElement = i == phrases.lastIndex)
} else {
- val elementWithOptionalDot =
- if (i != phrases.lastIndex) {
- "$e."
- } else {
- e
- }
- buildBreakableHtmlElement(elementWithOptionalDot)
+ buildBreakableHtmlElement(elementWithOptionalDot, i == phrases.lastIndex)
}
}
}
-private fun FlowContent.joinToHtml(elements: List<String>, onEach: (String) -> String) {
+private fun FlowContent.joinToHtml(elements: List<String>, hasLastElement: Boolean = true, onEach: (String) -> String) {
elements.dropLast(1).forEach {
buildBreakableHtmlElement(onEach(it))
}
- span {
- buildBreakableHtmlElement(elements.last(), last = true)
+ elements.takeIf { it.isNotEmpty() && it.last().isNotEmpty() }?.let {
+ if (hasLastElement) {
+ span {
+ buildBreakableHtmlElement(it.last(), last = true)
+ }
+ } else {
+ buildBreakableHtmlElement(it.last(), last = false)
+ }
}
}
private fun FlowContent.buildBreakableHtmlElement(element: String, last: Boolean = false) {
- span {
- +element
+ element.takeIf { it.isNotBlank() }?.let {
+ span {
+ +it
+ }
}
if (!last) {
wbr { }
@@ -56,4 +59,4 @@ private fun FlowContent.buildBreakableHtmlElement(element: String, last: Boolean
fun FlowContent.buildBreakableText(name: String) =
if (name.contains(".")) buildBreakableDotSeparatedHtml(name)
- else buildTextBreakableAfterCapitalLetters(name) \ No newline at end of file
+ else buildTextBreakableAfterCapitalLetters(name, hasLastElement = true) \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
index b6099e21..347e16bf 100644
--- a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
@@ -49,37 +49,6 @@ abstract class NavigationDataProvider {
}
}
-open class NavigationSearchInstaller(val context: DokkaContext) : NavigationDataProvider(), PageTransformer {
- private val mapper = jacksonObjectMapper()
-
- open fun createSearchRecordFromNode(node: NavigationNode, location: String): SearchRecord =
- SearchRecord(name = node.name, location = location)
-
- override fun invoke(input: RootPageNode): RootPageNode {
- val page = RendererSpecificResourcePage(
- name = "scripts/navigation-pane.json",
- children = emptyList(),
- strategy = RenderingStrategy.DriLocationResolvableWrite { resolver ->
- val content = navigableChildren(input).withDescendants().map {
- createSearchRecordFromNode(it, resolveLocation(resolver, it.dri, it.sourceSets).orEmpty())
- }
- if (context.configuration.delayTemplateSubstitution) {
- mapper.writeValueAsString(AddToSearch(context.configuration.moduleName, content.toList()))
- } else {
- mapper.writeValueAsString(content)
- }
- })
-
- return input.modified(children = input.children + page)
- }
-
- private fun resolveLocation(locationResolver: DriResolver, dri: DRI, sourceSets: Set<DisplaySourceSet>): String? =
- locationResolver(dri, sourceSets).also { location ->
- if (location.isNullOrBlank()) context.logger.warn("Cannot resolve path for $dri and sourceSets: ${sourceSets.joinToString { it.name }}")
- }
-
-}
-
open class NavigationPageInstaller(val context: DokkaContext) : NavigationDataProvider(), PageTransformer {
override fun invoke(input: RootPageNode): RootPageNode =
@@ -118,6 +87,7 @@ class ScriptsInstaller(private val dokkaContext: DokkaContext) : PageTransformer
"scripts/navigation-loader.js",
"scripts/platform-content-handler.js",
"scripts/main.js",
+ "scripts/prism.js"
)
override fun invoke(input: RootPageNode): RootPageNode =
@@ -134,9 +104,9 @@ class ScriptsInstaller(private val dokkaContext: DokkaContext) : PageTransformer
class StylesInstaller(private val dokkaContext: DokkaContext) : PageTransformer {
private val stylesPages = listOf(
"styles/style.css",
- "styles/logo-styles.css",
"styles/jetbrains-mono.css",
- "styles/main.css"
+ "styles/main.css",
+ "styles/prism.css"
)
override fun invoke(input: RootPageNode): RootPageNode =
@@ -153,13 +123,13 @@ class StylesInstaller(private val dokkaContext: DokkaContext) : PageTransformer
object AssetsInstaller : PageTransformer {
private val imagesPages = listOf(
"images/arrow_down.svg",
- "images/docs_logo.svg",
"images/logo-icon.svg",
"images/go-to-top-icon.svg",
"images/footer-go-to-link.svg",
"images/anchor-copy-button.svg",
"images/copy-icon.svg",
"images/copy-successful-icon.svg",
+ "images/theme-toggle.svg",
)
override fun invoke(input: RootPageNode) = input.modified(
diff --git a/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt b/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt
index d17fa276..94af96e2 100644
--- a/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt
+++ b/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt
@@ -8,7 +8,6 @@ import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.drisOfAllNestedBounds
import org.jetbrains.dokka.model.AnnotationTarget
-import org.jetbrains.dokka.model.doc.DocumentationNode
interface JvmSignatureUtils {
@@ -80,21 +79,22 @@ interface JvmSignatureUtils {
when (renderAtStrategy) {
is All, is OnlyOnce -> {
- text("@")
when(a.scope) {
- Annotations.AnnotationScope.GETTER -> text("get:")
- Annotations.AnnotationScope.SETTER -> text("set:")
+ Annotations.AnnotationScope.GETTER -> text("@get:", styles = mainStyles + TokenStyle.Annotation)
+ Annotations.AnnotationScope.SETTER -> text("@set:", styles = mainStyles + TokenStyle.Annotation)
+ else -> text("@", styles = mainStyles + TokenStyle.Annotation)
}
+ link(a.dri.classNames!!, a.dri, styles = mainStyles + TokenStyle.Annotation)
}
- is Never -> Unit
+ is Never -> link(a.dri.classNames!!, a.dri)
}
- link(a.dri.classNames!!, a.dri)
val isNoWrappedBrackets = a.params.entries.isEmpty() && renderAtStrategy is OnlyOnce
listParams(
a.params.entries,
if (isNoWrappedBrackets) null else Pair('(', ')')
) {
- text(it.key + " = ")
+ text(it.key)
+ text(" = ", styles = mainStyles + TokenStyle.Operator)
when (renderAtStrategy) {
is All -> All
is Never, is OnlyOnce -> Never
@@ -116,8 +116,9 @@ interface JvmSignatureUtils {
}
is EnumValue -> link(a.enumName, a.enumDri)
is ClassValue -> link(a.className + classExtension, a.classDRI)
- is StringValue -> group(styles = setOf(TextStyle.Breakable)) { text( "\"${a.text()}\"") }
- is LiteralValue -> group(styles = setOf(TextStyle.Breakable)) { text(a.text()) }
+ is StringValue -> group(styles = setOf(TextStyle.Breakable)) { stringLiteral( "\"${a.text()}\"") }
+ is BooleanValue -> group(styles = setOf(TextStyle.Breakable)) { booleanLiteral(a.value) }
+ is LiteralValue -> group(styles = setOf(TextStyle.Breakable)) { constant(a.text()) }
}
private fun<T> PageContentBuilder.DocumentableContentBuilder.listParams(
@@ -125,14 +126,14 @@ interface JvmSignatureUtils {
listBrackets: Pair<Char, Char>?,
outFn: PageContentBuilder.DocumentableContentBuilder.(T) -> Unit
) {
- listBrackets?.let{ text(it.first.toString()) }
+ listBrackets?.let{ punctuation(it.first.toString()) }
params.forEachIndexed { i, it ->
group(styles = setOf(TextStyle.BreakableAfter)) {
this.outFn(it)
- if (i != params.size - 1) text(", ")
+ if (i != params.size - 1) punctuation(", ")
}
}
- listBrackets?.let{ text(it.second.toString()) }
+ listBrackets?.let{ punctuation(it.second.toString()) }
}
fun PageContentBuilder.DocumentableContentBuilder.annotationsBlockWithIgnored(
diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt
index e5f0ae97..8db37012 100644
--- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt
+++ b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt
@@ -15,6 +15,7 @@ import org.jetbrains.dokka.model.properties.WithExtraProperties
import org.jetbrains.dokka.pages.ContentKind
import org.jetbrains.dokka.pages.ContentNode
import org.jetbrains.dokka.pages.TextStyle
+import org.jetbrains.dokka.pages.TokenStyle
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.plugin
import org.jetbrains.dokka.plugability.querySingle
@@ -60,7 +61,7 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
it !in ignoredExtraModifiers || entry.key.analysisPlatform in (platformSpecificModifiers[it]
?: emptySet())
}
- }
+ }, styles = mainStyles + TokenStyle.Keyword
) {
it.toSignatureString()
}
@@ -78,8 +79,15 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
annotationsBlock(e)
link(e.name, e.dri, styles = emptySet())
e.extra[ConstructorValues]?.let { constructorValues ->
- constructorValues.values[it]
- text(constructorValues.values[it]?.joinToString(prefix = "(", postfix = ")") ?: "")
+ constructorValues.values[it]?.let { values ->
+ punctuation("(")
+ list(
+ elements = values,
+ separator = ", ",
+ separatorStyles = mainStyles + TokenStyle.Punctuation,
+ ) { highlightValue(it) }
+ punctuation(")")
+ }
}
}
}
@@ -93,9 +101,9 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
?: emptySet()),
sourceSets = setOf(sourceSet)
) {
- text("typealias ")
+ keyword("typealias ")
link(c.name.orEmpty(), c.dri)
- text(" = ")
+ operator(" = ")
signatureForProjection(aliasedType)
}
@@ -118,10 +126,9 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
sourceSets = setOf(sourceSet)
) {
annotationsBlock(c)
- text(c.visibility[sourceSet]?.takeIf { it !in ignoredVisibilities }?.name?.let { "$it " } ?: "")
+ c.visibility[sourceSet]?.takeIf { it !in ignoredVisibilities }?.name?.let { keyword("$it ") }
if (c is DClass) {
- text(
- if (c.modifier[sourceSet] !in ignoredModifiers)
+ val modifier = if (c.modifier[sourceSet] !in ignoredModifiers)
when {
c.extra[AdditionalModifiers]?.content?.get(sourceSet)?.contains(ExtraModifiers.KotlinOnlyModifiers.Data) == true -> ""
c.modifier[sourceSet] is JavaModifier.Empty -> "${KotlinModifier.Open.name} "
@@ -129,33 +136,35 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
}
else
""
- )
+ modifier.takeIf { it.isNotEmpty() }?.let { keyword(it) }
}
when (c) {
is DClass -> {
processExtraModifiers(c)
- text("class ")
+ keyword("class ")
}
is DInterface -> {
processExtraModifiers(c)
- text("interface ")
+ keyword("interface ")
}
is DEnum -> {
processExtraModifiers(c)
- text("enum ")
+ keyword("enum ")
}
is DObject -> {
processExtraModifiers(c)
- text("object ")
+ keyword("object ")
}
is DAnnotation -> {
processExtraModifiers(c)
- text("annotation class ")
+ keyword("annotation class ")
}
}
link(c.name!!, c.dri)
if (c is WithGenerics) {
- list(c.generics, prefix = "<", suffix = ">") {
+ list(c.generics, prefix = "<", suffix = ">",
+ separatorStyles = mainStyles + TokenStyle.Punctuation,
+ surroundingCharactersStyle = mainStyles + TokenStyle.Operator) {
annotationsInline(it)
+buildSignature(it)
}
@@ -166,18 +175,20 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
if (pConstructor.annotations().values.any { it.isNotEmpty() }) {
text(nbsp.toString())
annotationsInline(pConstructor)
- text("constructor")
+ keyword("constructor")
}
list(
- pConstructor.parameters,
- "(",
- ")",
- ", ",
- pConstructor.sourceSets.toSet()
+ elements = pConstructor.parameters,
+ prefix = "(",
+ suffix = ")",
+ separator = ", ",
+ separatorStyles = mainStyles + TokenStyle.Punctuation,
+ surroundingCharactersStyle = mainStyles + TokenStyle.Punctuation,
+ sourceSets = pConstructor.sourceSets.toSet()
) {
annotationsInline(it)
- text(it.name ?: "", styles = mainStyles.plus(TextStyle.Bold))
- text(": ")
+ text(it.name.orEmpty())
+ operator(": ")
signatureForProjection(it.type)
}
}
@@ -186,7 +197,9 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
c.supertypes.filter { it.key == sourceSet }.map { (s, typeConstructors) ->
list(typeConstructors, prefix = " : ", sourceSets = setOf(s)) {
link(it.typeConstructor.dri.sureClassNames, it.typeConstructor.dri, sourceSets = setOf(s))
- list(it.typeConstructor.projections, prefix = "<", suffix = "> ") {
+ list(it.typeConstructor.projections, prefix = "<", suffix = "> ",
+ separatorStyles = mainStyles + TokenStyle.Punctuation,
+ surroundingCharactersStyle = mainStyles + TokenStyle.Operator) {
signatureForProjection(it)
}
}
@@ -203,31 +216,42 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
sourceSets = setOf(it)
) {
annotationsBlock(p)
- text(p.visibility[it].takeIf { it !in ignoredVisibilities }?.name?.let { "$it " } ?: "")
- text(
- p.modifier[it].takeIf { it !in ignoredModifiers }?.let {
+ p.visibility[it].takeIf { it !in ignoredVisibilities }?.name?.let { keyword("$it ") }
+ p.modifier[it].takeIf { it !in ignoredModifiers }?.let {
if (it is JavaModifier.Empty) KotlinModifier.Open else it
- }?.name?.let { "$it " } ?: ""
- )
- text(p.modifiers()[it]?.toSignatureString() ?: "")
- p.setter?.let { text("var ") } ?: text("val ")
- list(p.generics, prefix = "<", suffix = "> ") {
+ }?.name?.let { keyword("$it ") }
+ p.modifiers()[it]?.toSignatureString()?.let { keyword(it) }
+ p.setter?.let { keyword("var ") } ?: keyword("val ")
+ list(p.generics, prefix = "<", suffix = "> ",
+ separatorStyles = mainStyles + TokenStyle.Punctuation,
+ surroundingCharactersStyle = mainStyles + TokenStyle.Operator) {
annotationsInline(it)
+buildSignature(it)
}
p.receiver?.also {
signatureForProjection(it.type)
- text(".")
+ punctuation(".")
}
link(p.name, p.dri)
- text(": ")
+ operator(": ")
signatureForProjection(p.type)
p.extra[DefaultValue]?.run {
- text(" = $value")
+ operator(" = ")
+ highlightValue(value)
}
}
}
+ private fun PageContentBuilder.DocumentableContentBuilder.highlightValue(expr: Expression) = when (expr) {
+ is IntegerConstant -> constant(expr.value.toString())
+ is FloatConstant -> constant(expr.value.toString() + "f")
+ is DoubleConstant -> constant(expr.value.toString())
+ is BooleanConstant -> booleanLiteral(expr.value)
+ is StringConstant -> stringLiteral("\"${expr.value}\"")
+ is ComplexExpression -> text(expr.value)
+ else -> Unit
+ }
+
private fun functionSignature(f: DFunction) =
f.sourceSets.map {
contentBuilder.contentFor(
@@ -237,37 +261,40 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
sourceSets = setOf(it)
) {
annotationsBlock(f)
- text(f.visibility[it]?.takeIf { it !in ignoredVisibilities }?.name?.let { "$it " } ?: "")
- text(f.modifier[it]?.takeIf { it !in ignoredModifiers }?.let {
+ f.visibility[it]?.takeIf { it !in ignoredVisibilities }?.name?.let { keyword("$it ") }
+ f.modifier[it]?.takeIf { it !in ignoredModifiers }?.let {
if (it is JavaModifier.Empty) KotlinModifier.Open else it
- }?.name?.let { "$it " } ?: ""
- )
- text(f.modifiers()[it]?.toSignatureString() ?: "")
- text("fun ")
+ }?.name?.let { keyword("$it ") }
+ f.modifiers()[it]?.toSignatureString()?.let { keyword(it) }
+ keyword("fun ")
val usedGenerics = if (f.isConstructor) f.generics.filter { f uses it } else f.generics
- list(usedGenerics, prefix = "<", suffix = "> ") {
+ list(usedGenerics, prefix = "<", suffix = "> ",
+ separatorStyles = mainStyles + TokenStyle.Punctuation,
+ surroundingCharactersStyle = mainStyles + TokenStyle.Operator) {
annotationsInline(it)
+buildSignature(it)
}
f.receiver?.also {
signatureForProjection(it.type)
- text(".")
+ punctuation(".")
}
- link(f.name, f.dri)
- text("(")
- list(f.parameters) {
+ link(f.name, f.dri, styles = mainStyles + TokenStyle.Function)
+ punctuation("(")
+ list(f.parameters,
+ separatorStyles = mainStyles + TokenStyle.Punctuation) {
annotationsInline(it)
processExtraModifiers(it)
text(it.name!!)
- text(": ")
+ operator(": ")
signatureForProjection(it.type)
it.extra[DefaultValue]?.run {
- text(" = $value")
+ operator(" = ")
+ highlightValue(value)
}
}
- text(")")
+ punctuation(")")
if (f.documentReturnType()) {
- text(": ")
+ operator(": ")
signatureForProjection(f.type)
}
}
@@ -291,11 +318,11 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
sourceSets = platforms.toSet()
) {
annotationsBlock(t)
- text(t.visibility[it]?.takeIf { it !in ignoredVisibilities }?.name?.let { "$it " } ?: "")
+ t.visibility[it]?.takeIf { it !in ignoredVisibilities }?.name?.let { keyword("$it ") }
processExtraModifiers(t)
- text("typealias ")
+ keyword("typealias ")
signatureForProjection(t.type)
- text(" = ")
+ operator(" = ")
signatureForTypealiasTarget(t, type)
}
}
@@ -306,7 +333,8 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
t.sourceSets.map {
contentBuilder.contentFor(t, styles = t.stylesIfDeprecated(it), sourceSets = setOf(it)) {
signatureForProjection(t.variantTypeParameter.withDri(t.dri.withTargetToDeclaration()))
- list(t.nontrivialBounds, prefix = " : ") { bound ->
+ list(t.nontrivialBounds, prefix = " : ",
+ surroundingCharactersStyle = mainStyles + TokenStyle.Operator) { bound ->
signatureForProjection(bound)
}
}
@@ -338,24 +366,29 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
val linkText = if (showFullyQualifiedName && p.dri.packageName != null) {
"${p.dri.packageName}.${p.dri.classNames.orEmpty()}"
} else p.dri.classNames.orEmpty()
- if (p.presentableName != null) text(p.presentableName + ": ")
+ if (p.presentableName != null) {
+ text(p.presentableName!!)
+ operator(": ")
+ }
annotationsInline(p)
link(linkText, p.dri)
- list(p.projections, prefix = "<", suffix = ">") {
+ list(p.projections, prefix = "<", suffix = ">",
+ separatorStyles = mainStyles + TokenStyle.Punctuation,
+ surroundingCharactersStyle = mainStyles + TokenStyle.Operator) {
signatureForProjection(it, showFullyQualifiedName)
}
}
is Variance<*> -> group(styles = emptySet()) {
- text("$p ".takeIf { it.isNotBlank() } ?: "")
+ keyword("$p ".takeIf { it.isNotBlank() } ?: "")
signatureForProjection(p.inner, showFullyQualifiedName)
}
- is Star -> text("*")
+ is Star -> operator("*")
is Nullable -> group(styles = emptySet()) {
signatureForProjection(p.inner, showFullyQualifiedName)
- text("?")
+ operator("?")
}
is TypeAliased -> signatureForProjection(p.typeAlias)
@@ -373,12 +406,15 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
private fun funType(dri: DRI, sourceSets: Set<DokkaSourceSet>, type: FunctionalTypeConstructor) =
contentBuilder.contentFor(dri, sourceSets, ContentKind.Main) {
- if (type.presentableName != null) text(type.presentableName + ": ")
- if (type.isSuspendable) text("suspend ")
+ if (type.presentableName != null) {
+ text(type.presentableName!!)
+ operator(": ")
+ }
+ if (type.isSuspendable) keyword("suspend ")
if (type.isExtensionFunction) {
signatureForProjection(type.projections.first())
- text(".")
+ punctuation(".")
}
val args = if (type.isExtensionFunction)
@@ -386,12 +422,13 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
else
type.projections
- text("(")
+ punctuation("(")
args.subList(0, args.size - 1).forEachIndexed { i, arg ->
signatureForProjection(arg)
- if (i < args.size - 2) text(", ")
+ if (i < args.size - 2) punctuation(", ")
}
- text(") -> ")
+ punctuation(")")
+ operator(" -> ")
signatureForProjection(args.last())
}
}
diff --git a/plugins/base/src/main/kotlin/templating/ProjectNameSubstitutionCommand.kt b/plugins/base/src/main/kotlin/templating/ProjectNameSubstitutionCommand.kt
new file mode 100644
index 00000000..fa4ffd7b
--- /dev/null
+++ b/plugins/base/src/main/kotlin/templating/ProjectNameSubstitutionCommand.kt
@@ -0,0 +1,3 @@
+package org.jetbrains.dokka.base.templating
+
+data class ProjectNameSubstitutionCommand(override val pattern: String, val default: String): SubstitutionCommand() \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt b/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt
index a02f1b53..8c2e1c99 100644
--- a/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt
+++ b/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt
@@ -108,7 +108,7 @@ open class DocTagToContentConverter : CommentsToContentConverter {
is BlockQuote, is Pre, is CodeBlock -> listOf(
ContentCodeBlock(
buildChildren(docTag),
- "",
+ docTag.params.getOrDefault("lang", ""),
dci,
sourceSets.toDisplaySourceSets(),
styles
diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
index 3ff8ffc3..d986056c 100644
--- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
@@ -1,6 +1,7 @@
package org.jetbrains.dokka.base.translators.descriptors
import com.intellij.psi.PsiNamedElement
+import com.intellij.psi.util.PsiLiteralUtil.*
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.runBlocking
@@ -29,6 +30,8 @@ import org.jetbrains.dokka.transformers.sources.AsyncSourceToDocumentableTransla
import org.jetbrains.dokka.utilities.DokkaLogger
import org.jetbrains.dokka.utilities.parallelMap
import org.jetbrains.dokka.utilities.parallelMapNotNull
+import org.jetbrains.kotlin.KtNodeTypes
+import org.jetbrains.dokka.model.BooleanConstant
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.isBuiltinExtensionFunctionalType
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
@@ -38,7 +41,6 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
-import org.jetbrains.kotlin.idea.core.getDirectlyOverriddenDeclarations
import org.jetbrains.kotlin.idea.kdoc.findKDoc
import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
@@ -53,7 +55,6 @@ import org.jetbrains.kotlin.resolve.constants.KClassValue.Value.LocalClass
import org.jetbrains.kotlin.resolve.constants.KClassValue.Value.NormalClass
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
-import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeUniqueAsSequence
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
@@ -1011,25 +1012,33 @@ private class DokkaDescriptorVisitor(
if (kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) this
else overriddenDescriptors.first().getConcreteDescriptor() as T
- private fun ValueParameterDescriptor.getDefaultValue(): String? =
- (source as? KotlinSourceElement)?.psi?.children?.find { it is KtExpression }?.text
+ private fun ValueParameterDescriptor.getDefaultValue(): Expression? =
+ ((source as? KotlinSourceElement)?.psi as? KtParameter)?.defaultValue?.toDefaultValueExpression()
- private suspend fun PropertyDescriptor.getDefaultValue(): String? =
- (source as? KotlinSourceElement)?.psi?.children?.find { it is KtConstantExpression }?.text
+ private suspend fun PropertyDescriptor.getDefaultValue(): Expression? =
+ (source as? KotlinSourceElement)?.psi?.children?.filterIsInstance<KtConstantExpression>()?.firstOrNull()
+ ?.toDefaultValueExpression()
private suspend fun ClassDescriptor.getAppliedConstructorParameters() =
(source as PsiSourceElement).psi?.children?.flatMap {
- it.safeAs<KtInitializerList>()?.initializersAsText().orEmpty()
+ it.safeAs<KtInitializerList>()?.initializersAsExpression().orEmpty()
}.orEmpty()
- private suspend fun KtInitializerList.initializersAsText() =
+ private suspend fun KtInitializerList.initializersAsExpression() =
initializers.firstIsInstanceOrNull<KtCallElement>()
?.getValueArgumentsInParentheses()
- ?.flatMap { it.childrenAsText() }
+ ?.map { it.getArgumentExpression()?.toDefaultValueExpression() ?: ComplexExpression("") }
.orEmpty()
- private fun ValueArgument.childrenAsText() =
- this.safeAs<KtValueArgument>()?.children?.map { it.text }.orEmpty()
+ private fun KtExpression.toDefaultValueExpression(): Expression? = when (node?.elementType) {
+ KtNodeTypes.INTEGER_CONSTANT -> parseLong(node?.text)?.let { IntegerConstant(it) }
+ KtNodeTypes.FLOAT_CONSTANT -> if (node?.text?.toLowerCase()?.endsWith('f') == true)
+ parseFloat(node?.text)?.let { FloatConstant(it) }
+ else parseDouble(node?.text)?.let { DoubleConstant(it) }
+ KtNodeTypes.BOOLEAN_CONSTANT -> BooleanConstant(node?.text == "true")
+ KtNodeTypes.STRING_TEMPLATE -> StringConstant(node.findChildByType(KtNodeTypes.LITERAL_STRING_TEMPLATE_ENTRY)?.text.orEmpty())
+ else -> node?.text?.let { ComplexExpression(it) }
+ }
private data class ClassInfo(val ancestry: List<AncestryLevel>, val docs: SourceSetDependent<DocumentationNode>) {
val supertypes: List<TypeConstructorWithKind>
diff --git a/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt b/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt
index 2db55d45..f9bc7e26 100644
--- a/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt
+++ b/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt
@@ -122,6 +122,13 @@ open class PageContentBuilder(
header(1, text, sourceSets = sourceSets, styles = styles, extra = extra, block = block)
}
+ fun constant(text: String) = text(text, styles = mainStyles + TokenStyle.Constant)
+ fun keyword(text: String) = text(text, styles = mainStyles + TokenStyle.Keyword)
+ fun stringLiteral(text: String) = text(text, styles = mainStyles + TokenStyle.String)
+ fun booleanLiteral(value: Boolean) = text(value.toString(), styles = mainStyles + TokenStyle.Boolean)
+ fun punctuation(text: String) = text(text, styles = mainStyles + TokenStyle.Punctuation)
+ fun operator(text: String) = text(text, styles = mainStyles + TokenStyle.Operator)
+
fun text(
text: String,
kind: Kind = ContentKind.Main,
@@ -194,16 +201,18 @@ open class PageContentBuilder(
suffix: String = "",
separator: String = ", ",
sourceSets: Set<DokkaSourceSet> = mainSourcesetData, // TODO: children should be aware of this platform data
+ surroundingCharactersStyle: Set<Style> = mainStyles,
+ separatorStyles: Set<Style> = mainStyles,
operation: DocumentableContentBuilder.(T) -> Unit
) {
if (elements.isNotEmpty()) {
- if (prefix.isNotEmpty()) text(prefix, sourceSets = sourceSets)
+ if (prefix.isNotEmpty()) text(prefix, sourceSets = sourceSets, styles = surroundingCharactersStyle)
elements.dropLast(1).forEach {
operation(it)
- text(separator, sourceSets = sourceSets)
+ text(separator, sourceSets = sourceSets, styles = separatorStyles)
}
operation(elements.last())
- if (suffix.isNotEmpty()) text(suffix, sourceSets = sourceSets)
+ if (suffix.isNotEmpty()) text(suffix, sourceSets = sourceSets, styles = surroundingCharactersStyle)
}
}
@@ -404,11 +413,12 @@ open class PageContentBuilder(
fun <T> sourceSetDependentText(
value: SourceSetDependent<T>,
sourceSets: Set<DokkaSourceSet> = value.keys,
+ styles: Set<Style> = mainStyles,
transform: (T) -> String
) = value.entries.filter { it.key in sourceSets }.mapNotNull { (p, v) ->
transform(v).takeIf { it.isNotBlank() }?.let { it to p }
}.groupBy({ it.first }) { it.second }.forEach {
- text(it.key, sourceSets = it.value.toSet())
+ text(it.key, sourceSets = it.value.toSet(), styles = styles)
}
}