Case-fold a string while recording, for every folded code unit, the index in
the ORIGINAL string it came from.
String.prototype.toLowerCase() is NOT length-preserving (İ U+0130 → i̇,
1 code unit → 2; final-sigma; the German ẞ; …). So an offset obtained from
original.toLowerCase().indexOf(needle) is an index into the FOLDED string and
drifts past the true position in original by the cumulative expansion of
every fold-expanding char before the match. Feeding that drifted offset to
sliceSnippet mis-centres the window and miscounts the line number.
Iterates by code POINT so a surrogate pair maps to the code-unit index where
the pair begins (matching sliceSnippet's code-unit slicing). map.length === folded.length; map[k] is the original code-unit index of folded unit k.
v3.11.0-rc.21 — the read/snippet-path siblings of the rc.18 replaceLineOnce
fold-offset class (found by the post-rc.20 re-sweep in semanticSearch +
searchText, where a folded offset was sliced against the original body).
Case-fold a string while recording, for every folded code unit, the index in the ORIGINAL string it came from.
String.prototype.toLowerCase()is NOT length-preserving (İU+0130 →i̇, 1 code unit → 2; final-sigma; the German ẞ; …). So an offset obtained fromoriginal.toLowerCase().indexOf(needle)is an index into the FOLDED string and drifts past the true position inoriginalby the cumulative expansion of every fold-expanding char before the match. Feeding that drifted offset to sliceSnippet mis-centres the window and miscounts the line number.Iterates by code POINT so a surrogate pair maps to the code-unit index where the pair begins (matching
sliceSnippet's code-unit slicing).map.length === folded.length;map[k]is the original code-unit index of folded unitk.v3.11.0-rc.21 — the read/snippet-path siblings of the rc.18
replaceLineOncefold-offset class (found by the post-rc.20 re-sweep insemanticSearch+searchText, where a folded offset was sliced against the original body).