-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
106 additions
and
0 deletions.
There are no files selected for viewing
51 changes: 51 additions & 0 deletions
51
core/src/main/scala/pink/cozydev/protosearch/highlight/FragmentFormatter.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package pink.cozydev.protosearch.highlight | ||
|
||
case class FragmentFormatter( | ||
maxSize: Int, | ||
startTag: String, | ||
endTag: String, | ||
) { | ||
private val tagSize = startTag.size + endTag.size | ||
private val tags: Array[String] = Array(startTag, endTag) | ||
|
||
def format(fragment: String, offsets: Iterable[Int]): String = | ||
if (offsets.size == 0) fragment | ||
else { | ||
val offsetArr = offsets.toArray | ||
assert(offsetArr.size % 2 == 0, "even number of offsets required") | ||
|
||
val sb = new StringBuilder() | ||
sb.sizeHint(fragment.size + tagSize * (offsets.size / 2)) | ||
val chars = fragment.toCharArray() | ||
|
||
try { | ||
// Add initial characters | ||
sb.appendAll(chars, 0, offsetArr(0)) | ||
var charsOffset = offsetArr(0) | ||
|
||
// Loop through offsets, two at a time | ||
var i = 0 | ||
while (i < offsetArr.size) { | ||
val offsetStart = offsetArr(i) | ||
// add chars between offsets | ||
val inbetweenChars = offsetStart - charsOffset | ||
sb.appendAll(chars, charsOffset, inbetweenChars) | ||
charsOffset += inbetweenChars | ||
|
||
// start new offset | ||
sb.append(startTag) | ||
val offsetLength = offsetArr(i + 1) | ||
sb.appendAll(chars, charsOffset, offsetLength) | ||
sb.append(endTag) | ||
charsOffset += offsetLength | ||
i += 2 | ||
} | ||
// Add remaining characters | ||
sb.appendAll(chars, charsOffset, chars.size - charsOffset) | ||
sb.result() | ||
} catch { | ||
case _: IndexOutOfBoundsException => | ||
throw new IllegalArgumentException("Offset exceeded string length") | ||
} | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
core/src/test/scala/pink/cozydev/protosearch/highlight/FragmentFormatterSuite.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package pink.cozydev.protosearch.highlight | ||
|
||
import munit.FunSuite | ||
|
||
class FragmentFormatterSuite extends FunSuite { | ||
val formatter = FragmentFormatter(100, "<b>", "</b>") | ||
|
||
test("formats string with empty offsets") { | ||
val s = "hello world" | ||
val actual = formatter.format(s, List.empty) | ||
val expected = s | ||
assertEquals(actual, expected) | ||
} | ||
|
||
test("formats string with one pair of offsets") { | ||
val s = "hello world" | ||
val actual = formatter.format(s, List(6, 5)) | ||
val expected = "hello <b>world</b>" | ||
assertEquals(actual, expected) | ||
} | ||
|
||
test("formats string with offset in the middle") { | ||
val s = "hello world, how are you?" | ||
val actual = formatter.format(s, List(6, 5)) | ||
val expected = "hello <b>world</b>, how are you?" | ||
assertEquals(actual, expected) | ||
} | ||
|
||
test("formats string with two pair of offsets") { | ||
val s = "hello world" | ||
val actual = formatter.format(s, List(0, 5, 6, 5)) | ||
val expected = "<b>hello</b> <b>world</b>" | ||
assertEquals(actual, expected) | ||
} | ||
|
||
test("formats whole string if one offset") { | ||
val s = "hello world" | ||
val actual = formatter.format(s, List(0, 11)) | ||
val expected = "<b>hello world</b>" | ||
assertEquals(actual, expected) | ||
} | ||
|
||
test("throws if offset length exceeds string boundary") { | ||
val s = "hello world" | ||
intercept[java.lang.IllegalArgumentException] { | ||
formatter.format(s, List(6, 5 + 1)) | ||
} | ||
} | ||
|
||
test("throws if odd number of offset integers") { | ||
intercept[java.lang.AssertionError] { | ||
formatter.format("", List(1)) | ||
} | ||
} | ||
} |