Skip to content

Commit

Permalink
Move source links into signature
Browse files Browse the repository at this point in the history
  • Loading branch information
vmishenev committed Apr 27, 2022
1 parent 2a0ed52 commit 8eb38d4
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 84 deletions.
1 change: 1 addition & 0 deletions core/api/core.api
Expand Up @@ -4276,6 +4276,7 @@ public final class org/jetbrains/dokka/pages/TextStyle : java/lang/Enum, org/jet
public static final field Italic Lorg/jetbrains/dokka/pages/TextStyle;
public static final field Monospace Lorg/jetbrains/dokka/pages/TextStyle;
public static final field Paragraph Lorg/jetbrains/dokka/pages/TextStyle;
public static final field RightAligned Lorg/jetbrains/dokka/pages/TextStyle;
public static final field Span Lorg/jetbrains/dokka/pages/TextStyle;
public static final field Strikethrough Lorg/jetbrains/dokka/pages/TextStyle;
public static final field Strong Lorg/jetbrains/dokka/pages/TextStyle;
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/kotlin/pages/ContentNodes.kt
Expand Up @@ -384,7 +384,8 @@ enum class TokenStyle : Style {

enum class TextStyle : Style {
Bold, Italic, Strong, Strikethrough, Paragraph,
Block, Span, Monospace, Indented, Cover, UnderCoverText, BreakableAfter, Breakable, InlineComment
Block, Span, Monospace, Indented, Cover, UnderCoverText, BreakableAfter, Breakable, InlineComment,
RightAligned
}

enum class ContentStyle : Style {
Expand Down
4 changes: 0 additions & 4 deletions plugins/base/api/base.api
Expand Up @@ -1329,10 +1329,6 @@ public final class org/jetbrains/dokka/base/transformers/pages/sourcelinks/Sourc
public fun invoke (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode;
}

public final class org/jetbrains/dokka/base/transformers/pages/sourcelinks/SourceLinksTransformerKt {
public static final fun hasTabbedContent (Lorg/jetbrains/dokka/pages/ContentGroup;)Z
}

public abstract interface class org/jetbrains/dokka/base/transformers/pages/tags/CustomTagContentProvider {
public abstract fun contentForBrief (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/model/doc/CustomTagWrapper;)V
public abstract fun contentForDescription (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/model/doc/CustomTagWrapper;)V
Expand Down
Expand Up @@ -128,6 +128,7 @@ open class HtmlRenderer(
}
node.hasStyle(TextStyle.Paragraph) -> p(additionalClasses) { childrenCallback() }
node.hasStyle(TextStyle.Block) -> div(additionalClasses) { childrenCallback() }
node.hasStyle(TextStyle.RightAligned) -> span("right $additionalClasses") { childrenCallback() }
node.isAnchorable -> buildAnchor(
node.anchor!!,
node.anchorLabel!!,
Expand Down
Expand Up @@ -7,11 +7,9 @@ import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
import org.jetbrains.dokka.analysis.DescriptorDocumentableSource
import org.jetbrains.dokka.analysis.PsiDocumentableSource
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder
import org.jetbrains.dokka.model.DocumentableSource
import org.jetbrains.dokka.model.WithSources
import org.jetbrains.dokka.model.toDisplaySourceSets
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.*
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.plugin
Expand All @@ -20,6 +18,7 @@ import org.jetbrains.dokka.transformers.pages.PageTransformer
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
import java.io.File

class SourceLinksTransformer(val context: DokkaContext) : PageTransformer {
Expand All @@ -33,11 +32,14 @@ class SourceLinksTransformer(val context: DokkaContext) : PageTransformer {
override fun invoke(input: RootPageNode) =
input.transformContentPagesTree { node ->
when (node) {
is WithDocumentables ->
node.documentables.filterIsInstance<WithSources>().flatMap { resolveSources(it) }
.takeIf { it.isNotEmpty() }
?.let { node.addSourcesContent(it) }
?: node
is WithDocumentables -> {
val sources = node.documentables.filterIsInstance<WithSources>()
.associate { (it as Documentable).dri to resolveSources(it) }
if (sources.isNotEmpty())
node.modified(content = transformContent(node.content, sources))
else
node
}
else -> node
}
}
Expand All @@ -48,46 +50,11 @@ class SourceLinksTransformer(val context: DokkaContext) : PageTransformer {
private fun resolveSources(documentable: WithSources) = documentable.sources
.mapNotNull { entry ->
getSourceLinks().find { File(entry.value.path).startsWith(it.path) && it.sourceSetData == entry.key }?.let {
Pair(
entry.key,
entry.key to
entry.value.toLink(it)
)
}
}

private fun ContentPage.addSourcesContent(sources: List<Pair<DokkaSourceSet, String>>) = builder
.buildSourcesContent(this, sources)
.let {
this.modified(
content = this.content.addTable(it)
)
}

private fun PageContentBuilder.buildSourcesContent(
node: ContentPage,
sources: List<Pair<DokkaSourceSet, String>>
): ContentGroup {
val documentables = (node as? WithDocumentables)?.documentables.orEmpty()
return contentFor(
node.dri,
documentables.flatMap { it.sourceSets }.toSet()
) {
header(2, "Sources", kind = ContentKind.Source)
+ContentTable(
header = emptyList(),
children = sources.map {
buildGroup(node.dri, setOf(it.first), kind = ContentKind.Source, extra = mainExtra + SymbolAnchorHint(it.second, ContentKind.Source)) {
link("${it.first.displayName} source", it.second)
}
},
dci = DCI(node.dri, ContentKind.Source),
sourceSets = documentables.flatMap { it.sourceSets }.toDisplaySourceSets(),
style = emptySet(),
extra = mainExtra + SimpleAttr.header("Sources")
)
}
}

private fun DocumentableSource.toLink(sourceLink: SourceLink): String {
val sourcePath = File(this.path).canonicalPath.replace("\\", "/")
val sourceLinkPath = File(sourceLink.path).canonicalPath.replace("\\", "/")
Expand All @@ -105,38 +72,45 @@ class SourceLinksTransformer(val context: DokkaContext) : PageTransformer {
sourceLink.lineSuffix +
"${lineNumber ?: 1}"
}

private fun PsiElement.lineNumber(): Int? {
val doc = PsiDocumentManager.getInstance(project).getDocument(containingFile)
// IJ uses 0-based line-numbers; external source browsers use 1-based
return doc?.getLineNumber(textRange.startOffset)?.plus(1)
}

private fun ContentNode.addTable(table: ContentGroup): ContentNode =
when (this) {
is ContentGroup -> {
if (hasTabbedContent()) {
copy(
children = children.map {
if (it.hasStyle(ContentStyle.TabbedContent) && it is ContentGroup) {
it.copy(children = it.children + table)
} else {
it
}
}
)
} else {
copy(children = children + table)
}
private fun ContentNode.signatureGroupOrNull() =
(this as? ContentGroup)?.takeIf { it.dci.kind == ContentKind.Symbol }

private fun transformContent(
contentNode: ContentNode, sources: Map<DRI, List<Pair<DokkaSourceSet, String>>>
): ContentNode =
contentNode.signatureGroupOrNull()?.let { cg ->
sources[cg.dci.dri.singleOrNull()]?.let { sourceLinks ->
sourceLinks.filter { it.first.sourceSetID in cg.sourceSets.sourceSetIDs }.ifNotEmpty {
cg.copy(children = cg.children + sourceLinks.map {
buildContentLink(
cg.dci.dri.first(),
it.first,
it.second
)
})
}
}
else -> ContentGroup(
children = listOf(this, table),
extra = this.extra,
sourceSets = this.sourceSets,
dci = this.dci,
style = this.style
)
} ?: when (contentNode) {
is ContentComposite -> contentNode.transformChildren { transformContent(it, sources) }
else -> contentNode
}

private fun PsiElement.lineNumber(): Int? {
val doc = PsiDocumentManager.getInstance(project).getDocument(containingFile)
// IJ uses 0-based line-numbers; external source browsers use 1-based
return doc?.getLineNumber(textRange.startOffset)?.plus(1)
private fun buildContentLink(dri: DRI, sourceSet: DokkaSourceSet, link: String) = builder.contentFor(
dri,
setOf(sourceSet),
ContentKind.Source,
setOf(TextStyle.RightAligned)
) {
text("(")
link("source", link)
text(")")
}
}

Expand All @@ -147,6 +121,4 @@ data class SourceLink(val path: String, val url: String, val lineSuffix: String?
sourceLinkDefinition.remoteLineSuffix,
sourceSetData
)
}

fun ContentGroup.hasTabbedContent(): Boolean = children.any { it.hasStyle(ContentStyle.TabbedContent) }
}
4 changes: 4 additions & 0 deletions plugins/base/src/main/resources/dokka/styles/style.css
Expand Up @@ -1182,3 +1182,7 @@ div.runnablesample {
display: none;
}
}

.right {
float: right;
}
Expand Up @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import utils.assertNotNull
import java.net.URL
import java.nio.file.Paths

Expand Down Expand Up @@ -131,10 +132,8 @@ class LinkableContentTest : BaseAbstractTest() {
Assertions.assertEquals(2, packageChildren.size)
packageChildren.forEach {
val name = it.name.substringBefore("Class")
val crl = it.safeAs<ClasslikePageNode>()?.content?.safeAs<ContentGroup>()?.children?.last()
?.safeAs<ContentGroup>()?.children?.last()?.safeAs<ContentGroup>()?.children?.lastOrNull()
?.safeAs<ContentTable>()?.children?.singleOrNull()
?.safeAs<ContentGroup>()?.children?.singleOrNull().safeAs<ContentResolvedLink>()
val signature = it.safeAs<ClasslikePageNode>()?.content?.dfs { it is ContentGroup && it.dci.kind == ContentKind.Symbol }.assertNotNull("signature")
val crl = signature.children.last().children[1].safeAs<ContentResolvedLink>()
Assertions.assertEquals(
"https://github.com/user/repo/tree/master/src/${name.toLowerCase()}Main/kotlin/${name}Class.kt#L3",
crl?.address
Expand Down

0 comments on commit 8eb38d4

Please sign in to comment.