Skip to content
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

Scaladoc/inkuire #12375

Merged
merged 38 commits into from
Jul 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
874ada3
Inkuire MVP
KacperFKorban May 1, 2021
9c513b5
Hide inkuire generation under flags
KacperFKorban May 4, 2021
e1fe38a
Inkuire JS support
KacperFKorban May 6, 2021
e070e70
Merge searchbar engines
KacperFKorban May 7, 2021
db21229
Fixes after rebase
KacperFKorban May 7, 2021
39f1230
Rm inkuire option
KacperFKorban May 7, 2021
f727ca1
Fix scaladoc-js tests
KacperFKorban May 7, 2021
c85ab0f
Change ec2 address
KacperFKorban May 9, 2021
6eb7b0c
Change server address to api gateway
KacperFKorban May 9, 2021
4a8bd32
Add debounce
KacperFKorban May 13, 2021
6e24b2e
Fix fluff search engine
KacperFKorban May 13, 2021
fe902f3
Add support for extension methods
KacperFKorban May 13, 2021
ada1e70
Remove JS Search Engine
KacperFKorban May 13, 2021
98086e1
Move debounce to only affect signature queries
KacperFKorban May 13, 2021
43d4dbd
Handle unresolved variance
KacperFKorban May 20, 2021
b489a45
Revert "Remove JS Search Engine"
KacperFKorban May 28, 2021
0aff402
Fix inkuire links 1
KacperFKorban Jun 8, 2021
df06efa
Fix inkuire links 2
KacperFKorban Jun 8, 2021
355f82f
WIP
KacperFKorban Jun 9, 2021
d67fc38
Inkuire Implicit conversions WIP
KacperFKorban Jun 10, 2021
85e3deb
Inkuire java aliases WIP
KacperFKorban Jun 10, 2021
90e2dd3
Remove implicit conversions debugs
KacperFKorban Jun 10, 2021
5cde3be
Rebase fixes 1
KacperFKorban Jun 18, 2021
bed98a1
Fix displaying Inkuire results
KacperFKorban Jun 18, 2021
3c7bf6f
Change implicit conmversions to only affect receivers and apply them …
KacperFKorban Jun 18, 2021
9eddc6d
Handle external mappings
KacperFKorban Jun 21, 2021
fd92adc
Various small improvements
KacperFKorban Jun 25, 2021
e470b11
Cleanup comments
KacperFKorban Jun 25, 2021
10230e8
Hack type aliases for String (among others) to work
KacperFKorban Jun 28, 2021
49870ea
Searchbar colors
KacperFKorban Jun 30, 2021
430071b
Dark theme logo
KacperFKorban Jun 30, 2021
0134bec
Inkuire internal summary
KacperFKorban Jun 30, 2021
c2861f1
Remove generated files
KacperFKorban Jun 30, 2021
c197121
Change inkuire.js to be downloaded on build instead of static resource
KacperFKorban Jun 30, 2021
b388048
Change inkuire worker to be copied on building documentation
KacperFKorban Jul 1, 2021
6adf3f6
Review changes
KacperFKorban Jul 1, 2021
ce50111
Further review changes + fixed bug with displaying old results on rar…
KacperFKorban Jul 2, 2021
1718d47
Review changes
KacperFKorban Jul 5, 2021
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
2 changes: 1 addition & 1 deletion project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1267,7 +1267,7 @@ object Build {
scalaSrcLink(stdLibVersion, srcManaged(dottyNonBootstrappedVersion, "scala") + "="),
dottySrcLink(referenceVersion, srcManaged(dottyNonBootstrappedVersion, "dotty") + "=", "#library/src"),
dottySrcLink(referenceVersion),
) ++ scalacOptionsDocSettings ++ revision ++ params ++ targets
) ++ scalacOptionsDocSettings ++ revision ++ params ++ targets ++ Seq("-Ygenerate-inkuire")
import _root_.scala.sys.process._
val escapedCmd = cmd.map(arg => if(arg.contains(" ")) s""""$arg"""" else arg)
Def.task {
Expand Down
17 changes: 9 additions & 8 deletions scaladoc-js/resources/scaladoc-searchbar.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
box-shadow: 0 2px 16px 0 rgba(0, 42, 76, 0.15);
font-size: 13px;
font-family: system-ui, -apple-system, Segoe UI, Roboto, Noto Sans, Ubuntu, Cantarell, Helvetica Neue, Arial, sans-serif;
background-color: var(--leftbar-bg);
color: var(--leftbar-fg);
box-shadow: 0 0 2px var(--shadow);
}

#scaladoc-searchbar-input {
Expand All @@ -58,22 +61,24 @@
border: none;
border-bottom: 1px solid #bbb;
padding: 10px;
background-color: var(--leftbar-bg);
color: var(--leftbar-fg);
}

