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

GSoC 2024- Scaladoc Search in Protosearch #241

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
79382bb
integration
golden-skipper03 Jul 24, 2024
6b7e322
improved-integration
golden-skipper03 Sep 12, 2024
b386ff3
implement-changes
golden-skipper03 Sep 16, 2024
db3e994
create-scaladoc-ubmodule
golden-skipper03 Sep 17, 2024
5cd8f5b
error-fixing
golden-skipper03 Sep 17, 2024
bb708e6
revert-unneeded-changes
golden-skipper03 Sep 17, 2024
df92d97
handle-warnings-and-update
golden-skipper03 Sep 18, 2024
74b6812
format-code
golden-skipper03 Sep 18, 2024
903435d
scala-version-build-settings
golden-skipper03 Sep 18, 2024
f3e1f84
git-flow
golden-skipper03 Sep 18, 2024
4a1a917
add-parser-tests
golden-skipper03 Sep 19, 2024
1e88a7f
git-workglow
golden-skipper03 Sep 19, 2024
07668f4
add-header
golden-skipper03 Sep 19, 2024
c406669
Tweak scaladoc project build
valencik Sep 20, 2024
b608833
Remove scaladoc project from rootJVM
valencik Sep 20, 2024
45f2f8f
Merge pull request #1 from valencik/abhi-build
golden-skipper03 Sep 20, 2024
844da27
Add initial plugin to get all source files
valencik Sep 18, 2024
8ca6f6d
Build and write Index to static location
valencik Sep 19, 2024
a797fdf
Fix plugin project dependsOn (scaladoc not cross)
valencik Sep 20, 2024
49f513e
Rename to `createScaladocIndex`, parameterize
valencik Sep 20, 2024
69e856f
Merge branch 'main' of upstream
golden-skipper03 Sep 22, 2024
4a7e3ab
Add `index` query param support to search.js
valencik Sep 22, 2024
0af21a1
Add support for `type=scaladoc` query param
valencik Sep 22, 2024
1d417e6
Fix reading big files in ProtosearchScaladocPlugin
valencik Sep 22, 2024
47dee14
Merge pull request #2 from valencik/index-param
golden-skipper03 Sep 22, 2024
a45c31f
improve-search-ui
golden-skipper03 Sep 23, 2024
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ jobs:

- name: Make target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: mkdir -p sbt/target laikaIO/.jvm/target core/.js/target jsinterop/.js/target core/.jvm/target project/target
run: mkdir -p sbt/target laikaIO/.jvm/target core/.js/target jsinterop/.js/target core/.jvm/target scaladoc/target project/target

- name: Compress target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: tar cf targets.tar sbt/target laikaIO/.jvm/target core/.js/target jsinterop/.js/target core/.jvm/target project/target
run: tar cf targets.tar sbt/target laikaIO/.jvm/target core/.js/target jsinterop/.js/target core/.jvm/target scaladoc/target project/target

- name: Upload target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
Expand Down
17 changes: 15 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ val munitCatsEffectV = "2.0.0"
val munitV = "1.0.2"
val scalajsDomV = "2.8.0"
def scodecV(scalaV: String) = if (scalaV.startsWith("2.")) "1.11.10" else "2.3.1"
val scalametaV = "4.9.7"

lazy val root =
tlCrossRootProject
Expand All @@ -53,7 +54,7 @@ lazy val root =
jsInterop,
)
.configureRoot { root =>
root.aggregate(plugin) // don't include the plugin in rootJVM, only in root
root.aggregate(plugin, scaladoc) // don't include the plugin in rootJVM, only in root
}

lazy val core = crossProject(JVMPlatform, JSPlatform)
Expand Down Expand Up @@ -102,6 +103,18 @@ lazy val laikaIO = crossProject(JVMPlatform)
},
)

lazy val scaladoc = project
.in(file("scaladoc"))
.dependsOn(core.jvm)
.settings(
name := "protosearch-scaladoc",
crossScalaVersions := Seq(Scala212),
libraryDependencies ++= Seq(
"org.scalameta" %%% "munit" % munitV % Test,
"org.scalameta" %%% "scalameta" % scalametaV,
),
)

