refactor(sync): rewrite extractSurroundingText to use block-parent text collection

Instead of reading only from the single resolved text node (which
produces a tiny window when the position is inside <em> or other inline
elements), extractSurroundingText now:

1. Finds the block-level parent (e.g. <p>) of the resolved text node
2. Collects all text within that block, transparently crossing inline
   formatting elements via collectInlineText
3. Computes the global offset of the original text node within the
   concatenated block text
4. Extracts the [offset-window : offset+window] slice

This gives a full context window regardless of inline element
boundaries, enabling accurate text bridging between EPUB and KEPUB
documents even when reading positions fall inside <em>, <strong>,
<span class="koboSpan">, etc.

Falls back to single-node extraction when no block parent is found
(e.g. orphan text nodes in tests).
This commit is contained in:
2026-06-03 20:00:40 -04:00
parent 3a54dda5c5
commit d5018936a0
+39 -8
View File
@@ -208,23 +208,54 @@ func extractSurroundingText(textNode *html.Node, offset int, window int) string
return ""
}
text := textNode.Data
runes := []rune(text)
block := findBlockParent(textNode)
if block == nil {
text := textNode.Data
runes := []rune(text)
start := offset - window
if start < 0 {
start = 0
}
end := offset + window
if end > len(runes) {
end = len(runes)
}
if start >= end {
return normalizeWhitespace(text)
}
return normalizeWhitespace(string(runes[start:end]))
}
start := offset - window
segments := collectInlineText(block)
globalOffset := 0
for _, seg := range segments {
if seg.node == textNode {
globalOffset += offset
break
}
globalOffset += len(seg.runes)
}
var allRunes []rune
for _, seg := range segments {
allRunes = append(allRunes, seg.runes...)
}
start := globalOffset - window
if start < 0 {
start = 0
}
end := offset + window
if end > len(runes) {
end = len(runes)
end := globalOffset + window
if end > len(allRunes) {
end = len(allRunes)
}
if start >= end {
return normalizeWhitespace(text)
return normalizeWhitespace(string(allRunes))
}
return normalizeWhitespace(string(runes[start:end]))
return normalizeWhitespace(string(allRunes[start:end]))
}
func (k *KEPUBCFIConverter) ComputeKEPUBPercentage(kepubCFI string) (float64, error) {