From 9e1f5a99bc983b00cef707ddfe00fe163fd82495 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Mon, 28 Feb 2022 15:16:36 +0100 Subject: [PATCH] Add extension suffixes and fqName to scaladoc searchbar Extension suffixes in the form of italized 'extension on (...)' allow to separate semantically different methods, which previously would have been displayed as the same in searchbar. File-based location was also replaced with fully qualified name based, in an effort to improve readability. --- .../main/src/searchbar/PageEntry.scala | 3 ++ .../src/searchbar/SearchbarComponent.scala | 7 ++++ .../dotty/tools/scaladoc/MatchersTest.scala | 1 + .../tools/scaladoc/renderers/Resources.scala | 32 ++++++++++++------- 4 files changed, 31 insertions(+), 12 deletions(-) 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 = "${