From d5018936a0fea482229848944deaf8d1ce3b1827 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Wed, 3 Jun 2026 20:00:40 -0400 Subject: [PATCH] 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 or other inline elements), extractSurroundingText now: 1. Finds the block-level parent (e.g.

) 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 , , , etc. Falls back to single-node extraction when no block parent is found (e.g. orphan text nodes in tests). --- internal/sync/kepub_cfi_converter.go | 47 +++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/internal/sync/kepub_cfi_converter.go b/internal/sync/kepub_cfi_converter.go index 29bc49b..4a2aad1 100644 --- a/internal/sync/kepub_cfi_converter.go +++ b/internal/sync/kepub_cfi_converter.go @@ -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) {