diff --git a/scaladoc-js/main/src/searchbar/PageEntry.scala b/scaladoc-js/main/src/searchbar/PageEntry.scala index c042798c7b35..3910f721192c 100644 --- a/scaladoc-js/main/src/searchbar/PageEntry.scala +++ b/scaladoc-js/main/src/searchbar/PageEntry.scala @@ -6,6 +6,7 @@ import scala.scalajs.js trait PageEntryJS extends js.Object { val n: String = js.native val t: String = js.native + val i: String = js.native val d: String = js.native val l: String = js.native val e: Boolean = js.native @@ -15,6 +16,7 @@ trait PageEntryJS extends js.Object { case class PageEntry( fullName: String, description: String, + extensionTarget: String, location: String, isLocationExternal: Boolean, shortName: String, @@ -35,6 +37,7 @@ object PageEntry { def apply(jsObj: PageEntryJS): PageEntry = PageEntry( jsObj.t, jsObj.d, + jsObj.i, jsObj.l, jsObj.e, jsObj.n.toLowerCase, diff --git a/scaladoc-js/main/src/searchbar/SearchbarComponent.scala b/scaladoc-js/main/src/searchbar/SearchbarComponent.scala index d0080d0793ae..7dd8bebd1ca2 100644 --- a/scaladoc-js/main/src/searchbar/SearchbarComponent.scala +++ b/scaladoc-js/main/src/searchbar/SearchbarComponent.scala @@ -23,9 +23,16 @@ class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearch Globals.pathToRoot + p.location } + val extensionTargetMessage = if (p.extensionTarget.isEmpty()) { + "" + } else { + " extension on " + p.extensionTarget + } + div(cls := "scaladoc-searchbar-row monospace", "result" := "")( a(href := location)( p.fullName, + span(i(extensionTargetMessage)), span(cls := "pull-right scaladoc-searchbar-location")(p.description) ).tap { _.onclick = (event: Event) => if (document.body.contains(rootDiv)) { diff --git a/scaladoc-js/main/test/dotty/tools/scaladoc/MatchersTest.scala b/scaladoc-js/main/test/dotty/tools/scaladoc/MatchersTest.scala index f6cc653ee479..bac13fa1e695 100644 --- a/scaladoc-js/main/test/dotty/tools/scaladoc/MatchersTest.scala +++ b/scaladoc-js/main/test/dotty/tools/scaladoc/MatchersTest.scala @@ -34,6 +34,7 @@ class MatchersTest: s"$kind $name", "", "", + "", false, s"$name", kind, diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala index a8118463cb95..e2965d5707ad 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala @@ -132,36 +132,44 @@ trait Resources(using ctx: DocContext) extends Locations, Writer: case Keyword(s) => s }.mkString - def mkEntry(dri: DRI, name: String, text: String, descr: String, kind: String) = jsonObject( + def mkEntry(dri: DRI, name: String, text: String, extensionTarget: String, descr: String, kind: String) = jsonObject( "l" -> jsonString(relativeInternalOrAbsoluteExternalPath(dri)), "e" -> (if dri.externalLink.isDefined then rawJSON("true") else rawJSON("false")), + "i" -> jsonString(extensionTarget), "n" -> jsonString(name), "t" -> jsonString(text), "d" -> jsonString(descr), "k" -> jsonString(kind) ) - def processPage(page: Page): Seq[JSON] = - val res = page.content match + def extensionTarget(member: Member): String = + member.kind match + case Kind.Extension(on, _) => flattenToText(on.signature) + case _ => "" + + def processPage(page: Page, pageFQName: List[String]): Seq[(JSON, Seq[String])] = + val (res, pageName) = page.content match case m: Member if m.kind != Kind.RootPackage => - val descr = m.dri.asFileLocation - def processMember(member: Member): Seq[JSON] = + def processMember(member: Member, fqName: List[String]): Seq[(JSON, Seq[String])] = val signatureBuilder = ScalaSignatureProvider.rawSignature(member, InlineSignatureBuilder())().asInstanceOf[InlineSignatureBuilder] val sig = Signature(Plain(member.name)) ++ signatureBuilder.names.reverse - val entry = mkEntry(member.dri, member.name, flattenToText(sig), descr, member.kind.name) + val descr = fqName.mkString(".") + val entry = mkEntry(member.dri, member.name, flattenToText(sig), extensionTarget(member), descr, member.kind.name) val children = member .membersBy(m => m.kind != Kind.Package && !m.kind.isInstanceOf[Classlike]) .filter(m => m.origin == Origin.RegularlyDefined && m.inheritedFrom.fold(true)(_.isSourceSuperclassHidden)) - Seq(entry) ++ children.flatMap(processMember) + val updatedFqName = fqName :+ member.name + Seq((entry, updatedFqName)) ++ children.flatMap(processMember(_, updatedFqName)) - processMember(m) + (processMember(m, pageFQName), m.name) case _ => - Seq(mkEntry(page.link.dri, page.link.name, page.link.name, "", "static")) + (Seq((mkEntry(page.link.dri, page.link.name, page.link.name, "", "", "static"), pageFQName)), "") - res ++ page.children.flatMap(processPage) + val updatedFqName = if !pageName.isEmpty then pageFQName :+ pageName else pageFQName + res ++ page.children.flatMap(processPage(_, updatedFqName)) - val entries = pages.flatMap(processPage) - Resource.Text(searchDataPath, s"pages = ${jsonList(entries)};") + val entries = pages.flatMap(processPage(_, Nil)) + Resource.Text(searchDataPath, s"pages = ${jsonList(entries.map(_._1))};") def scastieConfiguration() = Resource.Text(scastieConfigurationPath, s"""scastieConfiguration = "${