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 all 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
9 changes: 9 additions & 0 deletions core/api/core.api
Expand Up @@ -3861,10 +3861,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 Expand Up @@ -4196,6 +4198,13 @@ public final class org/jetbrains/dokka/pages/SimpleAttr$SimpleAttrKey : org/jetb
public abstract interface class org/jetbrains/dokka/pages/Style {
}

public final class org/jetbrains/dokka/pages/SymbolContentKind : java/lang/Enum, org/jetbrains/dokka/pages/Kind {
public static final field Parameter Lorg/jetbrains/dokka/pages/SymbolContentKind;
public static final field Parameters Lorg/jetbrains/dokka/pages/SymbolContentKind;
public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/dokka/pages/SymbolContentKind;
public static fun values ()[Lorg/jetbrains/dokka/pages/SymbolContentKind;
}

public final class org/jetbrains/dokka/pages/TextStyle : java/lang/Enum, org/jetbrains/dokka/pages/Style {
public static final field Block Lorg/jetbrains/dokka/pages/TextStyle;
public static final field Bold Lorg/jetbrains/dokka/pages/TextStyle;
Expand Down
45 changes: 43 additions & 2 deletions core/src/main/kotlin/pages/ContentNodes.kt
Expand Up @@ -316,9 +316,25 @@ data class PlatformHintedContent(
interface Style
interface Kind

/**
* [ContentKind] represents a grouping of content of one kind. This can be rendered
* as either a part of a composite page (one tab/block within a class's page, for instance)
* or as a separate page altogether.
*/
enum class ContentKind : Kind {

Comment, Constructors, Functions, Parameters, Properties, Classlikes, Packages, Symbol, Sample, Main, BriefComment,
/**
* Marks all sorts of signatures. Can contain sub-kinds marked as [SymbolContentKind]
*
* Some examples:
* - primary constructor: `data class CoroutineName(name: String) : AbstractCoroutineContextElement`
* - constructor: `fun CoroutineName(name: String)`
* - function: `open override fun toString(): String`
* - property: `val name: String`
*/
Symbol,

Comment, Constructors, Functions, Parameters, Properties, Classlikes, Packages, Sample, Main, BriefComment,
Empty, Source, TypeAliases, Cover, Inheritors, SourceSetDependentHint, Extensions, Annotations;

companion object {
Expand All @@ -338,6 +354,30 @@ enum class ContentKind : Kind {
fun shouldBePlatformTagged(kind: Kind): Boolean = kind in platformTagged
}
}

/**
* Content kind for [ContentKind.Symbol] content, which is essentially about signatures
*/
enum class SymbolContentKind : Kind {
/**
* Marks constructor/function parameters, everything in-between parentheses.
*
* For function `fun foo(bar: String, baz: Int, qux: Boolean)`,
* the parameters would be the whole of `bar: String, baz: Int, qux: Boolean`
*/
Parameters,

/**
* Marks a single parameter in a function. Most likely to be a child of [Parameters].
*
* In function `fun foo(bar: String, baz: Int, qux: Boolean)` there would be 3 [Parameter] instances:
* - `bar: String, `
* - `baz: Int, `
* - `qux: Boolean`
*/
Parameter,
}

enum class TokenStyle : Style {
Keyword, Punctuation, Function, Operator, Annotation, Number, String, Boolean, Constant, Builtin
}
Expand All @@ -347,7 +387,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 @@ -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()
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:
* ```
* 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
Expand Down