Skip to content

Commit

Permalink
Add FirstMatchHighlighter
Browse files Browse the repository at this point in the history
Co-authored-by: Sam Pillsworth <[email protected]>
  • Loading branch information
valencik and samspills committed Nov 28, 2024
1 parent 9c93fa6 commit 010d906
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.highlight

case class FirstMatchHighlighter(
formatter: FragmentFormatter
) {

val lookBackWindowSize: Int = formatter.maxSize / 2

def trim(str: String): String = {
val trimmed = str.trim()
if (trimmed.size > formatter.maxSize)
trimmed.take(formatter.maxSize) + "..."
else trimmed
}

def highlight(str: String, queryStr: String): String = {
val offset = str.indexOf(queryStr)
if (offset == -1)
trim(str)
else {
val start = Math.max(0, offset - lookBackWindowSize)
val nearby = str.indexWhere(c => " \n\t.".contains(c), start)
val slice = if (str.size < formatter.maxSize) str else str.drop(nearby)
val newOffset = if (str.size < formatter.maxSize) offset else offset - nearby
val fStr = formatter.format(slice, List(newOffset, queryStr.size))
trim(fStr)
}
}

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* 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.highlight

case class FragmentFormatter(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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.highlight

class FirstMatchHighlighterSuite extends munit.FunSuite {
val formatter = FragmentFormatter(36, "<b>", "</b>")
val highlighter = FirstMatchHighlighter(formatter)

test("no highlight on no match") {
val s = "hello world"
val actual = highlighter.highlight(s, "cat")
val expected = "hello world"
assertEquals(actual, expected)
}

test("highlights simple substring") {
val s = "hello world"
val actual = highlighter.highlight(s, "world")
val expected = "hello <b>world</b>"
assertEquals(actual, expected)
}

test("highlights only first match") {
val s = "hello world, you, nice world, you"
val actual = highlighter.highlight(s, "world")
val expected = "hello <b>world</b>, you, nice world, you"
assertEquals(actual, expected)
}

test("highlights matches near end of long doc") {
val s = List.fill(100)("hello cat,").mkString("", " ", " world")
val actual = highlighter.highlight(s, "world")
val expected = "cat, hello cat, hello cat, <b>world</b>"
assertEquals(actual, expected)
}

test("long docs get trimmed with ellipses") {
val s = List.fill(100)("hello cat,").mkString("", " ", " world")
val actual = highlighter.highlight(s, "fake")
val expected = s.take(formatter.maxSize) + "..."
assertEquals(actual, expected)
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* 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.highlight

import munit.FunSuite
Expand Down

0 comments on commit 010d906

Please sign in to comment.