lazy val jsInterop = crossProject(JSPlatform)
.crossType(CrossType.Pure)
.in(file("jsinterop"))
Expand All @@ -116,7 +129,7 @@ lazy val jsInterop = crossProject(JSPlatform)
lazy val plugin =
project
.in(file("sbt"))
.dependsOn(core.jvm, laikaIO.jvm)
.dependsOn(core.jvm, laikaIO.jvm, scaladoc)
.enablePlugins(SbtPlugin)
.settings(
name := "protosearch-sbt",
Expand Down
14 changes: 14 additions & 0 deletions laikaIO/src/main/resources/pink/cozydev/protosearch/sbt/search.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@
padding-left: 10px;
}

.field.has-addons-centered {
justify-content: center;
}

#search_input {
width: 100%;
}

#app {
min-height: 200px;
background-color: #f5f5f5;
padding: 20px;
}

/* Modal CSS setup from https://www.w3schools.com/howto/howto_css_modals.asp */
/* The Modal (background) */
.search-modal {
Expand Down
33 changes: 20 additions & 13 deletions laikaIO/src/main/resources/pink/cozydev/protosearch/sbt/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,29 @@

<body>
<section class="section">
<h1 class="title">Demo: JS Interop</h1>
<p class="subtitle">
Search from Javascript!
</p>
<div class="container">
<h1 class="title has-text-centered">Demo: JS Interop</h1>
<p class="subtitle has-text-centered">
Search from Javascript!
</p>

<div class="field has-addons has-addons-centered">
<div class="control is-expanded">
<input id="search_input" class="input is-primary" type="text" placeholder="Type your query...">
</div>
</div>
</div>
</section>

<div class="container is-widescreen">
<section class="section">
<input id="search_input" class="input is-primary" type="text" placeholder="search">
</section>
<section class="section">
<div id="app"></div>
</section>
</div>
<section class="section">
<div class="container is-widescreen">
<div id="app" class="box">

</div>
</div>
</section>

<script type="text/javascript" src="search.js"></script>
</body>

</html>
</html>
64 changes: 62 additions & 2 deletions laikaIO/src/main/resources/pink/cozydev/protosearch/sbt/search.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,70 @@
function renderDoc(hit) {
const path = hit.fields.path
const link = "../" + hit.fields.path.replace(".txt", ".html")
const title = hit.fields.title
const preview = hit.fields.body.slice(0, 150) + "..."
return (
`
<ol>
<div class="card">
<div class="card-content">
<p class="is-size-6 has-text-grey-light">
<span>${path}</span>
</p>
<div class="level-left">
<p class="title is-capitalized is-flex-wrap-wrap">
<a href="${link}" target="_blank">
<span>${title}</span>
</a>
</p>
</div>
<p class="subtitle">${preview}</p>
</div>
</div>
</ol>
`
)
}
function renderScaladoc(hit) {
const title = hit.fields.functionName
const description = hit.fields.description
const returnType = hit.fields.returnType
const params = hit.fields.params
return (
`
<ol>
<div class="card">
<div class="card-content">
<div class="level-left">
<p class="title is-capitalized is-flex-wrap-wrap">
<span>${title}</span>
</p>
</div>
<p class="subtitle">${description}</p>
<p class="subtitle">Parameters: ${params}</p>
<p class="subtitle">Return type: ${returnType}</p>
</div>
</div>
</ol>
`
)
}

async function main() {
var app = document.getElementById("app")
var searchBar = document.getElementById("search_input")
const urlParams = new URLSearchParams(location.search)

const renderFunction = urlParams.get("type") == "scaladoc" ? renderScaladoc : renderDoc

const maybeIndex = urlParams.get("index")
const workerJS = maybeIndex ? `worker.js?index=${maybeIndex}` : "worker.js"

const worker = new Worker("worker.js")
const worker = new Worker(workerJS)
worker.onmessage = function(e) {
app.innerHTML = e.data
console.log(e.data)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
console.log(e.data)

We only needed this during testing.

const markup = e.data.map(renderFunction).join("\n")
app.innerHTML = markup
}

searchBar.addEventListener('input', function () {
Expand Down
38 changes: 6 additions & 32 deletions laikaIO/src/main/resources/pink/cozydev/protosearch/sbt/worker.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,21 @@
importScripts("./protosearch.js")

async function getQuerier() {
let querier = fetch("./searchIndex.idx")
async function getQuerier(index) {
let querier = fetch("./" + index + ".idx")
.then(res => res.blob())
.then(blob => QuerierBuilder.load(blob))
.catch((error) => console.error("getQuerier error: ", error));
return await querier
}
const querierPromise = getQuerier()
const urlParams = new URLSearchParams(location.search)
const maybeIndex = urlParams.get("index")
const index = maybeIndex ? maybeIndex : "searchIndex"

function render(hit) {
const path = hit.fields.path
const link = "../" + hit.fields.path.replace(".txt", ".html")
const title = hit.fields.title
const preview = hit.fields.body.slice(0, 150) + "..."
return (
`
<ol>
<div class="card">
<div class="card-content">
<p class="is-size-6 has-text-grey-light">
<span>${path}</span>
</p>
<div class="level-left">
<p class="title is-capitalized is-flex-wrap-wrap">
<a href="${link}" target="_blank">
<span>${title}</span>
</a>
</p>
</div>
<p class="subtitle">${preview}</p>
</div>
</div>
</ol>
`
)
}
const querierPromise = getQuerier(index)

async function searchIt(query) {
const querier = await querierPromise
return querier.search(query)
.map(render)
.join("\n")
}

onmessage = async function(e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright 2022 CozyDev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package pink.cozydev.protosearch.sbt

import sbt.*
import sbt.Keys.*
import sbt.nio.file.FileTreeView
import fs2.{Stream, Chunk}
import fs2.io.file.{Files, Path}
import cats.effect.IO
import cats.effect.unsafe.implicits.global
import cats.syntax.all._
import java.nio.file.{Path => JPath}

import pink.cozydev.protosearch.scaladoc.{ParseScaladoc, ScaladocIndexer}
import pink.cozydev.protosearch.MultiIndex

object ProtosearchScaladocPlugin extends AutoPlugin {

lazy val createScaladocIndex: TaskKey[File] =
taskKey[File]("Create a Search Index based on Scaladocs within the project")

private def buildScaladocIndex: Def.Initialize[Task[File]] = Def.task {
val logger = streams.value.log
val sourceGlobs = (Compile / sourceDirectories).value.map(f => f.toGlob / "**" / "*.scala")
val scalaSourceFiles: Seq[JPath] = sourceGlobs.flatMap(g =>
FileTreeView.default.list(g).collect {
case (path, attributes) if attributes.isRegularFile => path
}
)

val scaladocInfos = Stream
.emits(scalaSourceFiles)
.flatMap { path =>
val p = Path.fromNioPath(path)
val getContent = Files[IO].readAll(p).through(fs2.text.utf8.decode).compile.string
Stream.eval(getContent).map(ParseScaladoc.parseAndExtractInfo)
}
.flatMap(Stream.emits)

val buildIndex = scaladocInfos.compile.toList.map(ScaladocIndexer.createScaladocIndex)

val projName = name.value
val targetDir = target.value
val outputFile = targetDir / s"$projName.idx"
val writer = Files[IO].writeAll(Path.fromNioPath(outputFile.toPath()))
val writeIndex = buildIndex.flatMap { index =>
val numDocs = index.indexes.head._2.numDocs
val log = IO(logger.info(s"Created index with ${numDocs} docs at $outputFile"))
val indexBytes = MultiIndex.codec
.encode(index)
.map(_.bytes)
.toEither
.leftMap(err => new Throwable(err.message))
val bytes: Stream[IO, Byte] =
Stream.fromEither[IO](indexBytes).flatMap(bv => Stream.chunk(Chunk.byteVector(bv)))
log *> bytes.through(writer).compile.drain
}

writeIndex.unsafeRunSync()
outputFile
}
override val trigger = allRequirements

override def requires = plugins.JvmPlugin

override lazy val projectSettings: Seq[Setting[_]] = Seq(
createScaladocIndex := buildScaladocIndex.value
)
}
Loading