#scaladoc-searchbar-input:focus {
outline: none;
}

#scaladoc-searchbar-results {
background: var(--white);
display: flex;
flex-direction: column;
max-height: 500px;
overflow: auto;
}

.scaladoc-searchbar-result {
background: var(--white);
background-color: var(--leftbar-bg);
color: var(--leftbar-fg);
line-height: 24px;
display: flex;
padding: 4px 10px 4px 10px;
Expand All @@ -90,11 +95,11 @@
}

.scaladoc-searchbar-result[selected] {
background-color: var(--blue100);
background-color: var(--leftbar-hover-bg);
color: var(--leftbar-hover-fg);
}

.scaladoc-searchbar-result a {
color: var(--grey900);
/* for some reason, with display:block if there's a wrap between the
* search result text and the location span, the dead space to the
* left of the location span doesn't get treated as part of the block,
Expand All @@ -107,10 +112,6 @@
padding-left: 20px;
}

.scaladoc-searchbar-result .scaladoc-searchbar-location {
color: gray;
}

#searchBar {
display: inline-flex;
}
Expand Down
7 changes: 4 additions & 3 deletions scaladoc-js/src/searchbar/Searchbar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package dotty.tools.scaladoc

class Searchbar {
val pages = SearchbarGlobals.pages.toList.map(PageEntry.apply)
val engine = SearchbarEngine(pages)
val parser = QueryParser()
val component = SearchbarComponent(q => engine.query(parser.parse(q)))
}
val searchEngine = SearchbarEngine(pages)
val inkuireEngine = InkuireJSSearchEngine()
val component = SearchbarComponent(searchEngine, inkuireEngine, parser)
}
67 changes: 55 additions & 12 deletions scaladoc-js/src/searchbar/SearchbarComponent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package dotty.tools.scaladoc

import org.scalajs.dom._
import org.scalajs.dom.html.Input
import scala.scalajs.js.timers._
import scala.concurrent.duration._

class SearchbarComponent(val callback: (String) => List[PageEntry]):
class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearchEngine, parser: QueryParser):
val resultsChunkSize = 100
extension (p: PageEntry)
def toHTML =
def toHTML(inkuire: Boolean = false) =
val wrapper = document.createElement("div").asInstanceOf[html.Div]
wrapper.classList.add("scaladoc-searchbar-result")
wrapper.classList.add("monospace")
Expand All @@ -16,7 +18,7 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
icon.classList.add(p.kind.take(2))

val resultA = document.createElement("a").asInstanceOf[html.Anchor]
resultA.href = Globals.pathToRoot + p.location
resultA.href = if inkuire then p.location else Globals.pathToRoot + p.location
resultA.text = s"${p.fullName}"

val location = document.createElement("span")
Expand All @@ -32,26 +34,67 @@ class SearchbarComponent(val callback: (String) => List[PageEntry]):
})
wrapper

def handleNewQuery(query: String) =
val result = callback(query).map(_.toHTML)
def handleNewFluffQuery(matchers: List[Matchers]) =
val result = engine.query(matchers).map(_.toHTML(inkuire = false))
resultsDiv.scrollTop = 0
while (resultsDiv.hasChildNodes()) resultsDiv.removeChild(resultsDiv.lastChild)
val fragment = document.createDocumentFragment()
result.take(resultsChunkSize).foreach(fragment.appendChild)
resultsDiv.appendChild(fragment)
def loadMoreResults(result: List[raw.HTMLElement]): Unit = {
resultsDiv.onscroll = (event: Event) => {
if (resultsDiv.scrollHeight - resultsDiv.scrollTop == resultsDiv.clientHeight)
{
val fragment = document.createDocumentFragment()
result.take(resultsChunkSize).foreach(fragment.appendChild)
resultsDiv.appendChild(fragment)
loadMoreResults(result.drop(resultsChunkSize))
}
if (resultsDiv.scrollHeight - resultsDiv.scrollTop == resultsDiv.clientHeight) {
val fragment = document.createDocumentFragment()
result.take(resultsChunkSize).foreach(fragment.appendChild)
resultsDiv.appendChild(fragment)
loadMoreResults(result.drop(resultsChunkSize))
}
}
}
loadMoreResults(result.drop(resultsChunkSize))

extension (s: String)
def toHTMLError =
val wrapper = document.createElement("div").asInstanceOf[html.Div]
wrapper.classList.add("scaladoc-searchbar-result")
wrapper.classList.add("monospace")

val errorSpan = document.createElement("span").asInstanceOf[html.Span]
errorSpan.classList.add("search-error")
errorSpan.textContent = s

wrapper.appendChild(errorSpan)
wrapper

var timeoutHandle: SetTimeoutHandle = null
def handleNewQuery(query: String) =
clearTimeout(timeoutHandle)
resultsDiv.scrollTop = 0
resultsDiv.onscroll = (event: Event) => { }
while (resultsDiv.hasChildNodes()) resultsDiv.removeChild(resultsDiv.lastChild)
val fragment = document.createDocumentFragment()
parser.parse(query) match {
case EngineMatchersQuery(matchers) =>
handleNewFluffQuery(matchers)
case BySignature(signature) =>
timeoutHandle = setTimeout(1.second) {
val properResultsDiv = document.createElement("div").asInstanceOf[html.Div]
resultsDiv.appendChild(properResultsDiv)
val loading = document.createElement("div").asInstanceOf[html.Div]
loading.classList.add("loading-wrapper")
val animation = document.createElement("div").asInstanceOf[html.Div]
animation.classList.add("loading")
loading.appendChild(animation)
properResultsDiv.appendChild(loading)
inkuireEngine.query(query) { (p: PageEntry) =>
properResultsDiv.appendChild(p.toHTML(inkuire = true))
} { (s: String) =>
animation.classList.remove("loading")
properResultsDiv.appendChild(s.toHTMLError)
}
}
}

private val searchIcon: html.Div =
val span = document.createElement("span").asInstanceOf[html.Span]
span.innerHTML = """<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"><path d="M19.64 18.36l-6.24-6.24a7.52 7.52 0 10-1.28 1.28l6.24 6.24zM7.5 13.4a5.9 5.9 0 115.9-5.9 5.91 5.91 0 01-5.9 5.9z"></path></svg>"""
Expand Down
50 changes: 50 additions & 0 deletions scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package dotty.tools.scaladoc

import scala.io.Source
import dotty.tools.scaladoc.PageEntry
import org.scalajs.dom.webworkers.Worker
import org.scalajs.dom._
import scala.scalajs.js.{ JSON, Dynamic }
import scala.collection.mutable.ListBuffer
import scala.scalajs.js
import scala.scalajs.js.timers._
import org.scalajs.dom.ext.Ajax
import scala.scalajs.js.URIUtils

class InkuireJSSearchEngine {

val scriptPath = Globals.pathToRoot + "scripts/"
val worker: Worker = new Worker(scriptPath + "inkuire-worker.js")

def dynamicToPageEntry(d: Dynamic): PageEntry = {
PageEntry(
d.functionName.asInstanceOf[String],
d.prettifiedSignature.asInstanceOf[String],
d.pageLocation.asInstanceOf[String],
d.functionName.asInstanceOf[String],
"def",
List.empty
)
}

def query(s: String)(callback: PageEntry => Unit)(endCallback: String => Unit): List[PageEntry] = {
worker.onmessage = _ => ()
val res = ListBuffer[PageEntry]()
val func = (msg: MessageEvent) => {
msg.data.asInstanceOf[String] match {
case "engine_ready" =>
case "new_query" =>
case endMsg if endMsg.startsWith("query_ended") =>
endCallback(endMsg.drop("query_ended".length))
case q =>
val matches = JSON.parse(q).matches
val actualMatches = matches.asInstanceOf[js.Array[Dynamic]].map(dynamicToPageEntry)
actualMatches.foreach(callback)
}
}
worker.onmessage = func
worker.postMessage(s)
res.toList
}

}
4 changes: 4 additions & 0 deletions scaladoc-js/src/searchbar/engine/Matchers.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package dotty.tools.scaladoc

sealed trait EngineQuery
case class EngineMatchersQuery(matchers: List[Matchers]) extends EngineQuery
case class BySignature(signature: String) extends EngineQuery

sealed trait Matchers extends Function1[PageEntry, Int]

case class ByName(query: String) extends Matchers:
Expand Down
10 changes: 8 additions & 2 deletions scaladoc-js/src/searchbar/engine/QueryParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,16 @@ class QueryParser:
val kindRegex = ("(?i)" + kinds.mkString("(","|",")") + " (.*)").r
val restRegex = raw"(.*)".r
val escapedRegex = raw"`(.*)`".r
val signatureRegex = raw"([^=>]+=>.*)".r

def parse(query: String): List[Matchers] = query match {
def parseMatchers(query: String): List[Matchers] = query match {
case escapedRegex(rest) => List(ByName(rest))
case kindRegex(kind, rest) => List(ByKind(kind)) ++ parse(rest)
case kindRegex(kind, rest) => List(ByKind(kind)) ++ parseMatchers(rest)
case restRegex(name) => List(ByName(name))
case _ => List()
}

def parse(query: String): EngineQuery = query match {
case signatureRegex(signature) => BySignature(signature)
case other => EngineMatchersQuery(parseMatchers(other))
}
1 change: 1 addition & 0 deletions scaladoc-js/src/searchbar/engine/SearchbarEngine.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dotty.tools.scaladoc

import math.Ordering.Implicits.seqOrdering
import org.scalajs.dom.Node

class SearchbarEngine(pages: List[PageEntry]):
def query(query: List[Matchers]): List[PageEntry] =
Expand Down
10 changes: 5 additions & 5 deletions scaladoc-js/test/dotty/dokka/QueryParserTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class QueryParserTest:
"given",
"type"
)
private def testCase(query: String, result: List[Matchers]) = {
private def testCase(query: String, result: EngineQuery) = {
val parsed = queryParser.parse(query)
assertEquals(
s"Query parser test error: for query: $query expected $result but found $parsed",
Expand All @@ -28,8 +28,8 @@ class QueryParserTest:

@Test
def queryParserTests() = {
kinds.foreach(k => testCase(s"$k ", List(ByKind(k), ByName(""))))
testCase("trait", List(ByName("trait")))
testCase("trait A", List(ByKind("trait"), ByName("A")))
testCase("`trait A`", List(ByName("trait A")))
kinds.foreach(k => testCase(s"$k ", EngineMatchersQuery(List(ByKind(k), ByName("")))))
testCase("trait", EngineMatchersQuery(List(ByName("trait"))))
testCase("trait A", EngineMatchersQuery(List(ByKind("trait"), ByName("A"))))
testCase("`trait A`", EngineMatchersQuery(List(ByName("trait A"))))
}
15 changes: 15 additions & 0 deletions scaladoc-testcases/src/tests/inkuire.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package tests.inkuire

trait InType1
trait InType2 extends InType1

trait OutType1
trait OutType2 extends OutType1

class JustAClass {
def mathod(l: InType1): OutType1 = ???
}

class JustAnotherClass extends JustAClass {
def method(i: InType2): OutType2 = ???
}
Loading