Skip to content

Commit 7631dab

Browse files
committed
Extend search by acronym to fuzzy search by tokens
1 parent 8443c16 commit 7631dab

File tree

4 files changed

+35
-30
lines changed

4 files changed

+35
-30
lines changed

scala3doc-js/src/Globals.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,11 @@ import scala.scalajs.js.annotation.JSGlobalScope
77
@JSGlobalScope
88
object Globals extends js.Object {
99
val pathToRoot: String = js.native
10+
}
11+
12+
object StringUtils {
13+
def createCamelCaseTokens(s: String): List[String] =
14+
if s.isEmpty then List.empty
15+
else if s.tail.indexWhere(_.isUpper) == -1 then List(s)
16+
else List(s.take(s.tail.indexWhere(_.isUpper) + 1)) ++ createCamelCaseTokens(s.drop(s.tail.indexWhere(_.isUpper) + 1))
1017
}

scala3doc-js/src/searchbar/PageEntry.scala

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,15 @@ case class PageEntry(
1515
description: String,
1616
location: String,
1717
shortName: String,
18-
acronym: Option[String]
18+
tokens: List[String]
1919
)
2020

2121
object PageEntry {
22-
private def createAcronym(s: String): Option[String] =
23-
s.headOption.map(firstLetter => firstLetter.toString ++ s.tail.filter(_.isUpper))
24-
2522
def apply(jsObj: PageEntryJS): PageEntry = PageEntry(
26-
jsObj.t,
27-
jsObj.d,
28-
jsObj.l,
29-
jsObj.n.toLowerCase,
30-
createAcronym(jsObj.n)
31-
)
23+
jsObj.t,
24+
jsObj.d,
25+
jsObj.l,
26+
jsObj.n.toLowerCase,
27+
StringUtils.createCamelCaseTokens(jsObj.n)
28+
)
3229
}
Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
package dotty.dokka
22

3-
enum Matchers extends Function1[PageEntry, Int]:
4-
case ByName(query: String)
5-
case ByKind(kind: String)
3+
sealed trait Matchers extends Function1[PageEntry, Int]
64

7-
def apply(p: PageEntry): Int = this match {
8-
case ByName(query) => {
9-
val nameOption = Option(p.shortName)
10-
val acronym = p.acronym
11-
//Edge case for empty query string
12-
if query == "" then 1
13-
else {
14-
val results = List(
15-
nameOption.filter(_.contains(query.toLowerCase)).fold(-1)(_.size - query.size),
16-
acronym.filter(_.contains(query)).fold(-1)(_.size - query.size + 1)
17-
)
18-
if results.forall(_ == -1) then -1 else results.filter(_ != -1).min
19-
}
5+
class ByName(query: String) extends Matchers:
6+
val tokens = StringUtils.createCamelCaseTokens(query)
7+
def apply(p: PageEntry): Int = {
8+
val nameOption = Option(p.shortName)
9+
//Edge case for empty query string
10+
if query == "" then 1
11+
else {
12+
val results = List(
13+
nameOption.filter(_.contains(query.toLowerCase)).fold(-1)(_.size - query.size),
14+
if p.tokens.size >= tokens.size && p.tokens.zip(tokens).forall( (token, query) => token.startsWith(query))
15+
then p.tokens.size - tokens.size + 1
16+
else -1
17+
//acronym.filter(_.contains(query)).fold(-1)(_.size - query.size + 1)
18+
)
19+
if results.forall(_ == -1) then -1 else results.filter(_ != -1).min
2020
}
21-
case ByKind(kind) => p.fullName.split(" ").headOption.filter(_.equalsIgnoreCase(kind)).fold(-1)(_ => 1)
2221
}
2322

23+
class ByKind(kind: String) extends Matchers:
24+
def apply(p: PageEntry): Int = p.fullName.split(" ").headOption.filter(_.equalsIgnoreCase(kind)).fold(-1)(_ => 1)

scala3doc-js/src/searchbar/engine/QueryParser.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ class QueryParser:
2121
val escapedRegex = raw"`(.*)`".r
2222

2323
def parse(query: String): List[Matchers] = query match {
24-
case escapedRegex(rest) => List(Matchers.ByName(rest))
25-
case kindRegex(kind, rest) => List(Matchers.ByKind(kind)) ++ parse(rest)
26-
case restRegex(name) => List(Matchers.ByName(name))
24+
case escapedRegex(rest) => List(ByName(rest))
25+
case kindRegex(kind, rest) => List(ByKind(kind)) ++ parse(rest)
26+
case restRegex(name) => List(ByName(name))
2727
case _ => List()
2828
}

0 commit comments

Comments
 (0)