Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KT-50292 - Implement vertical alignment of parameter #2309

Merged
merged 5 commits into from Jan 27, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions core/api/core.api
Expand Up @@ -3748,6 +3748,7 @@ public final class org/jetbrains/dokka/pages/ContentKind : java/lang/Enum, org/j
public static final field Inheritors Lorg/jetbrains/dokka/pages/ContentKind;
public static final field Main Lorg/jetbrains/dokka/pages/ContentKind;
public static final field Packages Lorg/jetbrains/dokka/pages/ContentKind;
public static final field Parameter Lorg/jetbrains/dokka/pages/ContentKind;
public static final field Parameters Lorg/jetbrains/dokka/pages/ContentKind;
public static final field Properties Lorg/jetbrains/dokka/pages/ContentKind;
public static final field Sample Lorg/jetbrains/dokka/pages/ContentKind;
Expand Down Expand Up @@ -3861,10 +3862,12 @@ public final class org/jetbrains/dokka/pages/ContentResolvedLink : org/jetbrains
public final class org/jetbrains/dokka/pages/ContentStyle : java/lang/Enum, org/jetbrains/dokka/pages/Style {
public static final field Caption Lorg/jetbrains/dokka/pages/ContentStyle;
public static final field InDocumentationAnchor Lorg/jetbrains/dokka/pages/ContentStyle;
public static final field Indented Lorg/jetbrains/dokka/pages/ContentStyle;
public static final field RowTitle Lorg/jetbrains/dokka/pages/ContentStyle;
public static final field RunnableSample Lorg/jetbrains/dokka/pages/ContentStyle;
public static final field TabbedContent Lorg/jetbrains/dokka/pages/ContentStyle;
public static final field WithExtraAttributes Lorg/jetbrains/dokka/pages/ContentStyle;
public static final field Wrapped Lorg/jetbrains/dokka/pages/ContentStyle;
public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/dokka/pages/ContentStyle;
public static fun values ()[Lorg/jetbrains/dokka/pages/ContentStyle;
}
Expand Down
5 changes: 3 additions & 2 deletions core/src/main/kotlin/pages/ContentNodes.kt
Expand Up @@ -318,7 +318,7 @@ interface Kind

enum class ContentKind : Kind {

Comment, Constructors, Functions, Parameters, Properties, Classlikes, Packages, Symbol, Sample, Main, BriefComment,
Comment, Constructors, Functions, Parameters, Parameter, Properties, Classlikes, Packages, Symbol, Sample, Main, BriefComment,
IgnatBeresnev marked this conversation as resolved.
Show resolved Hide resolved
Empty, Source, TypeAliases, Cover, Inheritors, SourceSetDependentHint, Extensions, Annotations;

companion object {
Expand Down Expand Up @@ -347,7 +347,8 @@ enum class TextStyle : Style {
}

enum class ContentStyle : Style {
RowTitle, TabbedContent, WithExtraAttributes, RunnableSample, InDocumentationAnchor, Caption
RowTitle, TabbedContent, WithExtraAttributes, RunnableSample, InDocumentationAnchor, Caption,
Wrapped, Indented
}

enum class ListStyle : Style {
Expand Down
4 changes: 4 additions & 0 deletions plugins/base/api/base.api
Expand Up @@ -820,6 +820,7 @@ public abstract interface class org/jetbrains/dokka/base/signatures/JvmSignature
public abstract fun annotationsInline (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/AnnotationTarget;)V
public abstract fun annotationsInlineWithIgnored (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/AnnotationTarget;Ljava/util/Set;Lorg/jetbrains/dokka/base/signatures/AtStrategy;Lkotlin/Pair;Ljava/lang/String;)V
public abstract fun modifiers (Lorg/jetbrains/dokka/model/properties/WithExtraProperties;)Ljava/util/Map;
public abstract fun parametersBlock (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/DFunction;Lkotlin/jvm/functions/Function2;)V
public abstract fun plus (Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map;
public abstract fun stylesIfDeprecated (Lorg/jetbrains/dokka/model/properties/WithExtraProperties;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Ljava/util/Set;
public abstract fun toSignatureString (Ljava/util/Collection;)Ljava/lang/String;
Expand All @@ -832,6 +833,7 @@ public final class org/jetbrains/dokka/base/signatures/JvmSignatureUtils$Default
public static fun annotations (Lorg/jetbrains/dokka/base/signatures/JvmSignatureUtils;Lorg/jetbrains/dokka/model/properties/WithExtraProperties;)Ljava/util/Map;
public static fun annotationsBlockWithIgnored (Lorg/jetbrains/dokka/base/signatures/JvmSignatureUtils;Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/AnnotationTarget;Ljava/util/Set;Lorg/jetbrains/dokka/base/signatures/AtStrategy;Lkotlin/Pair;Ljava/lang/String;)V
public static fun annotationsInlineWithIgnored (Lorg/jetbrains/dokka/base/signatures/JvmSignatureUtils;Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/AnnotationTarget;Ljava/util/Set;Lorg/jetbrains/dokka/base/signatures/AtStrategy;Lkotlin/Pair;Ljava/lang/String;)V
public static fun parametersBlock (Lorg/jetbrains/dokka/base/signatures/JvmSignatureUtils;Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/DFunction;Lkotlin/jvm/functions/Function2;)V
public static fun plus (Lorg/jetbrains/dokka/base/signatures/JvmSignatureUtils;Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map;
public static fun stylesIfDeprecated (Lorg/jetbrains/dokka/base/signatures/JvmSignatureUtils;Lorg/jetbrains/dokka/model/properties/WithExtraProperties;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Ljava/util/Set;
public static fun toSignatureString (Lorg/jetbrains/dokka/base/signatures/JvmSignatureUtils;Ljava/util/Collection;)Ljava/lang/String;
Expand All @@ -849,6 +851,7 @@ public final class org/jetbrains/dokka/base/signatures/KotlinSignatureProvider :
public fun annotationsInline (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/AnnotationTarget;)V
public fun annotationsInlineWithIgnored (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/AnnotationTarget;Ljava/util/Set;Lorg/jetbrains/dokka/base/signatures/AtStrategy;Lkotlin/Pair;Ljava/lang/String;)V
public fun modifiers (Lorg/jetbrains/dokka/model/properties/WithExtraProperties;)Ljava/util/Map;
public fun parametersBlock (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/DFunction;Lkotlin/jvm/functions/Function2;)V
public fun plus (Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map;
public fun signature (Lorg/jetbrains/dokka/model/Documentable;)Ljava/util/List;
public fun stylesIfDeprecated (Lorg/jetbrains/dokka/model/properties/WithExtraProperties;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Ljava/util/Set;
Expand All @@ -869,6 +872,7 @@ public final class org/jetbrains/dokka/base/signatures/KotlinSignatureUtils : or
public final fun getDriOrNull (Lorg/jetbrains/dokka/model/Bound;)Lorg/jetbrains/dokka/links/DRI;
public final fun getDrisOfAllNestedBounds (Lorg/jetbrains/dokka/model/Projection;)Ljava/util/List;
public fun modifiers (Lorg/jetbrains/dokka/model/properties/WithExtraProperties;)Ljava/util/Map;
public fun parametersBlock (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/DFunction;Lkotlin/jvm/functions/Function2;)V
public fun plus (Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map;
public fun stylesIfDeprecated (Lorg/jetbrains/dokka/model/properties/WithExtraProperties;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Ljava/util/Set;
public fun toSignatureString (Ljava/util/Collection;)Ljava/lang/String;
Expand Down
13 changes: 12 additions & 1 deletion plugins/base/base-test-utils/api/base-test-utils.api
Expand Up @@ -85,6 +85,14 @@ public final class renderers/TestPageKt {
public static final fun testPage (Lkotlin/jvm/functions/Function1;)Lrenderers/RawTestPage;
}

public final class signatures/Parameter : utils/Tag {
public fun <init> ([Ljava/lang/Object;)V
}

public final class signatures/Parameters : utils/Tag {
public fun <init> ([Ljava/lang/Object;)V
}

public final class signatures/SignatureUtilsKt {
public static final fun firstSignature (Lorg/jsoup/nodes/Element;)Lorg/jsoup/nodes/Element;
public static final fun renderedContent (Lutils/TestOutputWriter;Ljava/lang/String;)Lorg/jsoup/nodes/Element;
Expand Down Expand Up @@ -131,6 +139,7 @@ public final class utils/I : utils/Tag {
public final class utils/JsoupUtilsKt {
public static final fun match (Lorg/jsoup/nodes/Element;[Ljava/lang/Object;Z)V
public static synthetic fun match$default (Lorg/jsoup/nodes/Element;[Ljava/lang/Object;ZILjava/lang/Object;)V
public static final fun withClasses (Lutils/Tag;[Ljava/lang/String;)Lutils/Tag;
}

public final class utils/P : utils/Tag {
Expand All @@ -146,7 +155,9 @@ public final class utils/Span : utils/Tag {
}

public class utils/Tag {
public fun <init> (Ljava/lang/String;[Ljava/lang/Object;)V
public fun <init> (Ljava/lang/String;[Ljava/lang/Object;Ljava/util/List;)V
public synthetic fun <init> (Ljava/lang/String;[Ljava/lang/Object;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getExpectedClasses ()Ljava/util/List;
public final fun getMatchers ()[Ljava/lang/Object;
public final fun getName ()Ljava/lang/String;
}
Expand Down
Expand Up @@ -21,7 +21,7 @@ fun Element.match(vararg matchers: Any, ignoreSpanWithTokenStyle:Boolean = false
.zip(matchers)
.forEach { (n, m) -> m.accepts(n, ignoreSpan = ignoreSpanWithTokenStyle) }

open class Tag(val name: String, vararg val matchers: Any)
open class Tag(val name: String, vararg val matchers: Any, val expectedClasses: List<String> = emptyList())
class Div(vararg matchers: Any) : Tag("div", *matchers)
class P(vararg matchers: Any) : Tag("p", *matchers)
class Span(vararg matchers: Any) : Tag("span", *matchers)
Expand All @@ -34,16 +34,24 @@ class Dt(vararg matchers: Any) : Tag("dt", *matchers)
class Dd(vararg matchers: Any) : Tag("dd", *matchers)
object Wbr : Tag("wbr")
object Br : Tag("br")

fun Tag.withClasses(vararg classes: String) = Tag(name, *matchers, expectedClasses = classes.toList())

private fun Any.accepts(n: Node, ignoreSpan:Boolean = true) {
when (this) {
is String -> assert(n is TextNode && n.text().trim() == this.trim()) { "\"$this\" expected but found: $n" }
is Tag -> {
assert(n is Element && n.tagName() == name) { "Tag $name expected but found: $n" }
if (n is Element && matchers.isNotEmpty()) n.match(*matchers, ignoreSpanWithTokenStyle = ignoreSpan)
check(n is Element) { "Expected node to be Element: $n" }
assert(n.tagName() == name) { "Tag \"$name\" expected but found: \"$n\"" }
expectedClasses.forEach {
assert(n.hasClass(it)) { "Expected to find class \"$it\" for tag \"$name\", found: ${n.classNames()}" }
}
if (matchers.isNotEmpty()) n.match(*matchers, ignoreSpanWithTokenStyle = ignoreSpan)
}
else -> throw IllegalArgumentException("$this is not proper matcher")
}
}

private fun List<Node>.uniteConsecutiveTextNodes(): MutableList<Node> {
val resList = mutableListOf<Node>()
var acc = StringBuilder()
Expand Down
Expand Up @@ -2,11 +2,15 @@ package signatures

import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import utils.Tag
import utils.TestOutputWriter

fun TestOutputWriter.renderedContent(path: String = "root/example.html") =
contents.getValue(path).let { Jsoup.parse(it) }.select("#content")
.single()

fun Element.signature() = select("div.symbol.monospace")
fun Element.firstSignature() = signature().first()
fun Element.firstSignature() = signature().first()

class Parameters(vararg matchers: Any) : Tag("span", *matchers, expectedClasses = listOf("parameters"))
vmishenev marked this conversation as resolved.
Show resolved Hide resolved
class Parameter(vararg matchers: Any) : Tag("span", *matchers, expectedClasses = listOf("parameter"))
15 changes: 15 additions & 0 deletions plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
Expand Up @@ -89,6 +89,21 @@ open class HtmlRenderer(
childrenCallback()
if (node.hasStyle(TextStyle.Monospace)) copyButton()
}
node.dci.kind == ContentKind.Parameters -> {
span("parameters $additionalClasses") {
childrenCallback()
}
}
node.dci.kind == ContentKind.Parameter -> {
span("parameter $additionalClasses") {
if (node.hasStyle(ContentStyle.Indented)) {
// could've been done with CSS (padding-left), but the indent needs to
IgnatBeresnev marked this conversation as resolved.
Show resolved Hide resolved
// consist of physical spaces, otherwise select and copy won't work properly
repeat(4) { consumer.onTagContentEntity(Entities.nbsp) }
}
childrenCallback()
}
}
node.hasStyle(TextStyle.BreakableAfter) -> {
span { childrenCallback() }
wbr { }
Expand Down
51 changes: 51 additions & 0 deletions plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt
Expand Up @@ -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:
* ```
* ContentKind.Parameters(style = wrapped) {
* ContentKind.Parameter(style = indented) { param, }
* ContentKind.Parameter(style = indented) { param, }
* ContentKind.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 = ContentKind.Parameters, styles = parametersStyle) {
function.parameters.dropLast(1).forEach {
group(kind = ContentKind.Parameter, styles = elementStyle) {
paramBuilder(it)
punctuation(", ")
}
}
group(kind = ContentKind.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
Expand Down
56 changes: 29 additions & 27 deletions plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt
Expand Up @@ -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
Expand Down Expand Up @@ -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(")")
}
}
}
Expand Down Expand Up @@ -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(")")
Expand Down
4 changes: 4 additions & 0 deletions plugins/base/src/main/resources/dokka/styles/style.css
Expand Up @@ -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;
}
Expand Down