mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-09 08:04:45 +00:00
fix: trim edge blank lines and skip full scan in highlight windowing
Audit follow-ups on the highlight context window: - Blank lines sitting at the very start/end of a `context` tag were passed through untouched when a side was short enough not to be trimmed, so a highlight whose context began or ended with blank lines still rendered empty space above/below the quote. Trim the outer edges of the windowed passage (re-basing the marked range accordingly). - `locate` enumerated every occurrence of the quote — a full context scan plus a list allocation — even in the common no-prefix case where only the first match is needed. Short-circuit to a single indexOf there. - Clamp the returned marked range to the trimmed text length so it can never point past the end (e.g. a quote ending in trimmed whitespace). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ApuEseGcFjUFqYoLhCuR91
This commit is contained in:
+16
-9
@@ -84,17 +84,20 @@ data class HighlightQuote(
|
||||
val trail = trimTrail(context.substring(endExclusive))
|
||||
val quote = context.substring(start, endExclusive)
|
||||
|
||||
// Nothing to trim on either side: the original context is short enough to show whole.
|
||||
if (!lead.trimmed && !trail.trimmed) {
|
||||
return HighlightQuote(context, start until endExclusive)
|
||||
}
|
||||
|
||||
val prefix = if (lead.trimmed) "$ELLIPSIS " else ""
|
||||
val suffix = if (trail.trimmed) " $ELLIPSIS" else ""
|
||||
|
||||
val text = prefix + lead.text + quote + trail.text + suffix
|
||||
val markStart = prefix.length + lead.text.length
|
||||
return HighlightQuote(text, markStart until (markStart + quote.length))
|
||||
// Drop any blank lines sitting at the very edges of the context — with the far text
|
||||
// trimmed (or even when it isn't) they would otherwise render as empty space above or
|
||||
// below the quote. Only the outer edges are touched; the whitespace framing the quote
|
||||
// itself is preserved.
|
||||
val raw = prefix + lead.text + quote + trail.text + suffix
|
||||
val leadingBlank = raw.length - raw.trimStart().length
|
||||
val text = raw.trim()
|
||||
|
||||
val markStart = (prefix.length + lead.text.length - leadingBlank).coerceAtLeast(0)
|
||||
val markEnd = (markStart + quote.length).coerceAtMost(text.length)
|
||||
return HighlightQuote(text, markStart until markEnd)
|
||||
}
|
||||
|
||||
private class Side(
|
||||
@@ -138,9 +141,13 @@ data class HighlightQuote(
|
||||
highlight: String,
|
||||
prefix: String?,
|
||||
): Int? {
|
||||
// The common case — no prefix to disambiguate with — needs only the first match, so
|
||||
// don't scan the whole context enumerating every occurrence.
|
||||
if (prefix.isNullOrBlank()) return context.indexOf(highlight).takeIf { it >= 0 }
|
||||
|
||||
val occurrences = occurrencesOf(context, highlight)
|
||||
if (occurrences.isEmpty()) return null
|
||||
if (occurrences.size == 1 || prefix.isNullOrBlank()) return occurrences.first()
|
||||
if (occurrences.size == 1) return occurrences.first()
|
||||
|
||||
val tail = prefix.trimEnd()
|
||||
return occurrences.firstOrNull { context.substring(0, it).trimEnd().endsWith(tail) }
|
||||
|
||||
+11
@@ -114,6 +114,17 @@ class HighlightQuoteTest {
|
||||
assertTrue(quote.text.length < context.length / 2, "expected windowing, got ${quote.text.length} of ${context.length}")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dropsBlankLinesAtTheEdgesOfAShortContext() {
|
||||
// A context whose paragraph boundaries left blank lines at its very start and end would
|
||||
// otherwise render as empty space above and below the quote.
|
||||
val quote = HighlightQuote.of("Forward Secrecy", "\n\nForward Secrecy is nice.\n\n")
|
||||
|
||||
assertEquals("Forward Secrecy is nice.", quote.text)
|
||||
assertEquals(0 until 15, quote.marked)
|
||||
assertEquals("Forward Secrecy", quote.text.substring(quote.marked!!))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun trimmingSnapsToWholeWordsSoNoWordIsCutInHalf() {
|
||||
val lead = "alpha bravo charlie delta echo foxtrot ".repeat(20) // long, space-separated
|
||||
|
||||
Reference in New Issue
Block a user