-
Notifications
You must be signed in to change notification settings - Fork 1
Bug #99: Search highlight missing in some TXT #26
Copy link
Copy link
Open
Labels
Description
Bug #99: Search results not highlighted in some TXT files
Severity: Medium
Repro
- Open a TXT file with non-UTF-8 encoding (e.g., GBK, Big5) or a large file using the chunked reader
- Open search → search for a term that exists in the file
- Tap a search result to navigate to it
- Observe whether the matched text is visually highlighted
Expected
Search result text is highlighted with a yellow background (systemYellow at 0.4 alpha) for 3 seconds.
Actual
Navigation scrolls to approximately the right area, but no yellow highlight is visible on the matched text.
Root Cause (Suspected)
Multiple potential causes depending on the scenario:
1. Chunked reader offset translation:
- The chunked reader (
TXTChunkedReaderBridge) splits content into chunks - Search results use global UTF-16 offsets, but the chunked bridge needs chunk-local offsets
scrollToGlobalOffset()uses binary search to find the right chunk, but the highlight range may not be correctly translated from global to chunk-local coordinates
2. Encoding edge cases:
- For non-UTF-8 files,
TXTService.detectEncodingFromSample()detects encoding - Search indexing may use different text than what the bridge displays if encoding detection differs between index-time and display-time
- UTF-16 offsets from search may not align with the displayed text's UTF-16 positions
3. isProgrammaticScroll guard timing:
- The
programmaticScrollCountcounter (bug Bug #12: Toolbar cannot be hidden while reading #43 fix, issue 8) prevents highlight auto-clear during programmatic scrolls - If the counter decrements too early (0.3s delay) and the scroll takes longer to settle, the highlight gets cleared before it's visible
- The
HighlightingLayoutManager.drawBackground()only draws highlights within the visible glyph range — if scroll hasn't settled, range may be outside visible area
Architecture Reference
Highlight rendering pipeline:
- Search result tapped →
LocatorwithcharRangeStartUTF16/charRangeEndUTF16posted via.readerNavigateToLocator - Container view receives notification → sets
highlightRange(NSRange) +scrollToOffset - Bridge's
updateUIViewapplies scroll and passes range toHighlightableTextView HighlightingLayoutManager.setHighlightRanges(persisted:active:)stores the rangedrawBackground(forGlyphRange:at:)draws yellow rect during layout pass- After 3s,
highlightClearTimerfires → clearshighlightRange
Guard mechanism:
programmaticScrollCount(integer counter, not boolean) prevents overlapping scrolls from clearing highlights too early- Incremented on programmatic scroll, decremented 0.3s later
clearSearchHighlightIfTemporary()only clears when counter ≤ 0
Files
vreader/Views/Reader/TXTTextViewBridge.swift— highlight application + scroll + programmatic guardvreader/Views/Reader/TXTTextViewBridgeCoordinator.swift—programmaticScrollCount, auto-clear logicvreader/Views/Reader/HighlightableTextView.swift—HighlightingLayoutManager.drawBackground()vreader/Views/Reader/TXTChunkedReaderBridge.swift— chunked reader highlight + offset translationvreader/Services/TXT/TXTOffsetMapper.swift— UTF-16 offset mapping, surrogate-pair snappingvreader/Views/Reader/TextHighlightRenderer.swift— locator → NSRange conversion
Refs #6
Reactions are currently unavailable