diff options
author | Ignat Beresnev <ignat@beresnev.me> | 2022-01-27 12:56:27 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-27 12:56:27 +0300 |
commit | e0a10c24ea7e623137f2ab21522ed0f84bf59814 (patch) | |
tree | c863973a41efccb4ad34858c88b885e5370b2dbd /plugins/base/src/main | |
parent | 7c44db1ef0075e2b80a4723e0747bbf57c32e775 (diff) | |
download | dokka-e0a10c24ea7e623137f2ab21522ed0f84bf59814.tar.gz dokka-e0a10c24ea7e623137f2ab21522ed0f84bf59814.tar.bz2 dokka-e0a10c24ea7e623137f2ab21522ed0f84bf59814.zip |
KT-50292 - Implement vertical alignment of parameters (#2309)
* Implement vertical alignment (wrapping) of parameters for kt
* Add tests for params wrapping and extend matchers to check for classes
* Add distinguishable parameters block to kotlinAsJava, extract common logic
* Create a separate Kind for symbol function parameters
Diffstat (limited to 'plugins/base/src/main')
4 files changed, 99 insertions, 27 deletions
diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt index 8d258461..2906e8f2 100644 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -98,6 +98,21 @@ open class HtmlRenderer( } node.hasStyle(TextStyle.Span) -> span { childrenCallback() } node.dci.kind == ContentKind.Symbol -> div("symbol $additionalClasses") { childrenCallback() } + node.dci.kind == SymbolContentKind.Parameters -> { + span("parameters $additionalClasses") { + childrenCallback() + } + } + node.dci.kind == SymbolContentKind.Parameter -> { + span("parameter $additionalClasses") { + if (node.hasStyle(ContentStyle.Indented)) { + // could've been done with CSS (padding-left, ::before, etc), but the indent needs to + // consist of physical spaces, otherwise select and copy won't work properly + repeat(4) { consumer.onTagContentEntity(Entities.nbsp) } + } + childrenCallback() + } + } node.dci.kind == ContentKind.BriefComment -> div("brief $additionalClasses") { childrenCallback() } node.dci.kind == ContentKind.Cover -> div("cover $additionalClasses") { //TODO this can be removed childrenCallback() diff --git a/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt b/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt index 94af96e2..b6841323 100644 --- a/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt +++ b/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt @@ -174,6 +174,57 @@ interface JvmSignatureUtils { parameters.flatMap { listOf(it.dri) + it.type.drisOfAllNestedBounds }) return t.dri in allDris } + + /** + * Builds a distinguishable [function] parameters block, so that it + * can be processed or custom rendered down the road. + * + * Resulting structure: + * ``` + * SymbolContentKind.Parameters(style = wrapped) { + * SymbolContentKind.Parameter(style = indented) { param, } + * SymbolContentKind.Parameter(style = indented) { param, } + * SymbolContentKind.Parameter(style = indented) { param } + * } + * ``` + * Wrapping and indentation of parameters is applied conditionally, see [shouldWrapParams] + */ + fun PageContentBuilder.DocumentableContentBuilder.parametersBlock( + function: DFunction, paramBuilder: PageContentBuilder.DocumentableContentBuilder.(DParameter) -> Unit + ) { + val shouldWrap = function.shouldWrapParams() + val parametersStyle = if (shouldWrap) setOf(ContentStyle.Wrapped) else emptySet() + val elementStyle = if (shouldWrap) setOf(ContentStyle.Indented) else emptySet() + group(kind = SymbolContentKind.Parameters, styles = parametersStyle) { + function.parameters.dropLast(1).forEach { + group(kind = SymbolContentKind.Parameter, styles = elementStyle) { + paramBuilder(it) + punctuation(", ") + } + } + group(kind = SymbolContentKind.Parameter, styles = elementStyle) { + paramBuilder(function.parameters.last()) + } + } + } + + /** + * Determines whether parameters in a function (including constructor) should be wrapped + * + * Without wrapping: + * ``` + * class SimpleClass(foo: String, bar: String) {} + * ``` + * With wrapping: + * ``` + * class SimpleClass( + * foo: String, + * bar: String, + * baz: String + * ) + * ``` + */ + private fun DFunction.shouldWrapParams() = this.parameters.size >= 3 } sealed class AtStrategy diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt index 47e16e69..3f8c1703 100644 --- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt +++ b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt @@ -7,15 +7,13 @@ import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.dri import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.driOrNull import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder +import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder.DocumentableContentBuilder import org.jetbrains.dokka.links.* import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.Nullable import org.jetbrains.dokka.model.TypeConstructor 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.pages.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle @@ -179,19 +177,19 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog annotationsInline(pConstructor) keyword("constructor") } - list( - elements = pConstructor.parameters, - prefix = "(", - suffix = ")", - separator = ", ", - separatorStyles = mainStyles + TokenStyle.Punctuation, - surroundingCharactersStyle = mainStyles + TokenStyle.Punctuation, - sourceSets = pConstructor.sourceSets.toSet() - ) { - annotationsInline(it) - text(it.name.orEmpty()) - operator(": ") - signatureForProjection(it.type) + + // for primary constructor, opening and closing parentheses + // should be present only if it has parameters. If there are + // no parameters, it should result in `class Example` + if (pConstructor.parameters.isNotEmpty()) { + punctuation("(") + parametersBlock(pConstructor) { param -> + annotationsInline(param) + text(param.name.orEmpty()) + operator(": ") + signatureForProjection(param.type) + } + punctuation(")") } } } @@ -283,17 +281,21 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog punctuation(".") } link(f.name, f.dri, styles = mainStyles + TokenStyle.Function) + + // for a function, opening and closing parentheses must be present + // anyway, even if it has no parameters, resulting in `fun test(): R` punctuation("(") - list(f.parameters, - separatorStyles = mainStyles + TokenStyle.Punctuation) { - annotationsInline(it) - processExtraModifiers(it) - text(it.name!!) - operator(": ") - signatureForProjection(it.type) - it.extra[DefaultValue]?.run { - operator(" = ") - highlightValue(value) + if (f.parameters.isNotEmpty()) { + parametersBlock(f) { param -> + annotationsInline(param) + processExtraModifiers(param) + text(param.name!!) + operator(": ") + signatureForProjection(param.type) + param.extra[DefaultValue]?.run { + operator(" = ") + highlightValue(value) + } } } punctuation(")") diff --git a/plugins/base/src/main/resources/dokka/styles/style.css b/plugins/base/src/main/resources/dokka/styles/style.css index ad28e895..cc8b6823 100644 --- a/plugins/base/src/main/resources/dokka/styles/style.css +++ b/plugins/base/src/main/resources/dokka/styles/style.css @@ -886,6 +886,10 @@ td.content { padding-bottom: 0; } +.parameters.wrapped > .parameter { + display: block; +} + .table-row .with-platform-tabs .sourceset-depenent-content .brief { padding: 8px; } |