Skip to content

Scala3doc: Fix searchbar to match only by name #10263

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

Merged
merged 1 commit into from
Nov 13, 2020
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions scala3doc/src/dotty/dokka/compat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import org.jetbrains.dokka.model.properties.ExtraProperty
// import java.util.Stream // TODO reproduction uncomment
import java.util.stream.Stream // comment out - wrong error!
import java.util.stream.Collectors
import org.jetbrains.dokka.plugability._
import kotlin.jvm.JvmClassMappingKt.getKotlinClass

def mkDRI(packageName: String = null, extra: String = null) = new DRI(packageName, null, null, PointingToDeclaration.INSTANCE, extra)

Expand Down Expand Up @@ -57,3 +59,15 @@ extension [V] (map: JMap[SourceSetWrapper, V]):
extension [V](jlist: JList[V]):
def ++ (other: JList[V]): JList[V] =
Stream.of(jlist, other).flatMap(_.stream).collect(Collectors.toList())

object PluginUtils:
import scala.reflect.ClassTag
import scala.reflect._
def plugin[T <: DokkaPlugin: ClassTag](ctx: DokkaContext) =
ctx.plugin[T](getKotlinClass(implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]]))

def query[T <: DokkaPlugin: ClassTag, E](ctx: DokkaContext, queryFunction: (T) => ExtensionPoint[E]): List[E] =
ctx.get(queryFunction(plugin[T](ctx))).asScala.toList

def querySingle[T <: DokkaPlugin: ClassTag, E](ctx: DokkaContext, queryFunction: (T) => ExtensionPoint[E]): E =
ctx.single(queryFunction(plugin[T](ctx)))
2 changes: 0 additions & 2 deletions scala3doc/src/dotty/dokka/utils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import org.jetbrains.dokka.model.properties.PropertyContainer
import java.util.function.Consumer
import kotlin.jvm.functions.Function2
import org.jetbrains.dokka.DokkaConfiguration$DokkaSourceSet
import org.jetbrains.dokka.plugability._
import kotlin.jvm.JvmClassMappingKt.getKotlinClass

class BaseKey[T, V] extends ExtraProperty.Key[T, V]:
override def mergeStrategyFor(left: V, right: V): MergeStrategy[T] =
Expand Down
9 changes: 9 additions & 0 deletions scala3doc/src/dotty/renderers/ScalaHtmlRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.jetbrains.dokka.base.resolvers.local.LocationProvider
import dotty.dokka.site.StaticPageNode
import dotty.dokka.site.PartiallyRenderedContent
import scala.util.Try
import org.jetbrains.dokka.base.renderers.html.SearchbarDataInstaller

class SignatureRenderer(pageContext: ContentPage, sourceSetRestriciton: JSet[DisplaySourceSet], locationProvider: LocationProvider):
def link(dri: DRI): Option[String] = Option(locationProvider.resolve(dri, sourceSetRestriciton, pageContext))
Expand All @@ -42,6 +43,14 @@ class SignatureRenderer(pageContext: ContentPage, sourceSetRestriciton: JSet[Dis

class ScalaHtmlRenderer(ctx: DokkaContext) extends HtmlRenderer(ctx) {

// TODO #239
val hackScalaSearchbarDataInstaller: SearchbarDataInstaller = {
val f = classOf[HtmlRenderer].getDeclaredField("searchbarDataInstaller")
f.setAccessible(true)
f.set(this, ScalaSearchbarDataInstaller(ctx))
f.get(this).asInstanceOf[ScalaSearchbarDataInstaller]
}

// Implementation below is based on Kotlin bytecode and we will try to migrate it to dokka
// TODO (https://github.com/lampepfl/scala3doc/issues/232): Move this method to dokka
def withHtml(context: FlowContent, content: String): Unit = context match {
Expand Down
68 changes: 68 additions & 0 deletions scala3doc/src/dotty/renderers/ScalaSearchbarDataInstaller.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package dotty.dokka

import com.fasterxml.jackson.module.kotlin.ExtensionsKt._
import org.jetbrains.dokka.base.renderers.html.{SearchbarDataInstaller, SearchRecord}
import java.util.{List => JList}
import java.util.concurrent.ConcurrentHashMap
import collection.JavaConverters._
import org.jetbrains.dokka.pages._
import dotty.dokka.model.api._
import org.jetbrains.dokka.plugability._
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.DokkaPluginKt._
import org.jetbrains.dokka.base.DokkaBase
import dotty.dokka.PluginUtils._
import org.jetbrains.dokka.base.signatures.SignatureProvider
import org.jetbrains.dokka._
import org.jetbrains.dokka.model._
import scala.collection.concurrent.TrieMap
import dotty.dokka.site.StaticPageNode

class ScalaSearchbarDataInstaller(val ctx: DokkaContext) extends SearchbarDataInstaller:

case class PageEntry(val name: String, val signature: String, val link: String, val pkg: String)

// We need to use there mutable, concurrent collections because Dokka renders content concurrently
// and adds entry to searchbar on start of processing page
val pages = TrieMap[String, PageEntry]()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can add a comment that this is such a strange piece of code (concurrent collection, mutable state etc.) due to dokka?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added


val signatureProvider = querySingle[DokkaBase, SignatureProvider](ctx, _.getSignatureProvider)

override def processPage(page: ContentPage, link: String) =
Option(page.getDocumentable) match {
case Some(member) => processMember(member, link)
case None => page match {
case p: StaticPageNode => processStaticSite(p, link)
case _ => ()
}
}

def flattenToText(node: ContentNode): String = {
def getContentTextNodes(node: ContentNode, sourceSetRestriciton: DisplaySourceSet): List[ContentText] = node match {
case t: ContentText => List(t)
case c: ContentComposite if c.getDci.getKind != ContentKind.Annotations => c.getChildren.asScala
.filter(_.getSourceSets.asScala.contains(sourceSetRestriciton))
.flatMap(getContentTextNodes(_, sourceSetRestriciton))
.toList
case _ => List.empty
}

val sourceSetRestriciton = node.getSourceSets.asScala.find(_.getPlatform == Platform.common).getOrElse(node.getSourceSets.asScala.head)
getContentTextNodes(node, sourceSetRestriciton).map(_.getText).mkString("")
}

def processMember(member: Member, link: String) = {
val memberSignature = flattenToText(signatureProvider.signature(member).get(0))
val memberPackage = (Option(member.dri.getPackageName) ++ Option(member.dri.getClassNames) ++ Option(member.dri.getCallable)).mkString(".")
pages.addOne(memberSignature + link, PageEntry(member.name, memberSignature, link, memberPackage))
}

def processStaticSite(p: StaticPageNode, link: String) = {
pages.addOne(p.getName + link, PageEntry(p.getName, p.getName, link, ""))
}

override def generatePagesList(): String = {
val mapper = jacksonObjectMapper()
val pagesList = pages.values.map(p => createSearchRecord(p.signature, p.pkg, p.link, List(p.name).asJava)).toList.asJava
mapper.writeValueAsString(pagesList)
}