From 9e4bdc75d50616ed5483d05d776db58d2ec0a1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zyba=C5=82a?= Date: Tue, 10 Nov 2020 09:41:02 +0100 Subject: [PATCH] Fix searchbar to match only by name --- scala3doc/src/dotty/dokka/compat.scala | 14 ++++ scala3doc/src/dotty/dokka/utils.scala | 2 - .../dotty/renderers/ScalaHtmlRenderer.scala | 9 +++ .../ScalaSearchbarDataInstaller.scala | 68 +++++++++++++++++++ 4 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 scala3doc/src/dotty/renderers/ScalaSearchbarDataInstaller.scala diff --git a/scala3doc/src/dotty/dokka/compat.scala b/scala3doc/src/dotty/dokka/compat.scala index cf9440bd6913..1c7ce3446e88 100644 --- a/scala3doc/src/dotty/dokka/compat.scala +++ b/scala3doc/src/dotty/dokka/compat.scala @@ -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) @@ -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))) diff --git a/scala3doc/src/dotty/dokka/utils.scala b/scala3doc/src/dotty/dokka/utils.scala index 67986989ad29..31a6afae752a 100644 --- a/scala3doc/src/dotty/dokka/utils.scala +++ b/scala3doc/src/dotty/dokka/utils.scala @@ -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] = diff --git a/scala3doc/src/dotty/renderers/ScalaHtmlRenderer.scala b/scala3doc/src/dotty/renderers/ScalaHtmlRenderer.scala index a1141cbe3e46..b62e84040d3d 100644 --- a/scala3doc/src/dotty/renderers/ScalaHtmlRenderer.scala +++ b/scala3doc/src/dotty/renderers/ScalaHtmlRenderer.scala @@ -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)) @@ -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 { diff --git a/scala3doc/src/dotty/renderers/ScalaSearchbarDataInstaller.scala b/scala3doc/src/dotty/renderers/ScalaSearchbarDataInstaller.scala new file mode 100644 index 000000000000..031980a60589 --- /dev/null +++ b/scala3doc/src/dotty/renderers/ScalaSearchbarDataInstaller.scala @@ -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]() + + 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) + }